Linux Signals: Custom Ctrl+C Handler (Short Practical Guide)

In Linux/embedded Linux, signals are useful for lightweight control events. Typical use: stop, reload, notify, timeout.

This example shows:

  • Custom Ctrl+C (SIGINT) behavior
  • Sending SIGUSR1 to another process
  • Using SIGALRM as a timeout

Full short example

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define W(msg) write(STDOUT_FILENO, msg, sizeof(msg) - 1)

static volatile sig_atomic_t running = 1;
static volatile sig_atomic_t got_usr1 = 0;
static volatile sig_atomic_t child_pid = -1;

static void on_sigint(int sig) {
    (void)sig;
    W("\nSIGINT: Ctrl+C caught. Sending SIGUSR1 to child and setting 3s alarm...\n");

    if (child_pid > 0) {
        kill((pid_t)child_pid, SIGUSR1);
    }

    alarm(3); // after 3 seconds, SIGALRM will arrive
}

static void on_sigusr1(int sig) {
    (void)sig;
    got_usr1 = 1;
}

static void on_sigalrm(int sig) {
    (void)sig;
    W("SIGALRM: timeout reached, exiting now.\n");
    running = 0;
}

int main(void) {
    struct sigaction sa_int = {0}, sa_usr1 = {0}, sa_alrm = {0};

    sa_int.sa_handler = on_sigint;
    sigemptyset(&sa_int.sa_mask);
    sigaction(SIGINT, &sa_int, NULL);

    sa_usr1.sa_handler = on_sigusr1;
    sigemptyset(&sa_usr1.sa_mask);
    sigaction(SIGUSR1, &sa_usr1, NULL);

    sa_alrm.sa_handler = on_sigalrm;
    sigemptyset(&sa_alrm.sa_mask);
    sigaction(SIGALRM, &sa_alrm, NULL);

    pid_t pid = fork();
    if (pid < 0) {
        perror("fork");
        return 1;
    }

    if (pid == 0) {
        // child process
        while (1) {
            pause();
            if (got_usr1) {
                got_usr1 = 0;
                W("Child: got SIGUSR1 from parent.\n");
            }
        }
    }

    // parent process
    child_pid = pid;
    printf("Parent PID=%d, Child PID=%d\n", getpid(), pid);
    printf("Press Ctrl+C to trigger custom SIGINT behavior.\n");

    while (running) {
        pause();
    }

    kill(pid, SIGTERM);
    return 0;
}

Build and run

gcc -Wall -Wextra -O2 signals_demo.c -o signals_demo
./signals_demo

Press Ctrl+C:

  • Parent catches SIGINT
  • Parent sends SIGUSR1 to child
  • Child prints a message
  • After 3s, SIGALRM ends parent

Embedded Linux notes

  • Signals are good for control events, not bulk data.
  • Keep handlers minimal (set flags, write short message).
  • Do real work in main loop, not inside handler.