close
https://gist.github.com/aspyct/3462238
Unix signal handling example in C, SIGINT, SIGALRM, SIGHUP...
/** | |
* More info? | |
* a.dotreppe@aspyct.org | |
* http://aspyct.org | |
* @aspyct (twitter) | |
* | |
* Hope it helps :) | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <signal.h> // sigaction(), sigsuspend(), sig*() | |
#include <unistd.h> // alarm() | |
void handle_signal(int signal); | |
void handle_sigalrm(int signal); | |
void do_sleep(int seconds); | |
/* Usage example | |
* | |
* First, compile and run this program: | |
* $ gcc signal.c | |
* $ ./a.out | |
* | |
* It will print out its pid. Use it from another terminal to send signals | |
* $ kill -HUP <pid> | |
* $ kill -USR1 <pid> | |
* $ kill -ALRM <pid> | |
* | |
* Exit the process with ^C ( = SIGINT) or SIGKILL, SIGTERM | |
*/ | |
int main() { | |
struct sigaction sa; | |
// Print pid, so that we can send signals from other shells | |
printf("My pid is: %d\n", getpid()); | |
// Setup the sighub handler | |
sa.sa_handler = &handle_signal; | |
// Restart the system call, if at all possible | |
sa.sa_flags = SA_RESTART; | |
// Block every signal during the handler | |
sigfillset(&sa.sa_mask); | |
// Intercept SIGHUP and SIGINT | |
if (sigaction(SIGHUP, &sa, NULL) == -1) { | |
perror("Error: cannot handle SIGHUP"); // Should not happen | |
} | |
if (sigaction(SIGUSR1, &sa, NULL) == -1) { | |
perror("Error: cannot handle SIGUSR1"); // Should not happen | |
} | |
// Will always fail, SIGKILL is intended to force kill your process | |
if (sigaction(SIGKILL, &sa, NULL) == -1) { | |
perror("Cannot handle SIGKILL"); // Will always happen | |
printf("You can never handle SIGKILL anyway...\n"); | |
} | |
if (sigaction(SIGINT, &sa, NULL) == -1) { | |
perror("Error: cannot handle SIGINT"); // Should not happen | |
} | |
for (;;) { | |
printf("\nSleeping for ~3 seconds\n"); | |
do_sleep(3); // Later to be replaced with a SIGALRM | |
} | |
} | |
void handle_signal(int signal) { | |
const char *signal_name; | |
sigset_t pending; | |
// Find out which signal we're handling | |
switch (signal) { | |
case SIGHUP: | |
signal_name = "SIGHUP"; | |
break; | |
case SIGUSR1: | |
signal_name = "SIGUSR1"; | |
break; | |
case SIGINT: | |
printf("Caught SIGINT, exiting now\n"); | |
exit(0); | |
default: | |
fprintf(stderr, "Caught wrong signal: %d\n", signal); | |
return; | |
} | |
/* | |
* Please note that printf et al. are NOT safe to use in signal handlers. | |
* Look for async safe functions. | |
*/ | |
printf("Caught %s, sleeping for ~3 seconds\n" | |
"Try sending another SIGHUP / SIGINT / SIGALRM " | |
"(or more) meanwhile\n", signal_name); | |
/* | |
* Indeed, all signals are blocked during this handler | |
* But, at least on OSX, if you send 2 other SIGHUP, | |
* only one will be delivered: signals are not queued | |
* However, if you send HUP, INT, HUP, | |
* you'll see that both INT and HUP are queued | |
* Even more, on my system, HUP has priority over INT | |
*/ | |
do_sleep(3); | |
printf("Done sleeping for %s\n", signal_name); | |
// So what did you send me while I was asleep? | |
sigpending(&pending); | |
if (sigismember(&pending, SIGHUP)) { | |
printf("A SIGHUP is waiting\n"); | |
} | |
if (sigismember(&pending, SIGUSR1)) { | |
printf("A SIGUSR1 is waiting\n"); | |
} | |
printf("Done handling %s\n\n", signal_name); | |
} | |
void handle_sigalrm(int signal) { | |
if (signal != SIGALRM) { | |
fprintf(stderr, "Caught wrong signal: %d\n", signal); | |
} | |
printf("Got sigalrm, do_sleep() will end\n"); | |
} | |
void do_sleep(int seconds) { | |
struct sigaction sa; | |
sigset_t mask; | |
sa.sa_handler = &handle_sigalrm; // Intercept and ignore SIGALRM | |
sa.sa_flags = SA_RESETHAND; // Remove the handler after first signal | |
sigfillset(&sa.sa_mask); | |
sigaction(SIGALRM, &sa, NULL); | |
// Get the current signal mask | |
sigprocmask(0, NULL, &mask); | |
// Unblock SIGALRM | |
sigdelset(&mask, SIGALRM); | |
// Wait with this mask | |
alarm(seconds); | |
sigsuspend(&mask); | |
printf("sigsuspend() returned\n"); | |
} |
全站熱搜