How to capture different signals such as SIGINT and SIGTERM in Swift correctly? For example, when people stop my script by pressing Control-C, I want to do some cleanup before terminating it.
Asked
Active
Viewed 3,081 times
11
Papershine
- 4,593
- 2
- 24
- 44
1 Answers
19
Dispatch Sources can be used to monitor UNIX signals.
Here is a simple example, a Swift 3 translation of the C code in the "Monitoring Signals" section from the Concurrency Programming Guide.
import Dispatch // or Foundation
signal(SIGINT, SIG_IGN) // // Make sure the signal does not terminate the application.
let sigintSrc = DispatchSource.makeSignalSource(signal: SIGINT, queue: .main)
sigintSrc.setEventHandler {
print("Got SIGINT")
// ...
exit(0)
}
sigintSrc.resume()
Note that this requires an active GCD event loop, e.g. with
dispatchMain()
in a command-line program.
Martin R
- 510,973
- 84
- 1,183
- 1,314
-
1Remember to `import Dispatch`! – Papershine Aug 16 '17 at 13:04
-
@paper1111: You are right. It worked for me because my test code already imported Foundation. – Martin R Aug 16 '17 at 13:08
-
Didn't work for me, the eventHandler never gets called. Does the whole programm need to be run in `DispatchQueue.main`? – YourMJK Oct 28 '18 at 11:51
-
@M.J.K: Yes. As I said, it requires an active GCD event loop. – Martin R Oct 28 '18 at 12:29
-
Sorry if I'm missing something basic, but why does this work when all of the code is together in the main function, but if I try to register the signal handler in a class init, and run dispatchMain in the main function, the program blocks forever on sigint? – A Tyshka Aug 08 '20 at 03:44
-
@ATyshka I had a similar issue where the signal handler wasn't executing. As it turns out I forgot to also copy the `signintSrc.resume()` command which from the docs, "Resumes the invocation of block objects on a dispatch object". So without this, the block was never going to be executed. Maybe you also forgot to add this where you moved the handler definition? – JonnyB Oct 30 '20 at 20:40