Closed
Description
The following code hangs forever on the call to mutex.unlock()
:
val mutex = Mutex()
(mutex as Semaphore).aquire()
println("locked: ${mutex.isLocked}")
mutex.unlock()
println("unlocked: ${!mutex.isLocked}")
The reason seems to be that MutexImpl
extends SemaphoreImpl
but SemaphoreImpl.aquire()
bypasses the invariants of MutexImpl.owner
: aquire
doesn't change owner
but unlock
spin loops because it expects to see something different than NO_OWNER
.
Similar bugs might be possible with other combinations of Mutex
and Semaphore
calls for MutexImpl
, I haven't checked yet.
Admittedly, this is a bit contrived, so I'm not sure if this is really a bug or just a missuse of implementatiom details (the public Mutex
interface doesn't extend Semaphore
). But if this is considered worth fixing I see two possible approaches:
- changing the behavior of the
SemaphoreImpl
methods (through override etc.) so they don't breakMutexImpl
invariants - splitting up
SemaphoreImpl
into a new abstract base type for bothMutex
andSemaphore
(that however doesn't implementSemaphore
directly) and a thin wrapper around it to actually implementSemaphore
- that way interacting with instances ofMutexImpl
through the methods ofSemaphore
won't be possible in the first place