@@ -165,20 +165,41 @@ internal open class MutexImpl(locked: Boolean) : SemaphoreImpl(1, if (locked) 1
165
165
lockSuspend(owner)
166
166
}
167
167
168
- private suspend fun lockSuspend (owner : Any? ) = suspendCancellableCoroutineReusable<Unit > { cont ->
169
- cont as CancellableContinuationImpl <Unit >
168
+ private suspend fun lockSuspend (owner : Any? ) = suspendCancellableCoroutineReusable { cont ->
170
169
val contWithOwner = CancellableContinuationWithOwner (cont, owner)
171
170
acquire(contWithOwner)
172
171
}
173
172
174
- override fun tryLock (owner : Any? ): Boolean =
175
- if (tryAcquire()) {
176
- assert { this .owner.value == = NO_OWNER }
177
- this .owner.value = owner
178
- true
179
- } else {
180
- false
173
+ override fun tryLock (owner : Any? ): Boolean = when (tryLockImpl(owner)) {
174
+ TRY_LOCK_SUCCESS -> true
175
+ TRY_LOCK_FAILED -> false
176
+ TRY_LOCK_ALREADY_LOCKED_BY_OWNER -> error(" This mutex is already locked by the specified owner: $owner " )
177
+ else -> error(" unexpected" )
178
+ }
179
+
180
+ private fun tryLockImpl (owner : Any? ): Int {
181
+ while (true ) {
182
+ if (tryAcquire()) {
183
+ assert { this .owner.value == = NO_OWNER }
184
+ this .owner.value = owner
185
+ return TRY_LOCK_SUCCESS
186
+ } else {
187
+ // The semaphore permit acquisition has failed.
188
+ // However, we need to check that this mutex is not
189
+ // locked by our owner.
190
+ if (owner != null ) {
191
+ // Is this mutex locked by our owner?
192
+ if (holdsLock(owner)) return TRY_LOCK_ALREADY_LOCKED_BY_OWNER
193
+ // This mutex is either locked by another owner or unlocked.
194
+ // In the latter case, it is possible that it WAS locked by
195
+ // our owner when the semaphore permit acquisition has failed.
196
+ // To preserve linearizability, the operation restarts in this case.
197
+ if (! isLocked) continue
198
+ }
199
+ return TRY_LOCK_FAILED
200
+ }
181
201
}
202
+ }
182
203
183
204
override fun unlock (owner : Any? ) {
184
205
while (true ) {
@@ -206,19 +227,26 @@ internal open class MutexImpl(locked: Boolean) : SemaphoreImpl(1, if (locked) 1
206
227
)
207
228
208
229
protected open fun onLockRegFunction (select : SelectInstance <* >, owner : Any? ) {
209
- onAcquireRegFunction(SelectInstanceWithOwner (select as SelectInstanceInternal <* >, owner), owner)
230
+ if (owner != null && holdsLock(owner)) {
231
+ select.selectInRegistrationPhase(ON_LOCK_ALREADY_LOCKED_BY_OWNER )
232
+ } else {
233
+ onAcquireRegFunction(SelectInstanceWithOwner (select, owner), owner)
234
+ }
210
235
}
211
236
212
237
protected open fun onLockProcessResult (owner : Any? , result : Any? ): Any? {
238
+ if (result == ON_LOCK_ALREADY_LOCKED_BY_OWNER ) {
239
+ error(" This mutex is already locked by the specified owner: $owner " )
240
+ }
213
241
return this
214
242
}
215
243
216
244
private inner class CancellableContinuationWithOwner (
217
245
@JvmField
218
- val cont : CancellableContinuationImpl <Unit >,
246
+ val cont : CancellableContinuation <Unit >,
219
247
@JvmField
220
248
val owner : Any?
221
- ) : CancellableContinuation<Unit> by cont, Waiter by cont {
249
+ ) : CancellableContinuation<Unit> by cont {
222
250
override fun tryResume (value : Unit , idempotent : Any? , onCancellation : ((cause: Throwable ) -> Unit )? ): Any? {
223
251
assert { this @MutexImpl.owner.value == = NO_OWNER }
224
252
val token = cont.tryResume(value, idempotent) {
@@ -242,10 +270,10 @@ internal open class MutexImpl(locked: Boolean) : SemaphoreImpl(1, if (locked) 1
242
270
243
271
private inner class SelectInstanceWithOwner <Q >(
244
272
@JvmField
245
- val select : SelectInstanceInternal <Q >,
273
+ val select : SelectInstance <Q >,
246
274
@JvmField
247
275
val owner : Any?
248
- ) : SelectInstanceInternal<Q> by select {
276
+ ) : SelectInstanceInternal<Q> by select as SelectInstanceInternal<Q> {
249
277
override fun trySelect (clauseObject : Any , result : Any? ): Boolean {
250
278
assert { this @MutexImpl.owner.value == = NO_OWNER }
251
279
return select.trySelect(clauseObject, result).also { success ->
@@ -264,3 +292,8 @@ internal open class MutexImpl(locked: Boolean) : SemaphoreImpl(1, if (locked) 1
264
292
}
265
293
266
294
private val NO_OWNER = Symbol (" NO_OWNER" )
295
+ private val ON_LOCK_ALREADY_LOCKED_BY_OWNER = Symbol (" ALREADY_LOCKED_BY_OWNER" )
296
+
297
+ private const val TRY_LOCK_SUCCESS = 0
298
+ private const val TRY_LOCK_FAILED = 1
299
+ private const val TRY_LOCK_ALREADY_LOCKED_BY_OWNER = 2
0 commit comments