80 lines
2.3 KiB
Swift
80 lines
2.3 KiB
Swift
import CodexBarCore
|
|
import Dispatch
|
|
import Foundation
|
|
#if canImport(Darwin)
|
|
import Darwin
|
|
#elseif canImport(Glibc)
|
|
import Glibc
|
|
#elseif canImport(Musl)
|
|
import Musl
|
|
#endif
|
|
|
|
private func handleCLITerminationSignal(_: Int32) {}
|
|
|
|
final class CLITerminationSignalMonitor: @unchecked Sendable {
|
|
static let signalNumbers = [SIGINT, SIGTERM, SIGHUP]
|
|
|
|
private let lock = NSLock()
|
|
private let sources: [DispatchSourceSignal]
|
|
private var isCancelled = false
|
|
|
|
init(onSignal: @escaping @Sendable (Int32) -> Void) {
|
|
self.sources = Self.signalNumbers.map { signalNumber in
|
|
Self.installCaptureHandler(for: signalNumber)
|
|
let source = DispatchSource.makeSignalSource(signal: signalNumber, queue: .global(qos: .utility))
|
|
source.setEventHandler {
|
|
onSignal(signalNumber)
|
|
}
|
|
source.resume()
|
|
return source
|
|
}
|
|
}
|
|
|
|
func cancel() {
|
|
self.lock.lock()
|
|
guard !self.isCancelled else {
|
|
self.lock.unlock()
|
|
return
|
|
}
|
|
self.isCancelled = true
|
|
self.lock.unlock()
|
|
|
|
for source in self.sources {
|
|
source.cancel()
|
|
}
|
|
for signalNumber in Self.signalNumbers {
|
|
Self.restoreDefaultHandler(for: signalNumber)
|
|
}
|
|
}
|
|
|
|
deinit {
|
|
self.cancel()
|
|
}
|
|
|
|
static func terminateActiveHelpersAndReraise(_ signalNumber: Int32) {
|
|
TTYCommandRunner.terminateActiveProcessesForAppShutdown()
|
|
self.restoreDefaultHandler(for: signalNumber)
|
|
_ = kill(getpid(), signalNumber)
|
|
}
|
|
|
|
private static func installCaptureHandler(for signalNumber: Int32) {
|
|
#if canImport(Darwin)
|
|
_ = Darwin.signal(signalNumber, handleCLITerminationSignal)
|
|
#elseif canImport(Glibc)
|
|
_ = Glibc.signal(signalNumber, handleCLITerminationSignal)
|
|
#elseif canImport(Musl)
|
|
_ = Musl.signal(signalNumber, handleCLITerminationSignal)
|
|
#endif
|
|
}
|
|
|
|
private static func restoreDefaultHandler(for signalNumber: Int32) {
|
|
#if canImport(Darwin)
|
|
_ = Darwin.signal(signalNumber, SIG_DFL)
|
|
#elseif canImport(Glibc)
|
|
_ = Glibc.signal(signalNumber, SIG_DFL)
|
|
#elseif canImport(Musl)
|
|
_ = Musl.signal(signalNumber, SIG_DFL)
|
|
#endif
|
|
}
|
|
}
|