Skip to content

Commit f31a9b9

Browse files
committed
Adopt Mutex.
This PR adopts `Mutex` on all platforms except Darwin (where we still need to back-deploy further than `Mutex` is available.) Resolves #538.
1 parent c996b0a commit f31a9b9

File tree

5 files changed

+100
-233
lines changed

5 files changed

+100
-233
lines changed

Sources/Testing/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ add_library(Testing
8989
Support/Graph.swift
9090
Support/JSON.swift
9191
Support/Locked.swift
92-
Support/Locked+Platform.swift
9392
Support/VersionNumber.swift
9493
Support/Versions.swift
9594
Discovery+Macro.swift

Sources/Testing/ExitTests/WaitFor.swift

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,42 @@ func wait(for pid: consuming pid_t) async throws -> ExitStatus {
8080
}
8181
#elseif SWT_TARGET_OS_APPLE || os(Linux) || os(FreeBSD) || os(OpenBSD)
8282
/// A mapping of awaited child PIDs to their corresponding Swift continuations.
83-
private let _childProcessContinuations = LockedWith<pthread_mutex_t, [pid_t: CheckedContinuation<ExitStatus, any Error>]>()
83+
private nonisolated(unsafe) let _childProcessContinuations = {
84+
let result = ManagedBuffer<[pid_t: CheckedContinuation<ExitStatus, any Error>], pthread_mutex_t>.create(
85+
minimumCapacity: 1,
86+
makingHeaderWith: { _ in [:] }
87+
)
88+
89+
result.withUnsafeMutablePointers { sectionBounds, lock in
90+
_ = pthread_mutex_init(lock, nil)
91+
}
92+
93+
return result
94+
}()
95+
96+
/// Access the value in `_childProcessContinuations` while guarded by its lock.
97+
///
98+
/// - Parameters:
99+
/// - body: A closure to invoke while the lock is held.
100+
///
101+
/// - Returns: Whatever is returned by `body`.
102+
///
103+
/// - Throws: Whatever is thrown by `body`.
104+
private func _withLockedChildProcessContinuations<R>(
105+
_ body: (
106+
_ childProcessContinuations: inout [pid_t: CheckedContinuation<ExitStatus, any Error>],
107+
_ lock: UnsafeMutablePointer<pthread_mutex_t>
108+
) throws -> R
109+
) rethrows -> R {
110+
try _childProcessContinuations.withUnsafeMutablePointers { childProcessContinuations, lock in
111+
_ = pthread_mutex_lock(lock)
112+
defer {
113+
_ = pthread_mutex_unlock(lock)
114+
}
115+
116+
return try body(&childProcessContinuations.pointee, lock)
117+
}
118+
}
84119

85120
/// A condition variable used to suspend the waiter thread created by
86121
/// `_createWaitThread()` when there are no child processes to await.
@@ -116,7 +151,7 @@ private let _createWaitThread: Void = {
116151
var siginfo = siginfo_t()
117152
if 0 == waitid(P_ALL, 0, &siginfo, WEXITED | WNOWAIT) {
118153
if case let pid = siginfo.si_pid, pid != 0 {
119-
let continuation = _childProcessContinuations.withLock { childProcessContinuations in
154+
let continuation = _withLockedChildProcessContinuations { childProcessContinuations, _ in
120155
childProcessContinuations.removeValue(forKey: pid)
121156
}
122157

@@ -137,7 +172,7 @@ private let _createWaitThread: Void = {
137172
// newly-scheduled waiter process. (If this condition is spuriously
138173
// woken, we'll just loop again, which is fine.) Note that we read errno
139174
// outside the lock in case acquiring the lock perturbs it.
140-
_childProcessContinuations.withUnsafeUnderlyingLock { lock, childProcessContinuations in
175+
_withLockedChildProcessContinuations { childProcessContinuations, lock in
141176
if childProcessContinuations.isEmpty {
142177
_ = pthread_cond_wait(_waitThreadNoChildrenCondition, lock)
143178
}
@@ -209,7 +244,7 @@ func wait(for pid: consuming pid_t) async throws -> ExitStatus {
209244
_createWaitThread
210245

211246
return try await withCheckedThrowingContinuation { continuation in
212-
_childProcessContinuations.withLock { childProcessContinuations in
247+
_withLockedChildProcessContinuations { childProcessContinuations, _ in
213248
// We don't need to worry about a race condition here because waitid()
214249
// does not clear the wait/zombie state of the child process. If it sees
215250
// the child process has terminated and manages to acquire the lock before

Sources/Testing/Support/Locked+Platform.swift

Lines changed: 0 additions & 96 deletions
This file was deleted.

0 commit comments

Comments
 (0)