79 lines · 2.3 KB · Swift
RawDownload
import CodexBarCoreimport Dispatchimport 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    }}