11//
22// This source file is part of the Swift.org open source project
33//
4- // Copyright (c) 2023 Apple Inc. and the Swift project authors
4+ // Copyright (c) 2023–2025 Apple Inc. and the Swift project authors
55// Licensed under Apache License v2.0 with Runtime Library Exception
66//
77// See https://swift.org/LICENSE.txt for license information
1010
1111internal import _TestingInternals
1212
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: -
43+
1344/// A type that wraps a value requiring access from a synchronous caller during
1445/// concurrent execution.
1546///
@@ -21,67 +52,23 @@ internal import _TestingInternals
2152/// concurrency tools.
2253///
2354/// This type is not part of the public interface of the testing library.
24- ///
25- /// - Bug: The state protected by this type should instead be protected using
26- /// actor isolation, but actor-isolated functions cannot be called from
27- /// synchronous functions. ([83888717](rdar://83888717))
28- struct Locked < T> : RawRepresentable , Sendable where T: Sendable {
29- /// The platform-specific type to use for locking.
30- ///
31- /// It would be preferable to implement this lock in Swift, however there is
32- /// no standard lock or mutex type available across all platforms that is
33- /// visible in Swift. C11 has a standard `mtx_t` type, but it is not widely
34- /// supported and so cannot be relied upon.
35- ///
36- /// To keep the implementation of this type as simple as possible,
37- /// `pthread_mutex_t` is used on Apple platforms instead of `os_unfair_lock`
38- /// or `OSAllocatedUnfairLock`.
39- #if SWT_TARGET_OS_APPLE || os(Linux) || os(Android) || (os(WASI) && compiler(>=6.1) && _runtime(_multithreaded))
40- typealias PlatformLock = pthread_mutex_t
41- #elseif os(FreeBSD) || os(OpenBSD)
42- typealias PlatformLock = pthread_mutex_t ?
43- #elseif os(Windows)
44- typealias PlatformLock = SRWLOCK
45- #elseif os(WASI)
46- // No locks on WASI without multithreaded runtime.
47- typealias PlatformLock = Never
48- #else
49- #warning("Platform-specific implementation missing: locking unavailable")
50- typealias PlatformLock = Never
51- #endif
52-
55+ struct LockedWith < L, T> : RawRepresentable where L: Lockable {
5356 /// A type providing heap-allocated storage for an instance of ``Locked``.
54- private final class _Storage : ManagedBuffer < T , PlatformLock > {
57+ private final class _Storage : ManagedBuffer < T , L > {
5558 deinit {
5659 withUnsafeMutablePointerToElements { lock in
57- #if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(OpenBSD) || os(Android) || (os(WASI) && compiler(>=6.1) && _runtime(_multithreaded))
58- _ = pthread_mutex_destroy ( lock)
59- #elseif os(Windows)
60- // No deinitialization needed.
61- #elseif os(WASI)
62- // No locks on WASI without multithreaded runtime.
63- #else
64- #warning("Platform-specific implementation missing: locking unavailable")
65- #endif
60+ L . deinitializeLock ( at: lock)
6661 }
6762 }
6863 }
6964
7065 /// Storage for the underlying lock and wrapped value.
71- private nonisolated ( unsafe) var _storage: ManagedBuffer < T , PlatformLock >
66+ private nonisolated ( unsafe) var _storage: ManagedBuffer < T , L >
7267
7368 init ( rawValue: T ) {
7469 _storage = _Storage. create ( minimumCapacity: 1 , makingHeaderWith: { _ in rawValue } )
7570 _storage. withUnsafeMutablePointerToElements { lock in
76- #if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(OpenBSD) || os(Android) || (os(WASI) && compiler(>=6.1) && _runtime(_multithreaded))
77- _ = pthread_mutex_init ( lock, nil )
78- #elseif os(Windows)
79- InitializeSRWLock ( lock)
80- #elseif os(WASI)
81- // No locks on WASI without multithreaded runtime.
82- #else
83- #warning("Platform-specific implementation missing: locking unavailable")
84- #endif
71+ L . initializeLock ( at: lock)
8572 }
8673 }
8774
@@ -103,28 +90,16 @@ struct Locked<T>: RawRepresentable, Sendable where T: Sendable {
10390 /// concurrency tools.
10491 nonmutating func withLock< R> ( _ body: ( inout T ) throws -> R ) rethrows -> R {
10592 try _storage. withUnsafeMutablePointers { rawValue, lock in
106- #if SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(OpenBSD) || os(Android) || (os(WASI) && compiler(>=6.1) && _runtime(_multithreaded))
107- _ = pthread_mutex_lock ( lock)
93+ L . unsafelyAcquireLock ( at: lock)
10894 defer {
109- _ = pthread_mutex_unlock ( lock)
95+ L . unsafelyRelinquishLock ( at : lock)
11096 }
111- #elseif os(Windows)
112- AcquireSRWLockExclusive ( lock)
113- defer {
114- ReleaseSRWLockExclusive ( lock)
115- }
116- #elseif os(WASI)
117- // No locks on WASI without multithreaded runtime.
118- #else
119- #warning("Platform-specific implementation missing: locking unavailable")
120- #endif
121-
12297 return try body ( & rawValue. pointee)
12398 }
12499 }
125100
126101 /// Acquire the lock and invoke a function while it is held, yielding both the
127- /// protected value and a reference to the lock itself .
102+ /// protected value and a reference to the underlying lock guarding it .
128103 ///
129104 /// - Parameters:
130105 /// - body: A closure to invoke while the lock is held.
@@ -134,16 +109,16 @@ struct Locked<T>: RawRepresentable, Sendable where T: Sendable {
134109 /// - Throws: Whatever is thrown by `body`.
135110 ///
136111 /// This function is equivalent to ``withLock(_:)`` except that the closure
137- /// passed to it also takes a reference to the underlying platform lock. This
138- /// function can be used when platform-specific functionality such as a
139- /// `pthread_cond_t` is needed. Because the caller has direct access to the
140- /// lock and is able to unlock and re-lock it, it is unsafe to modify the
141- /// protected value.
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.
142117 ///
143118 /// - Warning: Callers that unlock the lock _must_ lock it again before the
144119 /// closure returns. If the lock is not acquired when `body` returns, the
145120 /// effect is undefined.
146- nonmutating func withUnsafePlatformLock < R> ( _ body: ( UnsafeMutablePointer < PlatformLock > , T ) throws -> R ) rethrows -> R {
121+ nonmutating func withUnsafeUnderlyingLock < R> ( _ body: ( UnsafeMutablePointer < L > , T ) throws -> R ) rethrows -> R {
147122 try withLock { value in
148123 try _storage. withUnsafeMutablePointerToElements { lock in
149124 try body ( lock, value)
@@ -152,7 +127,16 @@ struct Locked<T>: RawRepresentable, Sendable where T: Sendable {
152127 }
153128}
154129
155- extension Locked where T: AdditiveArithmetic {
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+ // MARK: - Additions
138+
139+ extension LockedWith where T: AdditiveArithmetic {
156140 /// Add something to the current wrapped value of this instance.
157141 ///
158142 /// - Parameters:
@@ -168,7 +152,7 @@ extension Locked where T: AdditiveArithmetic {
168152 }
169153}
170154
171- extension Locked where T: Numeric {
155+ extension LockedWith where T: Numeric {
172156 /// Increment the current wrapped value of this instance.
173157 ///
174158 /// - Returns: The sum of ``rawValue`` and `1`.
@@ -188,7 +172,7 @@ extension Locked where T: Numeric {
188172 }
189173}
190174
191- extension Locked {
175+ extension LockedWith {
192176 /// Initialize an instance of this type with a raw value of `nil`.
193177 init < V> ( ) where T == V ? {
194178 self . init ( rawValue: nil )
@@ -198,4 +182,9 @@ extension Locked {
198182 init < K, V> ( ) where T == Dictionary < K , V > {
199183 self . init ( rawValue: [ : ] )
200184 }
185+
186+ /// Initialize an instance of this type with a raw value of `[]`.
187+ init < V> ( ) where T == [ V ] {
188+ self . init ( rawValue: [ ] )
189+ }
201190}
0 commit comments