Golang : Intercept and process UNIX signals example




Golang's os/signal package allows you to configure the behaviour of your Golang program upon receiving certain type of UNIX signals. Most Linux/Unix based program will gladly die upon receiving a kill signal, but in case you want your program to intercept the signal first, perform some backup, flush data to disk, etc before dying, then you should use the os/signal package.

Here is a simple Golang example on how to intercept the most common UNIX kill/terminate signals.

File : ossignal.go

 package main

 import (
 "fmt"
 "os"
 "os/signal"
 "syscall"
 )

 func main() {
 go ProcessSignal()

 done := make(chan bool, 1)

 fmt.Println("Open a new terminal, get the PID and issue kill -# PID command")

 // loop forever
 for {
 select {
 case <-done:
 break
 }

 }

 }

 func ProcessSignal() {

 sigch := make(chan os.Signal)

 // the case statement below will mute if not binded to signal.Notify
 // will purposely leave out SIGABRT(abort) as an example

 signal.Notify(sigch, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL, syscall.SIGTERM, syscall.SIGUSR1, syscall.SIGUSR2, syscall.SIGHUP, os.Interrupt)

 for {
 signalType := <-sigch
 fmt.Println("Received signal from channel : ", signalType)

 switch signalType {
 default:
 fmt.Printf("got signal = %v \n", signalType)
 case syscall.SIGHUP:
 fmt.Println("got Hangup/SIGHUP - portable number 1")
 case syscall.SIGINT:
 fmt.Println("got Terminal interrupt signal/SIGINT - portable number 2")
 case syscall.SIGQUIT:
 fmt.Println("got Terminal quit signal/SIGQUIT - portable number 3 - will core dump")
 case syscall.SIGABRT:
 fmt.Println("got Process abort signal/SIGABRT - portable number 6 - will core dump")
 case syscall.SIGKILL:
 fmt.Println("got Kill signal/SIGKILL - portable number 9")
 case syscall.SIGALRM:
 fmt.Println("got Alarm clock signal/SIGALRM - portable number 14")
 case syscall.SIGTERM:
 fmt.Println("got Termination signal/SIGTERM - portable number 15")
 case syscall.SIGUSR1:
 fmt.Println("got User-defined signal 1/SIGUSR1")
 //HINT : this is where you want to tell your program do something upon receiving a user-defined-signal

 case syscall.SIGUSR2:
 fmt.Println("got User-defined signal 2/SIGUSR2")

 }
 }
 }

Run the above program and open another terminal. Find out the ossignal process identifier(PID) and issue kill commands to it.

Example of getting the PID :

>ps -ef | grep ossignal

501 965 796 0 1:07PM ttys000 0:00.04 go run ossignal.go

501 968 965 0 1:07PM ttys000 0:00.00 /var/folders/nd/5m9x1/T/go-build114926687/command-line-arguments/_obj/exe/ossignal

501 970 829 0 1:07PM ttys001 0:00.00 grep ossignal

Use process identifier 968

Sample inputs and outputs :

>kill 968

Received signal from channel : terminated

got Termination signal/SIGTERM - portable number 15


>kill -3 968

Received signal from channel : quit

got Terminal quit signal/SIGQUIT - portable number 3 - will core dump


>kill -USR1 968

Received signal from channel : user defined signal 1

got User-defined signal 1/SIGUSR1


NOTES : Because the above program did not bind SIGABRT (abort signal) to signal.Notify(). The program will NOT be able to intercept the kill -6 command. It will display the core dump on screen.

For complete reference of the available UNIX signals. See https://en.wikipedia.org/wiki/Unixsignal#POSIXsignals

Happy coding!

References :

https://golang.org/pkg/os/signal/

https://en.wikipedia.org/wiki/Unix_signal

https://socketloop.com/tutorials/golang-intercept-ctrl-c-interrupt-or-kill-signal-and-determine-the-signal-type

  See also : Golang : Intercept Ctrl-C interrupt or kill signal and determine the signal type





By Adam Ng

IF you gain some knowledge or the information here solved your programming problem. Please consider donating to the less fortunate or some charities that you like. Apart from donation, planting trees, volunteering or reducing your carbon footprint will be great too.


Advertisement