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}