signal_handler.c

Download
c 130 lines 3.7 KB
  1/**
  2 * Signal Handling Demo
  3 *
  4 * Demonstrates proper signal handling with sigaction:
  5 * - Graceful shutdown on SIGINT/SIGTERM
  6 * - Custom behavior on SIGUSR1/SIGUSR2
  7 * - Child process reaping with SIGCHLD
  8 *
  9 * Build: make
 10 * Usage: ./signal_handler
 11 *   Then send signals: kill -USR1 <pid>, Ctrl+C, etc.
 12 */
 13
 14#include <stdio.h>
 15#include <stdlib.h>
 16#include <signal.h>
 17#include <unistd.h>
 18#include <sys/wait.h>
 19#include <string.h>
 20
 21/* Use volatile sig_atomic_t for signal-safe flags */
 22static volatile sig_atomic_t running = 1;
 23static volatile sig_atomic_t usr1_count = 0;
 24static volatile sig_atomic_t usr2_count = 0;
 25
 26/* SIGINT / SIGTERM handler: graceful shutdown */
 27static void handle_shutdown(int sig) {
 28    const char *name = (sig == SIGINT) ? "SIGINT" : "SIGTERM";
 29    /* write() is async-signal-safe; printf is NOT */
 30    write(STDOUT_FILENO, "\nReceived ", 10);
 31    write(STDOUT_FILENO, name, strlen(name));
 32    write(STDOUT_FILENO, ", shutting down...\n", 18);
 33    running = 0;
 34}
 35
 36/* SIGUSR1 handler */
 37static void handle_usr1(int sig) {
 38    (void)sig;
 39    usr1_count++;
 40}
 41
 42/* SIGUSR2 handler with siginfo */
 43static void handle_usr2(int sig, siginfo_t *info, void *context) {
 44    (void)sig;
 45    (void)context;
 46    usr2_count++;
 47    /* We can safely use write() here */
 48    char buf[128];
 49    int n = snprintf(buf, sizeof(buf),
 50                     "SIGUSR2 from PID %d (uid=%d)\n",
 51                     info->si_pid, info->si_uid);
 52    write(STDOUT_FILENO, buf, n);
 53}
 54
 55/* SIGCHLD handler: reap children */
 56static void handle_sigchld(int sig) {
 57    (void)sig;
 58    int status;
 59    pid_t pid;
 60    while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
 61        char buf[64];
 62        int n = snprintf(buf, sizeof(buf),
 63                         "Child %d exited (status=%d)\n",
 64                         pid, WEXITSTATUS(status));
 65        write(STDOUT_FILENO, buf, n);
 66    }
 67}
 68
 69/* Install a signal handler */
 70static void install_handler(int sig, void (*handler)(int), int flags) {
 71    struct sigaction sa;
 72    memset(&sa, 0, sizeof(sa));
 73    sa.sa_handler = handler;
 74    sigemptyset(&sa.sa_mask);
 75    sa.sa_flags = flags;
 76    if (sigaction(sig, &sa, NULL) < 0) {
 77        perror("sigaction");
 78        exit(EXIT_FAILURE);
 79    }
 80}
 81
 82int main(void) {
 83    printf("Signal Handler Demo\n");
 84    printf("PID: %d\n\n", getpid());
 85    printf("Available signals:\n");
 86    printf("  Ctrl+C     → SIGINT  (graceful shutdown)\n");
 87    printf("  kill -USR1 → SIGUSR1 (counter increment)\n");
 88    printf("  kill -USR2 → SIGUSR2 (with sender info)\n");
 89    printf("  kill -TERM → SIGTERM (graceful shutdown)\n\n");
 90
 91    /* Install handlers */
 92    install_handler(SIGINT,  handle_shutdown, 0);
 93    install_handler(SIGTERM, handle_shutdown, 0);
 94    install_handler(SIGUSR1, handle_usr1, SA_RESTART);
 95    install_handler(SIGCHLD, handle_sigchld, SA_RESTART | SA_NOCLDSTOP);
 96
 97    /* SIGUSR2 with SA_SIGINFO for sender information */
 98    struct sigaction sa_usr2;
 99    memset(&sa_usr2, 0, sizeof(sa_usr2));
100    sa_usr2.sa_sigaction = handle_usr2;
101    sigemptyset(&sa_usr2.sa_mask);
102    sa_usr2.sa_flags = SA_SIGINFO | SA_RESTART;
103    sigaction(SIGUSR2, &sa_usr2, NULL);
104
105    /* Ignore SIGPIPE */
106    signal(SIGPIPE, SIG_IGN);
107
108    /* Fork a child to demonstrate SIGCHLD */
109    pid_t child = fork();
110    if (child == 0) {
111        printf("[Child %d] Running for 3 seconds...\n", getpid());
112        sleep(3);
113        printf("[Child %d] Exiting\n", getpid());
114        exit(42);
115    }
116    printf("Forked child PID=%d\n\n", child);
117
118    /* Main loop */
119    int iteration = 0;
120    while (running) {
121        printf("Tick %d (USR1=%d, USR2=%d)\n",
122               ++iteration, (int)usr1_count, (int)usr2_count);
123        sleep(2);
124    }
125
126    printf("\nClean shutdown. Final counts: USR1=%d, USR2=%d\n",
127           (int)usr1_count, (int)usr2_count);
128    return 0;
129}