@@ -14,28 +14,54 @@ import Basic
14
14
/// Interrupt signal handling global variables
15
15
private var wasInterrupted = false
16
16
private var wasInterruptedLock = Lock ( )
17
+ #if os(Windows)
18
+ private var signalWatchingPipe : [ HANDLE ] = [ INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE]
19
+ #else
17
20
private var signalWatchingPipe : [ Int32 ] = [ 0 , 0 ]
18
21
private var oldAction = sigaction ( )
22
+ #endif
19
23
20
24
/// This class can be used by command line tools to install a handler which
21
25
/// should be called when a interrupt signal is delivered to the process.
22
26
public final class InterruptHandler {
23
27
24
28
/// The thread which waits to be notified when a signal is received.
25
29
let thread : Thread
30
+ #if os(Windows)
31
+ let signalHandler : @convention ( c) ( UInt32 ) -> Int32
32
+ #else
33
+ let signalHandler : @convention ( c) ( Int32 ) -> Void
34
+ #endif
26
35
27
36
/// Start watching for interrupt signal and call the handler whenever the signal is received.
28
37
public init ( _ handler: @escaping ( ) -> Void ) throws {
29
38
// Create a signal handler.
30
- let signalHandler : @ convention ( c ) ( Int32 ) -> Void = { _ in
39
+ signalHandler = { _ in
31
40
// Turn on the interrupt bool.
32
41
wasInterruptedLock. withLock {
33
42
wasInterrupted = true
34
43
}
35
44
// Write on pipe to notify the watching thread.
36
45
var byte : UInt8 = 0
46
+ #if os(Windows)
47
+ var bytesWritten : DWORD = 0
48
+ WriteFile ( signalWatchingPipe [ 1 ] , & byte, 1 , & bytesWritten, nil )
49
+ return TRUE
50
+ #else
37
51
write ( signalWatchingPipe [ 1 ] , & byte, 1 )
52
+ #endif
38
53
}
54
+ #if os(Windows)
55
+ SetConsoleCtrlHandler ( signalHandler, TRUE)
56
+
57
+ var readPipe : HANDLE ?
58
+ var writePipe : HANDLE ?
59
+ let rv = CreatePipe ( & readPipe, & writePipe, nil , 1 )
60
+ signalWatchingPipe = [ readPipe!, writePipe!]
61
+ guard rv != FALSE else {
62
+ throw SystemError . pipe ( rv)
63
+ }
64
+ #else
39
65
var action = sigaction ( )
40
66
#if canImport(Darwin)
41
67
action. __sigaction_u. __sa_handler = signalHandler
@@ -51,13 +77,19 @@ public final class InterruptHandler {
51
77
guard rv == 0 else {
52
78
throw SystemError . pipe ( rv)
53
79
}
80
+ #endif
54
81
55
82
// This thread waits to be notified via pipe. If something is read from pipe, check the interrupt bool
56
83
// and send termination signal to all spawned processes in the process group.
57
84
thread = Thread {
58
85
while true {
59
86
var buf : Int8 = 0
87
+ #if os(Windows)
88
+ var n : DWORD = 0
89
+ ReadFile ( signalWatchingPipe [ 1 ] , & buf, 1 , & n, nil )
90
+ #else
60
91
let n = read ( signalWatchingPipe [ 0 ] , & buf, 1 )
92
+ #endif
61
93
// Pipe closed, nothing to do.
62
94
if n == 0 { break }
63
95
// Read the value of wasInterrupted and set it to false.
@@ -71,15 +103,24 @@ public final class InterruptHandler {
71
103
handler ( )
72
104
}
73
105
}
106
+ #if os(Windows)
107
+ CloseHandle ( signalWatchingPipe [ 0 ] )
108
+ #else
74
109
close ( signalWatchingPipe [ 0 ] )
110
+ #endif
75
111
}
76
112
thread. start ( )
77
113
}
78
114
79
115
deinit {
116
+ #if os(Windows)
117
+ SetConsoleCtrlHandler ( signalHandler, FALSE)
118
+ CloseHandle ( signalWatchingPipe [ 1 ] )
119
+ #else
80
120
// Restore the old action and close the write end of pipe.
81
121
sigaction ( SIGINT, & oldAction, nil )
82
122
close ( signalWatchingPipe [ 1 ] )
123
+ #endif
83
124
thread. join ( )
84
125
}
85
126
}
0 commit comments