/bin/kill
, /usr/bin/killall
, Ctrl + C
, Ctrl + z
, kill
, alarm
등 다양한 방법이 있음.
따라서 기본적으로 signal은 asynchronous하다.
Signal은 queue되지 않는다!(중첩은 된다.)
if (pending_signal & ~blocked_signal)
로 검사한다.inside singal handler ...
while(pending & ~blocked) {
int n = get_least_sig_num(pending & ~blocked); // get signal number(least signal)
do_signal_action(n); // handle signal
pending = pending & ~(1 >> n); // clear nth-bit signal
}
return to process
blocked_signal
의 역할이 이렇게 block된 signal을 걸러내는 것이다.sighandler_t signal(int signum, sighandler_t handler);
#include <stdio.h>
#include <signal.h>
int beeps = 0;
/* SIGALRM handler */
void handler(int sig)
{
printf("BEEP\n");
fflush(stdout);
if (++beeps < 5) {
alarm(1);
}
else {
printf("BOOM!\n");
exit(0);
}
}
main()
{
signal(SIGALRM, handler);
/* send SIGALRM in 1 second */
alarm(1);
while (1) {
/* handler returns here */
}
}
프로그래머 입장에서, Nested Signal Handlers는 조심히 다루어야한다
/bin/kill -[SIGNUM] -[PID]
Ctrl + C
와 Ctrl + Z
#include <signal.h>
int kill(pid_t pid, int sig);
pid
sig
return value < 0,indicate error occur
int main(int argc, char *argv[])
{
pid_t pid[N];
int i, child_status;
/* child process를 N개 생성합니다. */
for (i = 0; i < N; i++) {
if ((pid[i] = fork()) == 0) { // child sleep for certain amount of time
sleep(i/2);
return 100 + i;
}
else {
printf("Created process %d\n", pid[i]);
}
}
for (i = 0; i < N; i++) { // parent: send SIGINT to half of children
printf("Killing proecess %d\n", pid[i]);
kill(pid[i], SIGINT);
}
for (i = 0; i < N; i++) { // parent: wait for children to terminate;
pid_t wpid = wait(&child_status);
if (WIFEXITED(child_status)) {
printf("Child %d terminated with exit status %d\n", wpid, WEXITSTATUS(child_status));
}
else {
printf("Child %d terminated abnormally\n", wpid);
}
}
}
sigaction()
#include <signal.h>
struct sigaction {
void (*sa_handler)(int); // handler functionn
sigset_t sa_mask;
int sa_flags;
}
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
sigaction()
argument
struct sigaction
signal()
#include <signal.h>
typedef void (*sighandler_t)(int);
int signal(int signum, sighandler_t handler);
sigaction()
argumentvoid handler(int sig) {
static int level = 0;
level++;
printf("[nesting level %d] Hohoo, got signal %d\n", level, sig);
sleep(3);
level--;
}
void alarm_hdl(int sig) {
printf("Wake up!\n");
alarm(5);
}
int main(int argc, char *argv[]) {
struct sigaction action;
action.sa_handler = handler;
sigemptyset(&action.sa_mask); // allow nested signals
action.sa_flags = SA_RESTART | SA_NODEFER; // restart syscalls if possible
if (sigaction(SIGINT, &action, NULL) < 0) {
perror("Cannot install signal handler"); return EXIT_FAILURE; // SIGINT 등록
}
if (signal(SIGALRM, alarm_hdl) == SIG_ERR) {
perror("Cannot install signal handler"); return EXIT_FAILURE; // SIGALRM 등록
}
alarm(5);
while (pause() == -1); // wait until receive signal...
return EXIT_SUCCESS;
}
void int_hdl(int sig) { printf("Received SIGINT\n"); }
void alarm_hdl(int sig) {
sigset_t set;
char sigset[32];
if (sigpending(&set) >= 0) {
for (int i=1; i<32; i++) sigset[i] = (sigismember(&set, i)) > 0 ? 'P' : '.'; // count which signal is pended now
sigset[0] = ' '; sigset[31] = '\0';
printf("Pending signals: %s\n", sigset);
}
alarm(1);
}
int main(int argc, char *argv[]) {
sigset_t set; // blocking signal set variable
sigemptyset(&set); // make empty set
sigaddset(&set, SIGINT); // add signal to set
if (signal(SIGALRM, alarm_hdl) == SIG_ERR) { perror("Cannot install signal handler"); return EXIT_FAILURE; }
if (signal(SIGINT, int_hdl) == SIG_ERR) { perror("Cannot install signal handler"); return EXIT_FAILURE; }
alarm(1);
struct timespec delay = { .tv_sec = 5, .tv_nsec = 0 };
while ((nanosleep(&delay, &delay) < 0) && (errno == EINTR));
if (sigprocmask(SIG_BLOCK, &set, NULL) == 0) printf("SIGINT is now blocked.\n");
delay.tv_sec = 5; delay.tv_nsec = 0;
while ((nanosleep(&delay, &delay) < 0) && (errno == EINTR));
if (sigprocmask(SIG_UNBLOCK, &set, NULL) == 0) printf("SIGINT is now unblocked.\n");
delay.tv_sec = 5; delay.tv_nsec = 0;
while ((nanosleep(&delay, &delay) < 0) && (errno == EINTR));
return EXIT_SUCCESS;
}
#define N 16
volatile int counter = 0;
void handler(int sig) { // signal handler
int child_status;
pid_t wpid = wait(&child_status);
if (WIFEXITED(child_status))
printf("Child %d terminated with exit status %d\n", wpid, WEXITSTATUS(child_status));
else
printf("Child %d terminated abnormally\n", wpid);
counter++;
}
int main(int argc, char *argv[]) {
pid_t pid[N];
if (signal(SIGCHLD, handler) == SIG_ERR) return EXIT_FAILURE; // register signal handler to SIGCHLD(send signal to parent process when child process terminated or stopped)
printf("Creating %d children...\n", N);
for (int i = 0; i < N; i++) {
if ((pid[i] = fork()) == 0) { // child: sleep for some amount of time
sleep(i/2);
return 100+i;
}
}
for (int i = 0; i < N; i+=2) { // parent: send SIGINT to half of children
printf("Killing process %d\n", pid[i]);
kill(pid[i], SIGINT);
}
printf("Waiting until all %d children have terminated...\n", N); // parent: wait for termination
while (counter < N) {
sleep(1); // sleep is syscall... so, return from sleep, process will handle(not all, but most case signal handled in here)
printf("--> %d / %d terminated.\n", counter, N);
}
return EXIT_SUCCESS;
}
(wpid = waitpid(-1, &child_status, WNOHANG)
void handler(int sig) { // signal handler
int child_status;
pid_t wpid;
while ((wpid = waitpid(-1, &child_status, WNOHANG)) > 0) { // solution
if (WIFEXITED(child_status))
printf("Child %d terminated with exit status %d\n", wpid, WEXITSTATUS(child_status));
else
printf("Child %d terminated abnormally\n", wpid);
counter++;
}
}
struct sigaction action;
action.sa_handler = handler;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
if (sigaction(SIGINT, &action, NULL) < 0) { perror("Cannot install signal handler"); return EXIT_FAILURE; }
//
// Read shell command
//
char prompt[] = "> ";
char cmdline[1024];
int res;
write(STDOUT_FILENO, prompt, strlen(prompt));
res = read(STDIN_FILENO, cmdline, sizeof(cmdline)); //만일 read 실행중 interrupt가 발생하면?
if (res >= 0) {
cmdline[res] = '\0';
printf("Executing command: %s", cmdline);
} else {
perror("Error reading command");
}
…
while ((res = read(STDIN_FILENO, cmdline, sizeof(cmdline))) < 0) {
if (errno != EINTR) break;
}
action.sa_flags = SA_RESTART;
Handler는 간단하게!
Handler 실행중에도 scheduling 될 수 있음을 명심하자(Async-signal-safe)
errno를 저장하고 복구하자
전역 변수는 volatile
로 선언 하자
Shared resource에 접근하고자 한다면 모든 signal을 막아서 data corruption을 막아야 한다.
volatile sig_atomic_t
을 사용하자.
flag = 1
, if (flag == 0)
flag += 1
or flag++
은 atomic하지 않다!