Slides: Sysprog: Signals#

Signals are poor notifications to a process

  • Number between 1 and 31

  • Sent to a process from another process

  • Sent to a process by the kernel

Example Signals#

SIGINT

Ctrl-C

termination

SIGTSTP

Ctrl-Z

suspend

SIGTERM

kill <pid>

termination

SIGALRM

Timer expiration

termination

  • Many more

  • Beware of SIGALRM. There better ways of timer management, nowadays.

Terminology#

  • Generate. A signal is sent.

  • Deliver. The signal is received by a process (delivered by the kernel). The signal handler is run.

  • Pending. A signal is pending on a process until it is delivered.

  • Blocked. A process refuses to get a signal delivered (he “blocks” the signal).

  • Signal Mask. The set of signals that are blocked by a process.

man -s 7 signal.

Default Actions#

All signals have a predefined default action

  • The signal is ignored. E.g. SIGCHLD.

  • Process termination. Abnormal Process Termination, as opposed to exit(). With or without core dump.

  • The process is stopped or continued.

Important Signals#

Signal

Default Action

Reason

SIGABRT

Terminate(core)

E.g. assert()

SIGSEGV

Terminate(core)

Access violation

SIGBUS

Terminate(core)

Access violation

SIGILL

Terminate(core)

Bogus function pointer

SIGFPE

Terminate(core)

Floating point

SIGINT

Terminate

Ctrl-C

SIGTERM

Terminate

Explicit kill

SIGPIPE

Terminate

Write to pipe/socket

SIGCHLD

Ignore

Child death

Sending, Commandline#

$ kill -l
... signals here ...
$ kill 1234   # to PID
$ kill -SEGV 1234   # kill as if segfaulted
$ killall firefox

man -s 1 kill

Sending Signals, Programmatically#

int kill(pid_t pid, int sig);
  • pid specifies where the signal goes to

  • pid > 0: process

  • pid == -1: Broadcast; every process the sender has permissions to. Except init and the sender itself.

  • pid == 0 or pid < -1: process group

man -s 2 kill

Warning!#

  • Signals are no toy

  • Signals are no communication medium

  • Signal handlers are executing in a context that has nothing to do with normal program context -> asynchronous

  • One does not install a signal handler for e.g. SIGSEGV

  • One does not ignore SIGSEGV

  • One does not block SIGSEGV

Blocking Signals: Signal Mask#

Signal Mask

  • Process attribute (more exactly: thread)

  • Specifies which signals are blocked

  • Signals that have been sent to a process but which are blocked remain pending

  • Pending signals are delivered as soon as they are unblocked

  • Signals of the same type don’t pile up at the receiver

    • two SIGINT are only delivered once

Signal Mask Manipulation#

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
  • Blocks all signal from set

  • Returns previously blocked signals in oldset

  • Behavior unspecified in multithreaded programs (use pthread_sigmask())

man -s 2 sigprocmask

Pending Signals#

int sigpending(sigset_t *set);

Boring …

man -s 2 sigpending

Signal Set: sigset_t#

int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signum);
int sigdelset(sigset_t *set, int signum);
int sigismember(const sigset_t *set, int signum);
  • Signal Set: set of signals (obviously). Signals are numbered 1 through 31

  • sigset_t is an int, actually. A bitmask.

man -s 3 sigsetops

Signal Handlers#

  • Default action is sufficient in most cases

    • SIGSEGV crashes and dumps core

    • SIGINT (Ctrl-C) terminates

  • Customizing signal reception: install signal handler

    • Pointer to C function

void handler(int sig);

Installing a Signal Handler (1)#

struct sigaction {
    void     (*sa_handler)(int);
    sigset_t   sa_mask;
    int        sa_flags;
};
int sigaction(int signum,
    const struct sigaction *act,
    struct sigaction *oldact);

man -s 2 sigaction

Installing a Signal Handler (2)#

  • Special sa_handler values

    • SIG_IGN: ignore the signal

    • SIG_DFL: restore default action

  • Historical baggage

    sighandler_t signal(int signum, sighandler_t handler);
    
    • Unclear semantics

    • Not portable

Effects of Signal Delivery#

E.g. terminate a program based upon the value of a flag (by dropping out of a loop) that is set in a signal handler. Use …

volatile sig_atomic_t flag;
  • Blocking system calls (e.g. read() or write()) return an error when they have been interrupted by a signal

  • errno is EINTR

Last Warning!#

Signals are delivered asynchronously

  • Much like hardware interrupts (only in software)

  • Literally nothing is legal

    • Only async-signal-safe functions can be used

    • Practically only system calls

man -s 7 signal-safety

WTF Async Signal Safe?#

The following functions (among many others) are not async-signal-safe

  • printf(), sprintf() (everything from stdio.h and iostream, respectively)

  • malloc(), free() etc.

  • exit() (_exit() is safe because a system call)

  • Everything from pthread.h

Exercise: Signals#

Write a program that …

  • … reads from STDIN_FILENO in a loop, and outputs what was read to STDOUT_FILENO. Imagine that this is a replacement for an immensely important work which can block - the program blocks on STDIN_FILENO.

  • On program termination, the program has to do important cleanup work - it has to catch at least SIGINT and SIGTERM.

  • Our cleanup work is to safely - not in the signal handler - write “Goodbye!” to standard output.