Linux Programming

Threads and fork(): think twice before mixing them.

When debugging a program I came across a bug that was caused by using fork(2) in a multi-threaded program. I thought it's worth to write some words about mixing POSIX threads with fork(2) because there are non-obvious problems when doing that.

All about Linux signals

In most cases if you want to handle a signal in your application you write a simple signal handler like:

void handler (int sig)

and use the signal(2) system function to run it when a signal is delivered to the process. This is the simplest case, but signals are more interesting than that! Information contained in this article is useful for example when you are writing a daemon and must handle interrupting your program properly without interrupting the current operation or the whole program.

Waiting for a signal with timeout using sigtimedwait()

/* The program creates a child process and waits for it to finish. If a timeout
 * elapses the child is killed. Waiting is done using sigtimedwait().

Blocking signals with sigprocmask()

/** This program blocks SIGTERM signal for 10 seconds using sigprocmask(2)
 * After that the signal is unblocked and the queued signal is handled.
 */
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
 
static int got_signal = 0;
 
static void hdl (int sig)
{
	got_signal = 1;
}
 
int main (int argc, char *argv[])
{
	sigset_t mask;
	sigset_t orig_mask;
	struct sigaction act;
 
	memset (&act, 0, sizeof(act));
	act.sa_handler = hdl;
 
	if (sigaction(SIGTERM, &act, 0)) {
		perror ("sigaction");
		return 1;
	}
 
	sigemptyset (&mask);
	sigaddset (

Handling interruption of system calls by signals

/** Example of handling cases when system calls are interrupted by
 * a signal. This program copies its standard input to the standard output.
 * Here read() and write() may be interrupted.

Example of using signalfd()

/* Example of use of a Linux-specific call - signalfd() to handle signals using
 * a file descriptor.
 */
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/signalfd.h>
#include <string.h>
 
int main (int argc, char *argv[])
{
	int sfd;
	sigset_t mask;
 
	/* We will handle SIGTERM and SIGINT. */
	sigemptyset (&mask);
	sigaddset (&mask, SIGTERM);
	sigaddset (&mask, SIGINT);
 
	/* Block the signals thet we handle using signalfd(), so they don't
	 * cause signal handlers or default signal actions to execute.

Example of using sigaction()

/* Example of using sigaction() to setup a signal handler with 3 arguments
 * including siginfo_t.
 */
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
 
static void hdl (int sig, siginfo_t *siginfo, void *context)
{
	printf ("Sending PID: %ld, UID: %ld\n",
			(long)siginfo->si_pid, (long)siginfo->si_uid);
}
 
int main (int argc, char *argv[])
{
	struct sigaction act;
 
	memset (&act, '\0', sizeof(act));
 
	/* Use the sa_sigaction field because the handles has two additional parameters */
	act.sa_sigaction = &hdl;
 
	/* The SA_SIGINFO flag tells 

SIGBUS handling

/* Example of SIGBUS handling. A read from mmap()ed memory is invalid because
 * a file was shrinked. SIGBUS is sent to the process, but we handle it and
 * jump to another place in the program so it doesn't crash.
 *
 * Run this program with or without the 'shrink' argument.
 */
#include <sys/types.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <setjmp.h>
 
/* Size of the file in pages.

SIGCHLD handler

/* Simplest dead child cleanup in a SIGCHLD handler. Prevent zombie processes
 * but don't actually do anything with the information that a child died.
 */
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
 
/* SIGCHLD handler. */
static void sigchld_hdl (int sig)
{
	/* Wait for all dead processes.
	 * We use a non-blocking call to be sure this signal handler will not
	 * block if a child was cleaned up in another part of the program.

Using pselect() to avoid a signal race

/* An example of a free of signal race program using sigprocmask() and
 * pselect(). */
#include <sys/select.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
 
/* Flag that tells the daemon to exit. */
static volatile int exit_request = 0;
 
/* Signal handler.
Syndicate content