Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions Sources/Subprocess/Thread.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,13 @@ private struct BackgroundWorkItem {
// exposed so we can use it with `pthread_cond_wait`.
private final class WorkQueue: Sendable {
private nonisolated(unsafe) var queue: [BackgroundWorkItem]
private nonisolated(unsafe) var isShuttingDown: Bool
internal nonisolated(unsafe) let mutex: UnsafeMutablePointer<MutexType>
internal nonisolated(unsafe) let waitCondition: UnsafeMutablePointer<ConditionType>

init() {
self.queue = []
self.isShuttingDown = false
self.mutex = UnsafeMutablePointer<MutexType>.allocate(capacity: 1)
self.waitCondition = UnsafeMutablePointer<ConditionType>.allocate(capacity: 1)
#if canImport(WinSDK)
Expand Down Expand Up @@ -128,7 +130,11 @@ private final class WorkQueue: Sendable {
pthread_mutex_unlock(mutex)
}
#endif
if condition(&queue) {
// Use a `while` loop (not `if`) so that spurious wakeups and signal
// interruptions of `pthread_cond_wait` do not fall through the wait.
// `condition` is responsible for also returning `false` when shutting
// down, so the worker can wake and exit rather than sleeping forever.
while condition(&queue) {
#if canImport(WinSDK)
SleepConditionVariableCS(self.waitCondition, mutex, INFINITE)
#else
Expand All @@ -141,8 +147,9 @@ private final class WorkQueue: Sendable {
// Only called in worker thread. Sleeps the thread if there's no more item
func dequeue() -> BackgroundWorkItem? {
return self.withUnsafeUnderlyingLock { queue in
// Sleep the worker thread if there's no more work
queue.isEmpty
// Sleep the worker thread while there's no work and we're not
// shutting down. Returning `false` here ends the wait.
queue.isEmpty && !self.isShuttingDown
} body: { mutex, queue in
guard !queue.isEmpty else {
return nil
Expand All @@ -166,6 +173,7 @@ private final class WorkQueue: Sendable {
func shutdown() {
self.withLock { queue in
queue.removeAll()
self.isShuttingDown = true
#if canImport(WinSDK)
WakeConditionVariable(self.waitCondition)
#else
Expand Down