99//
1010
1111internal import _TestingInternals
12-
13- /// A protocol defining a type, generally platform-specific, that satisfies the
14- /// requirements of a lock or mutex.
15- protocol Lockable {
16- /// Initialize the lock at the given address.
17- ///
18- /// - Parameters:
19- /// - lock: A pointer to uninitialized memory that should be initialized as
20- /// an instance of this type.
21- static func initializeLock( at lock: UnsafeMutablePointer < Self > )
22-
23- /// Deinitialize the lock at the given address.
24- ///
25- /// - Parameters:
26- /// - lock: A pointer to initialized memory that should be deinitialized.
27- static func deinitializeLock( at lock: UnsafeMutablePointer < Self > )
28-
29- /// Acquire the lock at the given address.
30- ///
31- /// - Parameters:
32- /// - lock: The address of the lock to acquire.
33- static func unsafelyAcquireLock( at lock: UnsafeMutablePointer < Self > )
34-
35- /// Relinquish the lock at the given address.
36- ///
37- /// - Parameters:
38- /// - lock: The address of the lock to relinquish.
39- static func unsafelyRelinquishLock( at lock: UnsafeMutablePointer < Self > )
40- }
41-
42- // MARK: -
12+ private import Synchronization
4313
4414/// A type that wraps a value requiring access from a synchronous caller during
4515/// concurrent execution.
@@ -52,30 +22,48 @@ protocol Lockable {
5222/// concurrency tools.
5323///
5424/// This type is not part of the public interface of the testing library.
55- struct LockedWith < L, T> : RawRepresentable where L: Lockable {
56- /// A type providing heap-allocated storage for an instance of ``Locked``.
57- private final class _Storage : ManagedBuffer < T , L > {
58- deinit {
59- withUnsafeMutablePointerToElements { lock in
60- L . deinitializeLock ( at: lock)
61- }
25+ struct Locked < T> {
26+ /// A type providing storage for the underlying lock and wrapped value.
27+ #if SWT_TARGET_OS_APPLE && canImport(os)
28+ private typealias _Storage = ManagedBuffer < T , os_unfair_lock_s >
29+ #else
30+ private final class _Storage {
31+ let mutex : Mutex < T >
32+
33+ init ( _ rawValue: consuming sending T) {
34+ mutex = Mutex ( rawValue)
6235 }
6336 }
37+ #endif
6438
6539 /// Storage for the underlying lock and wrapped value.
66- private nonisolated ( unsafe) var _storage: ManagedBuffer < T , L >
40+ private nonisolated ( unsafe) var _storage: _Storage
41+ }
42+
43+ extension Locked : Sendable where T: Sendable { }
6744
45+ extension Locked : RawRepresentable {
6846 init ( rawValue: T ) {
69- _storage = _Storage. create ( minimumCapacity: 1 , makingHeaderWith: { _ in rawValue } )
47+ #if SWT_TARGET_OS_APPLE && canImport(os)
48+ _storage = . create( minimumCapacity: 1 , makingHeaderWith: { _ in rawValue } )
7049 _storage. withUnsafeMutablePointerToElements { lock in
71- L . initializeLock ( at : lock )
50+ lock . initialize ( to : . init ( ) )
7251 }
52+ #else
53+ nonisolated ( unsafe) let rawValue = rawValue
54+ _storage = _Storage ( rawValue)
55+ #endif
7356 }
7457
7558 var rawValue : T {
76- withLock { $0 }
59+ withLock { rawValue in
60+ nonisolated ( unsafe) let rawValue = rawValue
61+ return rawValue
62+ }
7763 }
64+ }
7865
66+ extension Locked {
7967 /// Acquire the lock and invoke a function while it is held.
8068 ///
8169 /// - Parameters:
@@ -88,55 +76,27 @@ struct LockedWith<L, T>: RawRepresentable where L: Lockable {
8876 /// This function can be used to synchronize access to shared data from a
8977 /// synchronous caller. Wherever possible, use actor isolation or other Swift
9078 /// concurrency tools.
91- nonmutating func withLock< R> ( _ body: ( inout T ) throws -> R ) rethrows -> R where R: ~ Copyable {
92- try _storage. withUnsafeMutablePointers { rawValue, lock in
93- L . unsafelyAcquireLock ( at: lock)
79+ func withLock< R> ( _ body: ( inout T ) throws -> sending R) rethrows -> sending R where R: ~ Copyable {
80+ #if SWT_TARGET_OS_APPLE && canImport(os)
81+ nonisolated ( unsafe) let result = try _storage. withUnsafeMutablePointers { rawValue, lock in
82+ os_unfair_lock_lock ( lock)
9483 defer {
95- L . unsafelyRelinquishLock ( at : lock)
84+ os_unfair_lock_unlock ( lock)
9685 }
9786 return try body ( & rawValue. pointee)
9887 }
99- }
100-
101- /// Acquire the lock and invoke a function while it is held, yielding both the
102- /// protected value and a reference to the underlying lock guarding it.
103- ///
104- /// - Parameters:
105- /// - body: A closure to invoke while the lock is held.
106- ///
107- /// - Returns: Whatever is returned by `body`.
108- ///
109- /// - Throws: Whatever is thrown by `body`.
110- ///
111- /// This function is equivalent to ``withLock(_:)`` except that the closure
112- /// passed to it also takes a reference to the underlying lock guarding this
113- /// instance's wrapped value. This function can be used when platform-specific
114- /// functionality such as a `pthread_cond_t` is needed. Because the caller has
115- /// direct access to the lock and is able to unlock and re-lock it, it is
116- /// unsafe to modify the protected value.
117- ///
118- /// - Warning: Callers that unlock the lock _must_ lock it again before the
119- /// closure returns. If the lock is not acquired when `body` returns, the
120- /// effect is undefined.
121- nonmutating func withUnsafeUnderlyingLock< R> ( _ body: ( UnsafeMutablePointer < L > , T ) throws -> R ) rethrows -> R where R: ~ Copyable {
122- try withLock { value in
123- try _storage. withUnsafeMutablePointerToElements { lock in
124- try body ( lock, value)
125- }
88+ return result
89+ #else
90+ try _storage. mutex. withLock { rawValue in
91+ try body ( & rawValue)
12692 }
93+ #endif
12794 }
12895}
12996
130- extension LockedWith : Sendable where T: Sendable { }
131-
132- /// A type that wraps a value requiring access from a synchronous caller during
133- /// concurrent execution and which uses the default platform-specific lock type
134- /// for the current platform.
135- typealias Locked < T> = LockedWith < DefaultLock , T >
136-
13797// MARK: - Additions
13898
139- extension LockedWith where T: AdditiveArithmetic {
99+ extension Locked where T: AdditiveArithmetic & Sendable {
140100 /// Add something to the current wrapped value of this instance.
141101 ///
142102 /// - Parameters:
@@ -152,7 +112,7 @@ extension LockedWith where T: AdditiveArithmetic {
152112 }
153113}
154114
155- extension LockedWith where T: Numeric {
115+ extension Locked where T: Numeric & Sendable {
156116 /// Increment the current wrapped value of this instance.
157117 ///
158118 /// - Returns: The sum of ``rawValue`` and `1`.
@@ -172,7 +132,7 @@ extension LockedWith where T: Numeric {
172132 }
173133}
174134
175- extension LockedWith {
135+ extension Locked {
176136 /// Initialize an instance of this type with a raw value of `nil`.
177137 init < V> ( ) where T == V ? {
178138 self . init ( rawValue: nil )
@@ -188,3 +148,10 @@ extension LockedWith {
188148 self . init ( rawValue: [ ] )
189149 }
190150}
151+
152+ // MARK: - POSIX conveniences
153+
154+ #if os(FreeBSD) || os(OpenBSD)
155+ typealias pthread_mutex_t = _TestingInternals . pthread_mutex_t ?
156+ typealias pthread_cond_t = _TestingInternals . pthread_cond_t ?
157+ #endif
0 commit comments