@@ -31,9 +31,16 @@ import Darwin
31
31
import ucrt
32
32
import WinSDK
33
33
#elseif canImport(Glibc)
34
- import Glibc
34
+ @ preconcurrency import Glibc
35
35
#elseif canImport(Musl)
36
- import 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
37
44
#else
38
45
#error("The concurrency NIOLock module was unable to identify your C library.")
39
46
#endif
@@ -47,7 +54,7 @@ typealias LockPrimitive = pthread_mutex_t
47
54
#endif
48
55
49
56
@usableFromInline
50
- enum LockOperations { }
57
+ enum LockOperations : Sendable { }
51
58
52
59
extension LockOperations {
53
60
@inlinable
@@ -56,12 +63,15 @@ extension LockOperations {
56
63
57
64
#if os(Windows)
58
65
InitializeSRWLock ( mutex)
59
- #else
66
+ #elseif (compiler(<6.1) && !os(WASI)) || (compiler(>=6.1) && _runtime(_multithreaded))
60
67
var attr = pthread_mutexattr_t ( )
61
68
pthread_mutexattr_init ( & attr)
62
- debugOnly {
63
- pthread_mutexattr_settype ( & attr, . init( PTHREAD_MUTEX_ERRORCHECK) )
64
- }
69
+ assert (
70
+ {
71
+ pthread_mutexattr_settype ( & attr, . init( PTHREAD_MUTEX_ERRORCHECK) )
72
+ return true
73
+ } ( )
74
+ )
65
75
66
76
let err = pthread_mutex_init ( mutex, & attr)
67
77
precondition ( err == 0 , " \( #function) failed in pthread_mutex with error \( err) " )
@@ -74,7 +84,7 @@ extension LockOperations {
74
84
75
85
#if os(Windows)
76
86
// SRWLOCK does not need to be free'd
77
- #else
87
+ #elseif (compiler(<6.1) && !os(WASI)) || (compiler(>=6.1) && _runtime(_multithreaded))
78
88
let err = pthread_mutex_destroy ( mutex)
79
89
precondition ( err == 0 , " \( #function) failed in pthread_mutex with error \( err) " )
80
90
#endif
@@ -86,7 +96,7 @@ extension LockOperations {
86
96
87
97
#if os(Windows)
88
98
AcquireSRWLockExclusive ( mutex)
89
- #else
99
+ #elseif (compiler(<6.1) && !os(WASI)) || (compiler(>=6.1) && _runtime(_multithreaded))
90
100
let err = pthread_mutex_lock ( mutex)
91
101
precondition ( err == 0 , " \( #function) failed in pthread_mutex with error \( err) " )
92
102
#endif
@@ -98,7 +108,7 @@ extension LockOperations {
98
108
99
109
#if os(Windows)
100
110
ReleaseSRWLockExclusive ( mutex)
101
- #else
111
+ #elseif (compiler(<6.1) && !os(WASI)) || (compiler(>=6.1) && _runtime(_multithreaded))
102
112
let err = pthread_mutex_unlock ( mutex)
103
113
precondition ( err == 0 , " \( #function) failed in pthread_mutex with error \( err) " )
104
114
#endif
@@ -139,9 +149,11 @@ final class LockStorage<Value>: ManagedBuffer<Value, LockPrimitive> {
139
149
@inlinable
140
150
static func create( value: Value ) -> Self {
141
151
let buffer = Self . create ( minimumCapacity: 1 ) { _ in
142
- return value
152
+ value
143
153
}
144
- // Avoid 'unsafeDowncast' as there is a miscompilation on 5.10.
154
+ // Intentionally using a force cast here to avoid a miss compiliation in 5.10.
155
+ // This is as fast as an unsafeDownCast since ManagedBuffer is inlined and the optimizer
156
+ // can eliminate the upcast/downcast pair
145
157
let storage = buffer as! Self
146
158
147
159
storage. withUnsafeMutablePointers { _, lockPtr in
@@ -175,7 +187,7 @@ final class LockStorage<Value>: ManagedBuffer<Value, LockPrimitive> {
175
187
@inlinable
176
188
func withLockPrimitive< T> ( _ body: ( UnsafeMutablePointer < LockPrimitive > ) throws -> T ) rethrows -> T {
177
189
try self . withUnsafeMutablePointerToElements { lockPtr in
178
- return try body ( lockPtr)
190
+ try body ( lockPtr)
179
191
}
180
192
}
181
193
@@ -189,23 +201,28 @@ final class LockStorage<Value>: ManagedBuffer<Value, LockPrimitive> {
189
201
}
190
202
}
191
203
192
- extension LockStorage : @unchecked Sendable { }
204
+ // This compiler guard is here becaue `ManagedBuffer` is already declaring
205
+ // Sendable unavailability after 6.1, which `LockStorage` inherits.
206
+ #if compiler(<6.2)
207
+ @available ( * , unavailable)
208
+ extension LockStorage : Sendable { }
209
+ #endif
193
210
194
211
/// A threading lock based on `libpthread` instead of `libdispatch`.
195
212
///
196
- /// - note : ``NIOLock`` has reference semantics.
213
+ /// - Note : ``NIOLock`` has reference semantics.
197
214
///
198
215
/// This object provides a lock on top of a single `pthread_mutex_t`. This kind
199
216
/// of lock is safe to use with `libpthread`-based threading models, such as the
200
217
/// one used by NIO. On Windows, the lock is based on the substantially similar
201
218
/// `SRWLOCK` type.
202
- struct NIOLock {
219
+ public struct NIOLock {
203
220
@usableFromInline
204
221
internal let _storage : LockStorage < Void >
205
222
206
223
/// Create a new lock.
207
224
@inlinable
208
- init ( ) {
225
+ public init ( ) {
209
226
self . _storage = . create( value: ( ) )
210
227
}
211
228
@@ -214,7 +231,7 @@ struct NIOLock {
214
231
/// Whenever possible, consider using `withLock` instead of this method and
215
232
/// `unlock`, to simplify lock handling.
216
233
@inlinable
217
- func lock( ) {
234
+ public func lock( ) {
218
235
self . _storage. lock ( )
219
236
}
220
237
@@ -223,13 +240,13 @@ struct NIOLock {
223
240
/// Whenever possible, consider using `withLock` instead of this method and
224
241
/// `lock`, to simplify lock handling.
225
242
@inlinable
226
- func unlock( ) {
243
+ public func unlock( ) {
227
244
self . _storage. unlock ( )
228
245
}
229
246
230
247
@inlinable
231
248
internal func withLockPrimitive< T> ( _ body: ( UnsafeMutablePointer < LockPrimitive > ) throws -> T ) rethrows -> T {
232
- return try self . _storage. withLockPrimitive ( body)
249
+ try self . _storage. withLockPrimitive ( body)
233
250
}
234
251
}
235
252
@@ -243,7 +260,7 @@ extension NIOLock {
243
260
/// - Parameter body: The block to execute while holding the lock.
244
261
/// - Returns: The value returned by the block.
245
262
@inlinable
246
- func withLock< T> ( _ body: ( ) throws -> T ) rethrows -> T {
263
+ public func withLock< T> ( _ body: ( ) throws -> T ) rethrows -> T {
247
264
self . lock ( )
248
265
defer {
249
266
self . unlock ( )
@@ -252,31 +269,16 @@ extension NIOLock {
252
269
}
253
270
254
271
@inlinable
255
- func withLockVoid( _ body: ( ) throws -> Void ) rethrows {
272
+ public func withLockVoid( _ body: ( ) throws -> Void ) rethrows {
256
273
try self . withLock ( body)
257
274
}
258
275
}
259
276
260
- extension NIOLock : Sendable { }
277
+ extension NIOLock : @ unchecked Sendable { }
261
278
262
279
extension UnsafeMutablePointer {
263
280
@inlinable
264
281
func assertValidAlignment( ) {
265
282
assert ( UInt ( bitPattern: self ) % UInt( MemoryLayout< Pointee> . alignment) == 0 )
266
283
}
267
284
}
268
-
269
- /// A utility function that runs the body code only in debug builds, without
270
- /// emitting compiler warnings.
271
- ///
272
- /// This is currently the only way to do this in Swift: see
273
- /// https://forums.swift.org/t/support-debug-only-code/11037 for a discussion.
274
- @inlinable
275
- internal func debugOnly( _ body: ( ) -> Void ) {
276
- assert (
277
- {
278
- body ( )
279
- return true
280
- } ( )
281
- )
282
- }
0 commit comments