Skip to content

Commit 6cb1d0f

Browse files
committed
Fix all the concurrency warnings and errors in the main target
1 parent 15b406f commit 6cb1d0f

File tree

7 files changed

+40
-19
lines changed

7 files changed

+40
-19
lines changed

Sources/SignalHandling/DelayedSigaction/DelayedSigactionHandler.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ import Foundation
1212
- Parameter signal: The signal that triggered the delayed sigaction.
1313
- Parameter sigactionAllowedHandler: The handler to call when the sigaction can be triggered or dropped.
1414
- Parameter allowSigaction: Whether the sigaction handler should be called, or the signal should be dropped. */
15-
public typealias DelayedSigactionHandler = (_ signal: Signal, _ sigactionAllowedHandler: @escaping (_ allowSigaction: Bool) -> Void) -> Void
15+
public typealias DelayedSigactionHandler = (_ signal: Signal, _ sigactionAllowedHandler: @escaping @Sendable (_ allowSigaction: Bool) -> Void) -> Void

Sources/SignalHandling/DelayedSigaction/SigactionDelayer_Block.swift

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ public enum SigactionDelayer_Block {
6464
- Important: Must be called before any thread is spawned.
6565
- Important: You should not use `pthread_sigmask` to sigprocmask (nor anything to unblock signals) after calling this method. */
6666
public static func bootstrap(for signals: Set<Signal>) throws {
67+
assert(!Thread.isMultiThreaded())
6768
guard !bootstrapDone else {
6869
fatalError("DelayedSigaction can be bootstrapped only once")
6970
}
@@ -93,7 +94,10 @@ public enum SigactionDelayer_Block {
9394
}
9495
}
9596
group.wait()
97+
9698
if let e = error {throw e}
99+
/* NOT in a defer as we do not want this to be set to true if the error check above throws. */
100+
bootstrapDone = true
97101
}
98102

