8
8
// See https://swift.org/CONTRIBUTORS.txt for Swift project authors
9
9
//
10
10
11
- internal 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: -
11
+ private import _TestingInternals
12
+ private import Synchronization
43
13
44
14
/// A type that wraps a value requiring access from a synchronous caller during
45
15
/// concurrent execution.
@@ -52,30 +22,48 @@ protocol Lockable {
52
22
/// concurrency tools.
53
23
///
54
24
/// 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)
62
35
}
63
36
}
37
+ #endif
64
38
65
39
/// 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 { }
67
44
45
+ extension Locked : RawRepresentable {
68
46
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 } )
70
49
_storage. withUnsafeMutablePointerToElements { lock in
71
- L . initializeLock ( at : lock )
50
+ lock . initialize ( to : . init ( ) )
72
51
}
52
+ #else
53
+ nonisolated ( unsafe) let rawValue = rawValue
54
+ _storage = _Storage ( rawValue)
55
+ #endif
73
56
}
74
57
75
58
var rawValue : T {
76
- withLock { $0 }
59
+ withLock { rawValue in
60
+ nonisolated ( unsafe) let rawValue = rawValue
61
+ return rawValue
62
+ }
77
63
}
64
+ }
78
65
66
+ extension Locked {
79
67
/// Acquire the lock and invoke a function while it is held.
80
68
///
81
69
/// - Parameters:
@@ -88,55 +76,27 @@ struct LockedWith<L, T>: RawRepresentable where L: Lockable {
88
76
/// This function can be used to synchronize access to shared data from a
89
77
/// synchronous caller. Wherever possible, use actor isolation or other Swift
90
78
/// 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)
94
83
defer {
95
- L . unsafelyRelinquishLock ( at : lock)
84
+ os_unfair_lock_unlock ( lock)
96
85
}
97
86
return try body ( & rawValue. pointee)
98
87
}
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)
126
92
}
93
+ #endif
127
94
}
128
95
}
129
96
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
-
137
97
// MARK: - Additions
138
98
139
- extension LockedWith where T: AdditiveArithmetic {
99
+ extension Locked where T: AdditiveArithmetic & Sendable {
140
100
/// Add something to the current wrapped value of this instance.
141
101
///
142
102
/// - Parameters:
@@ -152,7 +112,7 @@ extension LockedWith where T: AdditiveArithmetic {
152
112
}
153
113
}
154
114
155
- extension LockedWith where T: Numeric {
115
+ extension Locked where T: Numeric & Sendable {
156
116
/// Increment the current wrapped value of this instance.
157
117
///
158
118
/// - Returns: The sum of ``rawValue`` and `1`.
@@ -172,7 +132,7 @@ extension LockedWith where T: Numeric {
172
132
}
173
133
}
174
134
175
- extension LockedWith {
135
+ extension Locked {
176
136
/// Initialize an instance of this type with a raw value of `nil`.
177
137
init < V> ( ) where T == V ? {
178
138
self . init ( rawValue: nil )
@@ -188,3 +148,10 @@ extension LockedWith {
188
148
self . init ( rawValue: [ ] )
189
149
}
190
150
}
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