Lesson 06intermediateProcesses

Advanced Signals with sigaction

Deep dive into sigaction() — the robust, portable replacement for signal(). Covers the sigaction struct anatomy, sa_mask for blocking signals during handling, SA_RESTART and SA_RESETHAND flags, and SA_SIGINFO for accessing detailed signal metadata.

sigactionsa_maskSA_SIGINFOSA_RESTARTsignal-blocking
1

sigaction Struct Reference

A thorough 124-line reference documenting every field and flag of the sigaction struct with inline explanations.

01-basic-info.c132 lines
2

Basic sigaction Usage

Setting up a signal handler using sigaction instead of signal — the minimal working example.

02-usage.c53 lines
/*
 * 02-usage.c — Basic sigaction usage — registering a handler
 *
 * Key concepts: sigaction(), sigemptyset(), signal registration
 * Compile: gcc -o usage 02-usage.c
 * Run:     ./prog
 */
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

// Handler function for SIGINT
void sigint_handler(int signum) {
    printf("\n[Handler] Caught signal %d (SIGINT). Exiting gracefully.\n", signum);
    exit(0);
}

int main() {
    printf("\n");
    printf("══════════════════════════════════════\n");
    printf("  Basic sigaction() Usage\n");
    printf("  Register a custom handler for SIGINT\n");
    printf("══════════════════════════════════════\n\n");
    struct sigaction sa;

    // Set up the sigaction struct
    sa.sa_handler = sigint_handler;    // Assign handler function
    sa.sa_flags = 0;                    // No special flags
    sigemptyset(&sa.sa_mask);           // Don't block any signals during handler

    // Set up the handler for SIGINT
    if (sigaction(SIGINT, &sa, NULL) == -1) {
        perror("Error: sigaction failed");
        exit(EXIT_FAILURE);
    }

    printf("[Setup] sigaction() registered handler for SIGINT\n");
    printf("[Setup] sa_handler = sigint_handler, sa_flags = 0\n");
    printf("[Setup] sa_mask = empty (no signals blocked during handler)\n");
    printf("[Info]  Process PID: %d\n\n", getpid());
    printf("Press Ctrl+C to trigger SIGINT...\n\n");

    // Infinite loop to keep the program running
    int tick = 0;
    while (1) {
        printf("  [Tick %d] Running... (Ctrl+C to exit)\n", ++tick);
        sleep(2);
    }

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

Multi-Signal Handling

Registering different handlers for multiple signals (SIGINT, SIGTERM, SIGUSR1) in a single program.

03-multi-signals.c81 lines
Expected Outputclick Run to execute live
[Program timed out after 5 seconds]
4

Signal Blocking with sa_mask

Using sa_mask to block specific signals while a handler is executing, preventing re-entrant handler chaos.

04-using-sa-mask.c83 lines
Expected Outputclick Run to execute live
[Program timed out after 5 seconds]
5

SA_RESTART and SA_RESETHAND

SA_RESTART automatically restarts interrupted syscalls; SA_RESETHAND makes a handler fire only once.

05-some-flags.c66 lines
/*
 * 05-some-flags.c — sigaction flags — SA_RESTART, SA_RESETHAND
 *
 * Key concepts: SA_RESTART (auto-retry interrupted syscalls), SA_RESETHAND (one-shot)
 * Compile: gcc -o flags 05-some-flags.c
 * Run:     ./prog
 */
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>


// here we show example of two flags
// SA_RESTART and SA_RESETHAND
// SA_RESTART is used to restart the system call if it was interrupted by the signal (sleep in this case)
// SA_RESETHAND is used to reset the handler to default after the first signal

// here we want to use :
// kill -SIGUSR1 <pid>
// than again
// kill -SIGUSR1 <pid>

// Handler for SIGUSR1
void handle_sigusr1(int signum) {
    printf("\n[Handler] Caught SIGUSR1 (signal %d).\n", signum);
    printf("[Handler] SA_RESETHAND: this handler is NOW reset to default (SIG_DFL).\n");
    printf("[Handler] SA_RESTART:   the sleep() that was interrupted will auto-restart.\n");
    printf("[Handler] Next SIGUSR1 will TERMINATE the process (default action).\n\n");
}

int main() {
    printf("\n");
    printf("══════════════════════════════════════\n");
    printf("  sigaction Flags Demo\n");
    printf("  SA_RESTART | SA_RESETHAND\n");
    printf("══════════════════════════════════════\n\n");
    struct sigaction sa;

    // Setup handler for SIGUSR1 with SA_RESTART and SA_RESETHAND flags
    sa.sa_handler = handle_sigusr1;
    sa.sa_flags = SA_RESTART | SA_RESETHAND; // Restart interrupted syscalls and reset handler
    sigemptyset(&sa.sa_mask);                  // No additional signals blocked

    if (sigaction(SIGUSR1, &sa, NULL) == -1) {
        perror("Error: sigaction for SIGUSR1 failed");
        exit(EXIT_FAILURE);
    }

    printf("[Setup] sa_flags = SA_RESTART | SA_RESETHAND\n");
    printf("[Setup]   SA_RESTART  — interrupted sleep() auto-restarts\n");
    printf("[Setup]   SA_RESETHAND — handler reverts to SIG_DFL after first catch\n\n");
    printf("[Info]  Process PID: %d\n", getpid());
    printf("[Test]  1st: kill -SIGUSR1 %d  → handler runs, then resets\n", getpid());
    printf("[Test]  2nd: kill -SIGUSR1 %d  → default action (terminate!)\n\n", getpid());

    // Infinite loop to keep the program running and handling signals
    int tick = 0;
    while (1) {
        printf("  [Tick %d] Waiting for SIGUSR1... (PID %d)\n", ++tick, getpid());
        sleep(4);
    }

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

SA_SIGINFO — Detailed Signal Info

Using SA_SIGINFO to receive a siginfo_t struct with the sender PID, signal code, and other metadata.

06-sig-info.c68 lines
/*
 * 06-sig-info.c — SA_SIGINFO — getting detailed signal information
 *
 * Key concepts: SA_SIGINFO, siginfo_t, si_pid, si_uid, si_signo
 * Compile: gcc -o siginfo 06-sig-info.c
 * Run:     ./prog
 */
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

// Enhanced handler for SIGUSR1 using SA_SIGINFO

// YOU DONT NEED TO USE SA_SIGINFO in the course/assigments
// it can be helpful in some cases, but its not mandatory!!
// (also the sets are not mandatory, but whatever)

//to use this program we need to send the signal with the kill command
// kill -SIGUSR1 <pid>

void handle_sigusr1(int signum, siginfo_t *info, void *context) {
    printf("\n  ── Signal Received ──────────────────\n");
    printf("  Signal:       %d (SIGUSR1)\n", signum);
    printf("  Sender PID:   %d\n", info->si_pid);
    printf("  Sender UID:   %d\n", info->si_uid);
    printf("  Signal code:  %d\n", info->si_code);
    printf("  Value (int):  %d\n", info->si_value.sival_int);
    printf("  Errno:        %d\n", info->si_errno);
    printf("  Address:      %p\n", info->si_addr);
    printf("  User time:    %ld\n", info->si_utime);
    printf("  System time:  %ld\n", info->si_stime);
    printf("  ────────────────────────────────────\n\n");
}

int main() {
    printf("\n");
    printf("══════════════════════════════════════\n");
    printf("  SA_SIGINFO — Detailed Signal Info\n");
    printf("  Access siginfo_t fields in handler\n");
    printf("══════════════════════════════════════\n\n");
    struct sigaction sa;

    // Setup handler for SIGUSR1 with SA_SIGINFO flag
    sa.sa_sigaction = handle_sigusr1;
    sa.sa_flags = SA_SIGINFO; // Enable extended signal information
    sigemptyset(&sa.sa_mask); // No additional signals blocked

    if (sigaction(SIGUSR1, &sa, NULL) == -1) {
        perror("Error: sigaction for SIGUSR1 failed");
        exit(EXIT_FAILURE);
    }

    printf("[Setup] Using SA_SIGINFO flag — handler gets siginfo_t struct\n");
    printf("[Setup] siginfo_t provides: sender PID, UID, signal code, etc.\n\n");
    printf("[Info]  Process PID: %d\n", getpid());
    printf("[Test]  Run: kill -SIGUSR1 %d\n\n", getpid());

    // Infinite loop to keep the program running
    int tick = 0;
    while (1) {
        printf("  [Tick %d] Waiting for SIGUSR1...\n", ++tick);
        sleep(3);
    }

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

Practical Alarm Example

Combining sigaction with alarm() for a practical timed-operation pattern, preparing for exercise 2.

07-before-ex2.c71 lines
/*
 * 07-before-ex2.c — Practical alarm example — preparation for exercise 2
 *
 * Key concepts: alarm(), sigaction, practical signal usage
 * Compile: gcc -o ex2 07-before-ex2.c
 * Run:     ./prog
 */
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>


int global_flag = 1;

void handle_sigalrm(int signum) {
    printf("\n[ALARM] Time's up! Caught SIGALRM (signal %d).\n", signum);
    global_flag = 0;
}

int main() {
    printf("\n");
    printf("══════════════════════════════════════\n");
    printf("  Timed Input with alarm() + sigaction\n");
    printf("  Enter numbers before the timer runs out!\n");
    printf("══════════════════════════════════════\n\n");
    const int seconds = 5;
    struct sigaction sa;

    sa.sa_handler = handle_sigalrm;
    sa.sa_flags = 0;
    sigemptyset(&sa.sa_mask);

    if (sigaction(SIGALRM, &sa, NULL) == -1) {
        perror("Error: sigaction for SIGALRM failed");
        exit(EXIT_FAILURE);
    }

    printf("[Setup] SIGALRM handler registered.\n");
    printf("[Setup] alarm(%d) gives you %d seconds per round.\n\n", seconds, seconds);

    int best = 0;
    for (int i = 0; i < 10; i++) {
        global_flag = 1;
        int counter = 0;
        printf("── Round %d/10 ──────────────────────\n", i + 1);
        while(global_flag)
        {
            alarm(seconds);
            printf("  Enter a number (%ds timer): ", seconds);
            fflush(stdout);
            int number;
            if (scanf("%d", &number) == 1) {
                printf("  Got: %d (entry #%d)\n", number, counter + 1);
            }
            counter++;
        }
        printf("[Round %d] You entered %d numbers before timeout.\n\n", i + 1, counter);
        if(counter > best)
        {
            best = counter;
        }
    }

    printf("══════════════════════════════════════\n");
    printf("  Best round: %d entries before timeout\n", best);
    printf("══════════════════════════════════════\n");

    return 0;
}

Open Full Terminal

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