11

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.

Papershine
  • 4,593
  • 2
  • 24
  • 44

1 Answers1

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
  • 1
    Remember 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