2727
2828#if canImport(Darwin)
2929import Darwin
30- #elseif canImport(Android)
31- import Android
32- #elseif canImport(Glibc)
33- import Glibc
3430#elseif os(Windows)
31+ import ucrt
3532import WinSDK
33+ #elseif canImport(Glibc)
34+ @preconcurrency import Glibc
35+ #elseif canImport(Musl)
36+ @preconcurrency import Musl
37+ #elseif canImport(Bionic)
38+ @preconcurrency import Bionic
39+ #elseif canImport(WASILibc)
40+ @preconcurrency import WASILibc
41+ #if canImport(wasi_pthread)
42+ import wasi_pthread
43+ #endif
44+ #else
45+ #error("The concurrency Lock module was unable to identify your C library.")
3646#endif
3747
3848#if os(Windows)
@@ -43,8 +53,19 @@ typealias LockPrimitive = SRWLOCK
4353typealias LockPrimitive = pthread_mutex_t
4454#endif
4555
56+
57+ /// A utility function that runs the body code only in debug builds, without
58+ /// emitting compiler warnings.
59+ ///
60+ /// This is currently the only way to do this in Swift: see
61+ /// https://forums.swift.org/t/support-debug-only-code/11037 for a discussion.
62+ @inlinable
63+ internal func debugOnly( _ body: ( ) -> Void ) {
64+ assert ( { body ( ) ; return true } ( ) )
65+ }
66+
4667@usableFromInline
47- enum LockOperations { }
68+ enum LockOperations : Sendable { }
4869
4970extension LockOperations {
5071 @inlinable
@@ -53,9 +74,12 @@ extension LockOperations {
5374
5475 #if os(Windows)
5576 InitializeSRWLock ( mutex)
56- #else
77+ #elseif (compiler(<6.1) && !os(WASI)) || (compiler(>=6.1) && _runtime(_multithreaded))
5778 var attr = pthread_mutexattr_t ( )
5879 pthread_mutexattr_init ( & attr)
80+ debugOnly {
81+ pthread_mutexattr_settype ( & attr, . init( PTHREAD_MUTEX_ERRORCHECK) )
82+ }
5983
6084 let err = pthread_mutex_init ( mutex, & attr)
6185 precondition ( err == 0 , " \( #function) failed in pthread_mutex with error \( err) " )
@@ -67,8 +91,8 @@ extension LockOperations {
6791 mutex. assertValidAlignment ( )
6892
6993 #if os(Windows)
70- // SRWLOCK does not need to be freed
71- #else
94+ // SRWLOCK does not need to be free'd
95+ #elseif (compiler(<6.1) && !os(WASI)) || (compiler(>=6.1) && _runtime(_multithreaded))
7296 let err = pthread_mutex_destroy ( mutex)
7397 precondition ( err == 0 , " \( #function) failed in pthread_mutex with error \( err) " )
7498 #endif
@@ -80,7 +104,7 @@ extension LockOperations {
80104
81105 #if os(Windows)
82106 AcquireSRWLockExclusive ( mutex)
83- #else
107+ #elseif (compiler(<6.1) && !os(WASI)) || (compiler(>=6.1) && _runtime(_multithreaded))
84108 let err = pthread_mutex_lock ( mutex)
85109 precondition ( err == 0 , " \( #function) failed in pthread_mutex with error \( err) " )
86110 #endif
@@ -92,7 +116,7 @@ extension LockOperations {
92116
93117 #if os(Windows)
94118 ReleaseSRWLockExclusive ( mutex)
95- #else
119+ #elseif (compiler(<6.1) && !os(WASI)) || (compiler(>=6.1) && _runtime(_multithreaded))
96120 let err = pthread_mutex_unlock ( mutex)
97121 precondition ( err == 0 , " \( #function) failed in pthread_mutex with error \( err) " )
98122 #endif
@@ -135,7 +159,9 @@ final class LockStorage<Value>: ManagedBuffer<Value, LockPrimitive> {
135159 let buffer = Self . create ( minimumCapacity: 1 ) { _ in
136160 value
137161 }
138- // Avoid 'unsafeDowncast' as there is a miscompilation on 5.10.
162+ // Intentionally using a force cast here to avoid a miss compiliation in 5.10.
163+ // This is as fast as an unsafeDownCast since ManagedBuffer is inlined and the optimizer
164+ // can eliminate the upcast/downcast pair
139165 let storage = buffer as! Self
140166
141167 storage. withUnsafeMutablePointers { _, lockPtr in
@@ -159,17 +185,15 @@ final class LockStorage<Value>: ManagedBuffer<Value, LockPrimitive> {
159185 }
160186 }
161187
162- @usableFromInline
188+ @inlinable
163189 deinit {
164190 self . withUnsafeMutablePointerToElements { lockPtr in
165191 LockOperations . destroy ( lockPtr)
166192 }
167193 }
168194
169195 @inlinable
170- func withLockPrimitive< T> (
171- _ body: ( UnsafeMutablePointer < LockPrimitive > ) throws -> T
172- ) rethrows -> T {
196+ func withLockPrimitive< T> ( _ body: ( UnsafeMutablePointer < LockPrimitive > ) throws -> T ) rethrows -> T {
173197 try self . withUnsafeMutablePointerToElements { lockPtr in
174198 try body ( lockPtr)
175199 }
@@ -185,11 +209,16 @@ final class LockStorage<Value>: ManagedBuffer<Value, LockPrimitive> {
185209 }
186210}
187211
188- extension LockStorage : @unchecked Sendable { }
212+ // This compiler guard is here becaue `ManagedBuffer` is already declaring
213+ // Sendable unavailability after 6.1, which `LockStorage` inherits.
214+ #if compiler(<6.2)
215+ @available ( * , unavailable)
216+ extension LockStorage : Sendable { }
217+ #endif
189218
190219/// A threading lock based on `libpthread` instead of `libdispatch`.
191220///
192- /// - note : ``Lock`` has reference semantics.
221+ /// - Note : ``Lock`` has reference semantics.
193222///
194223/// This object provides a lock on top of a single `pthread_mutex_t`. This kind
195224/// of lock is safe to use with `libpthread`-based threading models, such as the
@@ -201,7 +230,7 @@ struct Lock {
201230 internal let _storage : LockStorage < Void >
202231
203232 /// Create a new lock.
204- @usableFromInline
233+ @inlinable
205234 init ( ) {
206235 self . _storage = . create( value: ( ) )
207236 }
@@ -225,9 +254,7 @@ struct Lock {
225254 }
226255
227256 @inlinable
228- internal func withLockPrimitive< T> (
229- _ body: ( UnsafeMutablePointer < LockPrimitive > ) throws -> T
230- ) rethrows -> T {
257+ internal func withLockPrimitive< T> ( _ body: ( UnsafeMutablePointer < LockPrimitive > ) throws -> T ) rethrows -> T {
231258 try self . _storage. withLockPrimitive ( body)
232259 }
233260}
@@ -249,9 +276,14 @@ extension Lock {
249276 }
250277 return try body ( )
251278 }
279+
280+ @inlinable
281+ func withLockVoid( _ body: ( ) throws -> Void ) rethrows {
282+ try self . withLock ( body)
283+ }
252284}
253285
254- extension Lock : Sendable { }
286+ extension Lock : @ unchecked Sendable { }
255287
256288extension UnsafeMutablePointer {
257289 @inlinable
@@ -260,20 +292,74 @@ extension UnsafeMutablePointer {
260292 }
261293}
262294
295+ /// Provides locked access to `Value`.
296+ ///
297+ /// - Note: ``LockedValueBox`` has reference semantics and holds the `Value`
298+ /// alongside a lock behind a reference.
299+ ///
300+ /// This is no different than creating a ``Lock`` and protecting all
301+ /// accesses to a value using the lock. But it's easy to forget to actually
302+ /// acquire/release the lock in the correct place. ``LockedValueBox`` makes
303+ /// that much easier.
263304@usableFromInline
264305struct LockedValueBox < Value> {
265- @usableFromInline
266- let storage : LockStorage < Value >
267306
268307 @usableFromInline
308+ internal let _storage : LockStorage < Value >
309+
310+ /// Initialize the `Value`.
311+ @inlinable
269312 init ( _ value: Value ) {
270- self . storage = . create( value: value)
313+ self . _storage = . create( value: value)
271314 }
272315
316+ /// Access the `Value`, allowing mutation of it.
273317 @inlinable
274318 func withLockedValue< T> ( _ mutate: ( inout Value ) throws -> T ) rethrows -> T {
275- try self . storage. withLockedValue ( mutate)
319+ try self . _storage. withLockedValue ( mutate)
320+ }
321+
322+ /// Provides an unsafe view over the lock and its value.
323+ ///
324+ /// This can be beneficial when you require fine grained control over the lock in some
325+ /// situations but don't want lose the benefits of ``withLockedValue(_:)`` in others by
326+ /// switching to ``NIOLock``.
327+ var unsafe : Unsafe {
328+ Unsafe ( _storage: self . _storage)
329+ }
330+
331+ /// Provides an unsafe view over the lock and its value.
332+ struct Unsafe {
333+ @usableFromInline
334+ let _storage : LockStorage < Value >
335+
336+ /// Manually acquire the lock.
337+ @inlinable
338+ func lock( ) {
339+ self . _storage. lock ( )
340+ }
341+
342+ /// Manually release the lock.
343+ @inlinable
344+ func unlock( ) {
345+ self . _storage. unlock ( )
346+ }
347+
348+ /// Mutate the value, assuming the lock has been acquired manually.
349+ ///
350+ /// - Parameter mutate: A closure with scoped access to the value.
351+ /// - Returns: The result of the `mutate` closure.
352+ @inlinable
353+ func withValueAssumingLockIsAcquired< Result> (
354+ _ mutate: ( _ value: inout Value ) throws -> Result
355+ ) rethrows -> Result {
356+ try self . _storage. withUnsafeMutablePointerToHeader { value in
357+ try mutate ( & value. pointee)
358+ }
359+ }
276360 }
277361}
278362
279- extension LockedValueBox : Sendable where Value: Sendable { }
363+ extension LockedValueBox : @unchecked Sendable where Value: Sendable { }
364+
365+ extension LockedValueBox . Unsafe : @unchecked Sendable where Value: Sendable { }
0 commit comments