diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 30b589c..8267c93 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -28,14 +28,14 @@ jobs: # Test dependencies yum install -y procps fi - linux_build_command: 'swift-format lint -s -r --configuration ./.swift-format . && swift test && swift test --disable-default-traits' + linux_build_command: 'swift-format lint -s -r --configuration ./.swift-format . && swift test && swift test -c release && swift test --disable-default-traits' windows_swift_versions: '["6.1", "nightly-main"]' windows_build_command: | Invoke-Program swift test Invoke-Program swift test --disable-default-traits enable_macos_checks: true macos_xcode_versions: '["16.3"]' - macos_build_command: 'xcrun swift-format lint -s -r --configuration ./.swift-format . && xcrun swift test && xcrun swift test --disable-default-traits' + macos_build_command: 'xcrun swift-format lint -s -r --configuration ./.swift-format . && xcrun swift test && xcrun swift test -c release && xcrun swift test --disable-default-traits' enable_linux_static_sdk_build: true linux_static_sdk_versions: '["6.1", "nightly-6.2"]' linux_static_sdk_build_command: | diff --git a/Sources/Subprocess/Thread.swift b/Sources/Subprocess/Thread.swift index a4e5c0c..3369134 100644 --- a/Sources/Subprocess/Thread.swift +++ b/Sources/Subprocess/Thread.swift @@ -77,12 +77,33 @@ private struct BackgroundWorkItem { // We can't use Mutex directly here because we need the underlying `pthread_mutex_t` to be // exposed so we can use it with `pthread_cond_wait`. private final class WorkQueue: Sendable { - private nonisolated(unsafe) var queue: [BackgroundWorkItem] + // Queue needs to be a reference type because we pass it inout + final class Queue: Sendable { + internal nonisolated(unsafe) var queue: [BackgroundWorkItem] + + var isEmpty: Bool { self.queue.isEmpty } + + func append(_ item: BackgroundWorkItem) { + self.queue.append(item) + } + + func removeFirst() -> BackgroundWorkItem { + return self.queue.removeFirst() + } + + func removeAll() { self.queue.removeAll() } + + init() { + self.queue = [] + } + } + + private nonisolated(unsafe) var queue: Queue internal nonisolated(unsafe) let mutex: UnsafeMutablePointer internal nonisolated(unsafe) let waitCondition: UnsafeMutablePointer init() { - self.queue = [] + self.queue = Queue() self.mutex = UnsafeMutablePointer.allocate(capacity: 1) self.waitCondition = UnsafeMutablePointer.allocate(capacity: 1) #if canImport(WinSDK) @@ -94,14 +115,14 @@ private final class WorkQueue: Sendable { #endif } - func withLock(_ body: (inout [BackgroundWorkItem]) throws -> R) rethrows -> R { + func withLock(_ body: (inout Queue) throws -> R) rethrows -> R { try withUnsafeUnderlyingLock { _, queue in try body(&queue) } } private func withUnsafeUnderlyingLock( - _ body: (UnsafeMutablePointer, inout [BackgroundWorkItem]) throws -> R + _ body: (UnsafeMutablePointer, inout Queue) throws -> R ) rethrows -> R { #if canImport(WinSDK) EnterCriticalSection(self.mutex)