@@ -30,8 +30,16 @@ struct Locked<T> {
3030 private final class _Storage {
3131 let mutex : Mutex < T >
3232
33+ #if os(Linux) || os(Android)
34+ // The Linux implementation of Mutex terminates if `_tryLock()` is called on
35+ // the owning thread. (Other platforms just return `false`.) So, on Linux,
36+ // we also track the thread ID of the owner.
37+ let owningThreadID : Atomic < pid_t >
38+ #endif
39+
3340 init ( _ rawValue: consuming sending T) {
3441 mutex = Mutex ( rawValue)
42+ owningThreadID = Atomic ( 0 )
3543 }
3644 }
3745#endif
@@ -88,6 +96,12 @@ extension Locked {
8896 return result
8997#else
9098 try _storage. mutex. withLock { rawValue in
99+ #if os(Linux) || os(Android)
100+ _storage. owningThreadID. store ( gettid ( ) , ordering: . sequentiallyConsistent)
101+ defer {
102+ _storage. owningThreadID. store ( 0 , ordering: . sequentiallyConsistent)
103+ }
104+ #endif
91105 try body ( & rawValue)
92106 }
93107#endif
@@ -119,7 +133,20 @@ extension Locked {
119133 }
120134 return result
121135#else
136+ #if os(Linux) || os(Android)
137+ let tid = gettid ( )
138+ if _storage. owningThreadID. load ( ordering: . sequentiallyConsistent) == tid {
139+ // This thread already holds the lock.
140+ return nil
141+ }
142+ #endif
122143 try _storage. mutex. withLockIfAvailable { rawValue in
144+ #if os(Linux) || os(Android)
145+ _storage. owningThreadID. store ( tid, ordering: . sequentiallyConsistent)
146+ defer {
147+ _storage. owningThreadID. store ( 0 , ordering: . sequentiallyConsistent)
148+ }
149+ #endif
123150 try body ( & rawValue)
124151 }
125152#endif
0 commit comments