Lesson 03intermediateProcesses

Introduction to Signals

Basic signal handling using the signal() function. Covers catching SIGINT, ignoring signals with SIG_IGN, setting alarms with SIGALRM, one-shot handlers, and the differences between signal() and sigaction() behavior.

signalSIGINTSIGALRMSIG_IGNhandler
1

Basic Signal Handling

Registering a handler for SIGINT (Ctrl+C) using the signal() function.

01-basic_signals.c44 lines
/*
 * 01-basic_signals.c — Catching SIGINT (Ctrl+C) with signal()
 *
 * Demonstrates: Registering a signal handler with signal()
 * Key concepts: SIGINT, signal handlers, the program keeps running after catching
 * Compile: gcc -o signals 01-basic_signals.c
 * Run:     ./signals   (press Ctrl+C to trigger the handler)
 */

#include <sys/types.h>
#include <signal.h>    // for signal(), SIGINT
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>    // for sleep()

void catch_int(int sig_num);

int main() {
    // Register catch_int as the handler for SIGINT (Ctrl+C)
    // signal() returns SIG_ERR on failure
    signal(SIGINT, catch_int);

    printf("\n");
    printf("========================================\n");
    printf("  Signal Handling — Catching SIGINT\n");
    printf("========================================\n\n");
    printf("[Main PID %d] Running... Press Ctrl+C to trigger the signal handler.\n", getpid());
    printf("  (The handler catches SIGINT but doesn't exit — try pressing Ctrl+C multiple times!)\n");
    printf("  (To actually quit, press Ctrl+\\ which sends SIGQUIT)\n\n");

    int count = 0;
    while (1) {
        printf("[Main PID %d] Still running... (tick %d)\n", getpid(), ++count);
        sleep(2);
    }

    return 0;
}

void catch_int(int sig_num) {
   printf("\n[Signal Handler] Caught signal %d (SIGINT) — Ctrl+C pressed! But I'm not exiting.\n", sig_num);
    //exit(0); 
 
}
Expected Outputclick Run to execute live
[Program timed out after 5 seconds]
2

Ignoring Signals

Using SIG_IGN to make a process immune to specific signals like SIGINT.

02-ignore_signal.c43 lines
/*
 * 02-ignore_signal.c — Ignoring signals with SIG_IGN
 *
 * Demonstrates: Using SIG_IGN to make a process immune to SIGINT
 * Key concepts: SIG_IGN, Ctrl+C won't stop this program (use kill -9 or close terminal)
 * Compile: gcc -o ignore 02-ignore_signal.c
 * Run:     ./ignore   (Ctrl+C will NOT work — use Ctrl+\ for SIGQUIT or kill the process)
 */

#include <sys/types.h>
#include <signal.h>    // for signal(), SIG_IGN, SIGINT
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>    // for sleep()

void catch_int(int sig_num);

int main() {
    // SIG_IGN = "ignore this signal" — Ctrl+C will be silently discarded
    signal(SIGINT, SIG_IGN);

    printf("\n");
    printf("========================================\n");
    printf("  Ignoring Signals with SIG_IGN\n");
    printf("========================================\n\n");
    printf("[PID %d] SIGINT (Ctrl+C) is now IGNORED.\n", getpid());
    printf("  Try pressing Ctrl+C — nothing will happen!\n");
    printf("  To quit: press Ctrl+\\ (sends SIGQUIT, which is NOT ignored)\n\n");

    int count = 0;
    while (1) {
        printf("[PID %d] Still running... (tick %d)\n", getpid(), ++count);
        sleep(2);
    }

    return 0;
}

void catch_int(int sig_num) {
   printf("Caught signal %d\n", sig_num);
    exit(0); 
 
}
Expected Outputclick Run to execute live
[Program timed out after 5 seconds]
3

SIGALRM Countdown Timer

Building a countdown timer using alarm() and SIGALRM — the signal fires after a specified number of seconds.

03-sig_alarm.c43 lines
/*
 * 03-sig_alarm.c — Using alarm() for a countdown timer
 *
 * Demonstrates: SIGALRM delivery after a timed delay
 * Key concepts: alarm(seconds) schedules a SIGALRM, only one alarm active at a time
 * Compile: gcc -o alarm 03-sig_alarm.c
 * Run:     ./alarm   (waits 5 seconds, then prints and exits)
 */

#include <stdio.h>
#include <stdlib.h>    // for exit()
#include <unistd.h>    // for alarm()
#include <signal.h>    // for signal(), SIGALRM

void handle_alarm(int sig);

int main() {
    int countdown = 5;

    // Register the signal handler
    signal(SIGALRM, handle_alarm);

    // Set the alarm for 5 seconds
    printf("\n");
    printf("========================================\n");
    printf("  SIGALRM — Timer Countdown\n");
    printf("========================================\n\n");
    printf("[Main PID %d] Setting alarm(%d) — SIGALRM will fire in %d seconds.\n\n", getpid(), countdown, countdown);
    alarm(countdown);

    printf("  Waiting for the alarm...\n");
    fflush(stdout);
    while (1) {
        sleep(1);
    }

    return 0;
}

void handle_alarm(int sig) {
    printf("\n[Signal Handler] SIGALRM received (signal %d) — time's up! Exiting.\n", sig);
    exit(0); // Exit the program
}
Expected Outputclick Run to execute live
[Program timed out after 5 seconds]
4

One-Shot Handler

A handler that resets itself to SIG_DFL after the first catch, so the second signal terminates the process.