99103
public static func registerDelayedSigaction(_ signal: Signal, handler: @escaping DelayedSigactionHandler) throws -> DelayedSigaction {
@@ -175,8 +179,9 @@ public enum SigactionDelayer_Block {
175179

176180
static let lock = NSConditionLock(condition: Self.nothingToDo.rawValue)
177181

178-
static var action: Action = .nop
179-
static var error: Error?
182+
/* Read/write is protected by the lock above. */
183+
static nonisolated(unsafe) var action: Action = .nop
184+
static nonisolated(unsafe) var error: Error?
180185

181186
case nothingToDo
182187
case actionInThread
@@ -193,8 +198,10 @@ public enum SigactionDelayer_Block {
193198

194199
private static let signalProcessingQueue = DispatchQueue(label: "com.xcode-actions.blocked-signals-processing-queue")
195200

196-
private static var bootstrapDone = false
197-
private static var blockedSignals = [Signal: BlockedSignal]()
201+
/* Only used on the main thread. */
202+
private static nonisolated(unsafe) var bootstrapDone = false
203+
/* Only used in the signals processing queue. */
204+
private static nonisolated(unsafe) var blockedSignals = [Signal: BlockedSignal]()
198205

199206
private static func executeOnThread(_ action: ThreadSync.Action) throws {
200207
do {
@@ -323,18 +330,22 @@ public enum SigactionDelayer_Block {
323330
}
324331

325332
for _ in 0..<count {
333+
let lock = NSLock()
326334
let group = DispatchGroup()
327-
var runOriginalHandlerFinal = true
335+
nonisolated(unsafe) var runOriginalHandlerFinal = true
328336
for (_, handler) in blockedSignal.handlers {
329337
group.enter()
330338
handler(signal, { runOriginalHandler in
331-
runOriginalHandlerFinal = runOriginalHandlerFinal && runOriginalHandler
339+
lock.withLock{
340+
runOriginalHandlerFinal = runOriginalHandlerFinal && runOriginalHandler
341+
}
332342
group.leave()
333343
})
334344
}
335345
group.wait()
336346

337-
/* All the handlers have responded, we now know whether to allow or drop the signal. */
347+
/* All the handlers have responded, we now know whether to allow or drop the signal.
348+
* No need to lock the lock to access runOriginalHandlerFinal here as all possible changes are finished by now. */
338349
do {try executeOnThread(runOriginalHandlerFinal ? .suspend(for: signal) : .drop(signal))}
339350
catch {
340351
Conf.logger?.error(

Sources/SignalHandling/DelayedSigaction/SigactionDelayer_Unsig.swift

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ public enum SigactionDelayer_Unsig {
100100
  MARK: - Private
101101
  *************** */
102102

103-
private enum ThreadSync : Int {
103+
private enum ThreadSync : Int, Sendable {
104104

105105
enum Action {
106106
case nop
@@ -132,8 +132,9 @@ public enum SigactionDelayer_Unsig {
132132

133133
static let lock = NSConditionLock(condition: Self.nothingToDo.rawValue)
134134

135-
static var action: Action = .nop
136-
static var completionResult: ErrorAndLogs?
135+
/* Read/write is protected by the lock above. */
136+
static nonisolated(unsafe) var action: Action = .nop
137+
static nonisolated(unsafe) var completionResult: ErrorAndLogs?
137138

138139
case nothingToDo
139140
case actionInThread
@@ -152,8 +153,9 @@ public enum SigactionDelayer_Unsig {
152153

153154
private static let signalProcessingQueue = DispatchQueue(label: "com.xcode-actions.unsigactioned-signals-processing-queue")
154155

155-
private static var hasCreatedProcessingThread = false
156-
private static var unsigactionedSignals = [Signal: UnsigactionedSignal]()
156+
/* Both these vars are only modified/read on the signal processing queue. */
157+
private static nonisolated(unsafe) var hasCreatedProcessingThread = false
158+
private static nonisolated(unsafe) var unsigactionedSignals = [Signal: UnsigactionedSignal]()
157159

158160
private static func executeOnThread(_ action: ThreadSync.Action) throws {
159161
try createProcessingThreadIfNeededOnQueue()
@@ -270,16 +272,21 @@ public enum SigactionDelayer_Unsig {
270272
Conf.logger?.trace("", metadata: ["signal": "\(signal)", "original-sigaction": "\(unsigactionedSignal.originalSigaction)"])
271273

272274
for _ in 0..<count {
275+
let lock = NSLock()
273276
let group = DispatchGroup()
274-
var runOriginalHandlerFinal = true
277+
nonisolated(unsafe) var runOriginalHandlerFinal = true
275278
for (_, handler) in unsigactionedSignal.handlers {
276279
group.enter()
277280
handler(signal, { runOriginalHandler in
278-
runOriginalHandlerFinal = runOriginalHandlerFinal && runOriginalHandler
281+
lock.withLock{
282+
runOriginalHandlerFinal = runOriginalHandlerFinal && runOriginalHandler
283+
}
279284
group.leave()
280285
})
281286
}
282287
group.wait()
288+
289+
/* No need to lock the lock to access runOriginalHandlerFinal here as all possible changes are finished by now. */
283290
if runOriginalHandlerFinal {
284291
Conf.logger?.trace("Resending signal.", metadata: ["signal": "\(signal)"])
285292
do {try executeOnThread(.send(signal, with: unsigactionedSignal.originalSigaction))}

Sources/signal-handling-tests-helper/DelaySignalUnsigaction.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import Foundation
22

33
import ArgumentParser
44
import CLTLogger
5+
import GlobalConfModule
56
import Logging
67

78
import SignalHandling
@@ -15,7 +16,7 @@ struct DelaySignalUnsigaction : ParsableCommand {
1516

1617
func run() throws {
1718
LoggingSystem.bootstrap{ _ in CLTLogger(multilineMode: .allMultiline) }
18-
SignalHandlingConfig.logger?.logLevel = .trace
19+
Conf[rootValueFor: \.signalHandling.logger]?.logLevel = .trace
1920

2021
let signal = Signal(rawValue: signalNumber)
2122

Sources/signal-handling-tests-helper/ManualDispatchMemTest.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import Foundation
22

33
import ArgumentParser
44
import CLTLogger
5+
import GlobalConfModule
56
import Logging
67

78
import SignalHandling
@@ -29,7 +30,7 @@ struct ManualDispatchMemTest : ParsableCommand {
2930
var logger = Logger(label: "main")
3031
logger.logLevel = .trace
3132
Self.logger = logger /* We must do this to be able to use the logger from the C handler. */
32-
SignalHandlingConfig.logger?.logLevel = .trace
33+
Conf[rootValueFor: \.signalHandling.logger]?.logLevel = .trace
3334

3435
let signal = Signal.interrupt
3536
logger.info("Process started; monitored signal is \(signal)")

Sources/signal-handling-tests-helper/ManualTest.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import Foundation
22

33
import ArgumentParser
44
import CLTLogger
5+
import GlobalConfModule
56
import Logging
67

78
import SignalHandling
@@ -30,7 +31,7 @@ struct ManualTest : ParsableCommand {
3031
var logger = Logger(label: "main")
3132
logger.logLevel = .trace
3233
Self.logger = logger /* We must do this to be able to use the logger from the C handler. */
33-
SignalHandlingConfig.logger?.logLevel = .trace
34+
Conf[rootValueFor: \.signalHandling.logger]?.logLevel = .trace
3435

3536
try Sigaction(handler: .ansiC({ _ in Self.logger?.debug("In libxct-test-helper sigaction handler for interrupt") })).install(on: .interrupt)
3637
try Sigaction(handler: .ansiC({ _ in Self.logger?.debug("In libxct-test-helper sigaction handler for terminated") })).install(on: .terminated)

Sources/signal-handling-tests-helper/main.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import ArgumentParser
66

77
struct SignalHandlingTestsHelper : ParsableCommand {
88

9-
static var configuration = CommandConfiguration(
9+
static let configuration = CommandConfiguration(
1010
subcommands: [
1111
ManualTest.self,
1212
ManualDispatchMemTest.self,

0 commit comments

Comments
 (0)