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,994 times
12

Papershine
- 4,995
- 2
- 24
- 48
2 Answers
22
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
- 529,903
- 94
- 1,240
- 1,382
-
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
-1
I use a simpler approach which is enough for my needs.
There is a limitation though. You can only access global-scoped things from the signalCallback
and please check the @cobbal comment below for other limitations.
Just paste those lines before any code is executed in the main.swift
:
let signalCallback: sig_t = { signal in
NSLog("Got signal: \(signal)")
exit(signal)
}
signal(SIGINT, signalCallback)

Anton Plebanovich
- 1,296
- 17
- 17
-
3Only a limited set of C functions are considered safe to use inside of a signal handler. Since the swift runtime may call all sorts of C functions under the hood, it's unsafe to use any swift at all in a signal handler. From https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/sigaction.2.html :"That is to say, the behaviour of such functions when called from a signal handler is undefined. In general though, signal handlers should do little more than set a flag; most other actions are not safe." – cobbal Feb 22 '23 at 19:49