Handling UNIX Signals
Let’s learn about handling UNIX signals.
We'll cover the following
UNIX signals offer a very handy way of interacting asynchronously with our applications. However, UNIX signal handling requires the use of Go channels that are used exclusively for this task. So, it would be good to talk a little about the concurrency model of Go, which requires the use of goroutines and channels for signal handling.
Goroutine and channel
A goroutine is the smallest executable Go entity. In order to create a new goroutine, we have to use the go
keyword followed by a predefined function or an anonymous function—the methods are equivalent. A channel in Go is a mechanism that, among other things, allows goroutines to communicate and exchange data. If you are an amateur programmer or are hearing about goroutines and channels for the first time, do not panic. Goroutines and channels are explained in much more detail in later chapters.
Note: In order for a goroutine or a function to terminate the entire Go application, it should call
os.Exit()
instead ofreturn
. However, most of the time, we should exit a goroutine or a function usingreturn
because we just want to exit that specific goroutine or function and not stop the entire application.
The presented program handles SIGINT
, which is called syscall.SIGINT
in Go and SIGINFO
separately and uses a default
case in a switch
block for handling the remaining cases (other signals). The implementation of that switch
block allows us to differentiate between the various signals according to our needs.
There exists a dedicated channel that receives all signals, as defined by the signal.Notify()
function. Go channels can have a capacity—the capacity of this particular channel is 1
in order to be able to receive and keep one signal at a time. This makes perfect sense because a signal can terminate a program and there is no need to try to handle another signal at the same time. There is usually an anonymous function that is executed as a goroutine and performs the signal handling and nothing else. The main task of that goroutine is to listen to the channel for data. Once a signal is received, it is sent to that channel, read by the goroutine, and stored into a variable— at this point, the channel can receive more signals. That variable is processed by a switch
statement.
Note: Some signals cannot be caught, and the operating system cannot ignore them. So, the
SIGKILL
andSIGSTOP
signals cannot be blocked, caught, or ignored, and the reason for this is that they allow privileged users, as well as the UNIX kernel, to terminate any process they desire.
Coding example
Let’s look at the signals.go
code:
Get hands-on with 1400+ tech skills courses.