3131
3232#if compiler(>=6)
3333
34- #if canImport(Darwin)
35- // Backports the Synchronization.Mutex API for earlier Darwin platforms
34+ #if !canImport(WinSDK)
35+
36+ // Backports the Swift 6 type Mutex<Value> to all Darwin platforms
37+ struct Mutex < Value: ~ Copyable> : ~ Copyable {
38+ let storage : Storage < Value >
39+
40+ init ( _ initialValue: consuming sending Value) {
41+ self . storage = Storage ( initialValue)
42+ }
43+
44+ borrowing func withLock< Result, E: Error > (
45+ _ body: ( inout sending Value) throws ( E ) -> sending Result
46+ ) throws ( E) -> sending Result {
47+ storage. lock ( )
48+ defer { storage. unlock ( ) }
49+ return try body ( & storage. value)
50+ }
51+
52+ borrowing func withLockIfAvailable< Result, E: Error > (
53+ _ body: ( inout sending Value) throws ( E ) -> sending Result
54+ ) throws ( E) -> sending Result? {
55+ guard storage. tryLock ( ) else { return nil }
56+ defer { storage. unlock ( ) }
57+ return try body ( & storage. value)
58+ }
59+ }
60+
61+ extension Mutex : @unchecked Sendable where Value: ~ Copyable { }
62+
63+ #else
64+
65+ // Windows doesn't support ~Copyable yet
3666
37- @usableFromInline
3867struct Mutex < Value> : @unchecked Sendable {
39- let storage : Storage
68+ let storage : Storage < Value >
4069
41- @usableFromInline
4270 init ( _ initialValue: consuming sending Value) {
4371 self . storage = Storage ( initialValue)
4472 }
4573
46- @usableFromInline
4774 borrowing func withLock< Result, E: Error > (
4875 _ body: ( inout sending Value) throws ( E ) -> sending Result
4976 ) throws ( E) -> sending Result {
@@ -52,59 +79,127 @@ struct Mutex<Value>: @unchecked Sendable {
5279 return try body ( & storage. value)
5380 }
5481
55- @usableFromInline
56- borrowing func withLockIfAvailable< Result, E> (
82+ borrowing func withLockIfAvailable< Result, E: Error > (
5783 _ body: ( inout sending Value) throws ( E ) -> sending Result
58- ) throws ( E) -> sending Result? where E : Error {
84+ ) throws ( E) -> sending Result? {
5985 guard storage. tryLock ( ) else { return nil }
6086 defer { storage. unlock ( ) }
6187 return try body ( & storage. value)
6288 }
6389}
6490
91+ #endif
92+
93+ #if canImport(Darwin)
94+
6595import struct os. os_unfair_lock_t
6696import struct os. os_unfair_lock
6797import func os. os_unfair_lock_lock
6898import func os. os_unfair_lock_unlock
6999import func os. os_unfair_lock_trylock
70100
71- extension Mutex {
101+ final class Storage < Value: ~ Copyable> {
102+ private let _lock : os_unfair_lock_t
103+ var value : Value
72104
73- final class Storage {
74- private let _lock : os_unfair_lock_t
105+ init ( _ initialValue: consuming Value ) {
106+ self . _lock = . allocate( capacity: 1 )
107+ self . _lock. initialize ( to: os_unfair_lock ( ) )
108+ self . value = initialValue
109+ }
75110
76- var value : Value
111+ func lock( ) {
112+ os_unfair_lock_lock ( _lock)
113+ }
114+
115+ func unlock( ) {
116+ os_unfair_lock_unlock ( _lock)
117+ }
118+
119+ func tryLock( ) -> Bool {
120+ os_unfair_lock_trylock ( _lock)
121+ }
122+
123+ deinit {
124+ self . _lock. deinitialize ( count: 1 )
125+ self . _lock. deallocate ( )
126+ }
127+ }
128+
129+ #elseif canImport(Glibc) || canImport(Musl) || canImport(Bionic)
130+
131+ #if canImport(Musl)
132+ import Musl
133+ #elseif canImport(Bionic)
134+ import Android
135+ #else
136+ import Glibc
137+ #endif
77138
78- init ( _ initialValue: Value ) {
79- self . _lock = . allocate( capacity: 1 )
80- self . _lock. initialize ( to: os_unfair_lock ( ) )
81- self . value = initialValue
82- }
139+ final class Storage < Value: ~ Copyable> {
140+ private let _lock : UnsafeMutablePointer < pthread_mutex_t >
141+
142+ var value : Value
143+
144+ init ( _ initialValue: consuming Value ) {
145+ var attr = pthread_mutexattr_t ( )
146+ pthread_mutexattr_init ( & attr)
147+ self . _lock = . allocate( capacity: 1 )
148+ let err = pthread_mutex_init ( self . _lock, & attr)
149+ precondition ( err == 0 , " pthread_mutex_init error: \( err) " )
150+ self . value = initialValue
151+ }
83152
84- func lock( ) {
85- os_unfair_lock_lock ( _lock)
86- }
153+ func lock( ) {
154+ let err = pthread_mutex_lock ( _lock)
155+ precondition ( err == 0 , " pthread_mutex_lock error: \( err) " )
156+ }
87157
88- func unlock( ) {
89- os_unfair_lock_unlock ( _lock)
90- }
158+ func unlock( ) {
159+ let err = pthread_mutex_unlock ( _lock)
160+ precondition ( err == 0 , " pthread_mutex_unlock error: \( err) " )
161+ }
91162
92- func tryLock( ) -> Bool {
93- os_unfair_lock_trylock ( _lock)
94- }
163+ func tryLock( ) -> Bool {
164+ pthread_mutex_trylock ( _lock) == 0
165+ }
95166
96- deinit {
97- self . _lock. deinitialize ( count : 1 )
98- self . _lock . deallocate ( )
99- }
167+ deinit {
168+ let err = pthread_mutex_destroy ( self . _lock)
169+ precondition ( err == 0 , " pthread_mutex_destroy error: \( err ) " )
170+ self . _lock . deallocate ( )
100171 }
101172}
102173
103- #elseif canImport(Synchronization)
174+ #elseif canImport(WinSDK)
175+
176+ import ucrt
177+ import WinSDK
178+
179+ final class Storage < Value> {
180+ private let _lock : UnsafeMutablePointer < SRWLOCK >
181+
182+ var value : Value
183+
184+ init ( _ initialValue: Value ) {
185+ self . _lock = . allocate( capacity: 1 )
186+ InitializeSRWLock ( self . _lock)
187+ self . value = initialValue
188+ }
104189
105- import Synchronization
190+ func lock( ) {
191+ AcquireSRWLockExclusive ( _lock)
192+ }
106193
107- typealias Mutex = Synchronization . Mutex
194+ func unlock( ) {
195+ ReleaseSRWLockExclusive ( _lock)
196+ }
197+
198+ func tryLock( ) -> Bool {
199+ TryAcquireSRWLockExclusive ( _lock) != 0
200+ }
201+ }
108202
109203#endif
204+
110205#endif
0 commit comments