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.