04-sig_init_once.c41 lines
/*
 * 04-sig_init_once.c — One-shot signal handler (catch once, then default)
 *
 * Demonstrates: Restoring default signal behavior with SIG_DFL inside a handler
 * Key concepts: First Ctrl+C is caught, second Ctrl+C kills the process
 * Compile: gcc -o once 04-sig_init_once.c
 * Run:     ./once   (press Ctrl+C twice)
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>    // for getpid(), sleep()
#include <signal.h>    // for signal(), SIGINT, SIG_DFL

void custom_handler(int sig) {
    printf("\n[Handler] Caught signal %d (SIGINT) — first Ctrl+C!\n", sig);
    printf("[Handler] Restoring default behavior with signal(SIGINT, SIG_DFL).\n");
    printf("[Handler] Next Ctrl+C will KILL the process.\n\n");
    signal(SIGINT, SIG_DFL);
}

int main() {
    signal(SIGINT, custom_handler);

    printf("\n");
    printf("========================================\n");
    printf("  One-Shot Signal Handler (SIG_DFL)\n");
    printf("========================================\n\n");
    printf("[Main PID %d] Custom SIGINT handler installed.\n", getpid());
    printf("  1st Ctrl+C → handler catches it, restores default\n");
    printf("  2nd Ctrl+C → default action (terminate process)\n\n");

    int count = 0;
    while (1) {
        printf("[Main PID %d] Running... (tick %d)\n", getpid(), ++count);
        sleep(2);
    }

    return 0;
}
Expected Outputclick Run to execute live
[Program timed out after 5 seconds]
5

Signal Handler Behavior

Exploring what happens when a signal arrives while another handler is already executing.

05-sighandler_behaviour.c46 lines
/*
 * 05-sighandler_behaviour.c — Signal handler behavior during blocking syscalls
 *
 * Key concepts: signal delivery interrupts sleep/scanf, handler re-registration
 * Compile: gcc -o handler 05-sighandler_behaviour.c
 * Run:     ./handler
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>    // for getpid()
#include <signal.h>    // for signal(), SIGINT

void signal_handler(int sig) {
    printf("\n[Handler] Caught signal %d (SIGINT) — Ctrl+C pressed during scanf!\n", sig);
    printf("[Handler] Returning to scanf... (it may fail or resume depending on the OS)\n\n");
}

int main() {
    signal(SIGINT, signal_handler);

    printf("\n");
    printf("========================================\n");
    printf("  signal() Behavior During scanf\n");
    printf("========================================\n\n");
    printf("[Main PID %d] What happens when Ctrl+C arrives while scanf() is blocking?\n\n", getpid());
    printf("  Experiment:\n");
    printf("    1. Don't type anything yet\n");
    printf("    2. Press Ctrl+C to send SIGINT\n");
    printf("    3. Observe: does scanf resume or fail?\n\n");

    int number;
    printf("  Enter a number: ");
    fflush(stdout);

    if (scanf("%d", &number) == 1) {
        printf("\n[Main] scanf succeeded! You entered: %d\n", number);
    } else {
        printf("[Main] scanf returned 0 or EOF — the signal interrupted the read.\n");
        printf("[Main] This is why sigaction() with SA_RESTART is often preferred.\n");
    }
    printf("\n[Main] Program continues normally after scanf.\n");
    printf("\n========================================\n");

    return 0;
}
6

sigaction vs signal

Comparing the behavior of sigaction() to signal() — why sigaction is the preferred, portable choice.

06-sigaction_behaviour.c55 lines
/*
 * 06-sigaction_behaviour.c — sigaction vs signal — comparing behavior during I/O
 *
 * Key concepts: sigaction struct, SA_RESTART flag, reliable signal handling
 * Compile: gcc -o sigact 06-sigaction_behaviour.c
 * Run:     ./sigact
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>    // for getpid()
#include <signal.h>    // for sigaction(), SIGINT

void sigint_handler(int sig) {
    printf("\n[Handler] Caught signal %d (SIGINT) via sigaction!\n", sig);
    printf("[Handler] Unlike signal(), sigaction handlers are NOT reset automatically.\n\n");
}

int main() {
    struct sigaction sa;
    sa.sa_handler = sigint_handler;
    sa.sa_flags = 0;              // No SA_RESTART — scanf will be interrupted
    sigemptyset(&sa.sa_mask);

    if (sigaction(SIGINT, &sa, NULL) == -1) {
        perror("sigaction failed");
        exit(EXIT_FAILURE);
    }

    printf("\n");
    printf("========================================\n");
    printf("  sigaction() Behavior During scanf\n");
    printf("========================================\n\n");
    printf("[Main PID %d] Using sigaction() instead of signal().\n\n", getpid());
    printf("  Key differences from signal():\n");
    printf("    - Handler is NOT reset after first signal\n");
    printf("    - sa_flags controls restart behavior (SA_RESTART)\n");
    printf("    - sa_mask can block other signals during handler\n\n");
    printf("  Try: press Ctrl+C during scanf, then observe what happens.\n\n");

    int number;
    printf("  Enter a number: ");
    fflush(stdout);

    if (scanf("%d", &number) == 1) {
        printf("\n[Main] scanf succeeded! You entered: %d\n", number);
    } else {
        printf("[Main] scanf failed — signal interrupted the blocking read.\n");
        printf("[Main] With sa.sa_flags = SA_RESTART, scanf would have resumed.\n");
    }
    printf("\n[Main] Program continues normally.\n");
    printf("\n========================================\n");

    return 0;
}

Open Full Terminal

Get a Linux terminal with all 6 files from this lesson pre-loaded. Compile, run, and experiment freely.