Created
February 14, 2014 14:32
-
-
Save doi-t/9001945 to your computer and use it in GitHub Desktop.
sigaction(2)のラッパー関数Signal
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Linuxカーネルのバージョンは2.6以上が前提 | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <signal.h> | |
#include <errno.h> | |
#include <stdarg.h> | |
#include <time.h> | |
#include <sys/types.h> | |
#include <unistd.h> | |
void err_msg(const char *, const char *, int, const char *, const char *, ...); | |
#define Sigaction(s,a,o) e_Sigaction((s),(a),(o), __FILE__, __FUNCTION__, __LINE__) | |
int e_Sigaction(int, const struct sigaction *, struct sigaction *, const char *, const char *, int); | |
typedef void Sigfunc(int); //何も返さない(void)関数を表す型として、Sigfuc型を定義 | |
Sigfunc *Signal(int , Sigfunc *); | |
void | |
sigint_handler(int signum) | |
{ | |
write(1, "Ctrl-C\n", strlen("Ctrl-C\n")); | |
exit(0); | |
} | |
int | |
main(int argc, char **argv) | |
{ | |
Signal(SIGINT, sigint_handler); | |
//Signal(SIGINT, SIG_DFL); //指定したシグナルをOSのデフォルトの動作に戻す | |
//Signal(SIGINT, SIG_IGN); //指定したシグナルを無視する | |
Signal(SIGCHLD, NULL); | |
printf("Signal:%p\n", Signal); | |
while(1){} //無限ループ | |
return 0; | |
} | |
/* | |
Sigfunc型を定義しておくことによって、Signalの定義が簡素化する. | |
Sigfuncを定義しない場合は関数プロトタイプが、 | |
void (*signal(int signo, void (*func) (int))) (int); | |
となる. | |
*/ | |
Sigfunc * | |
Signal(int signo, Sigfunc *func) | |
{ | |
struct sigaction act, oact; /* act:新しく定義する動作,oact:今までの動作 */ | |
act.sa_handler = func; | |
sigemptyset(&act.sa_mask); | |
act.sa_flags = 0; | |
if(signo == SIGALRM){ | |
act.sa_flags |= SA_INTERRUPT; //例えばalarm(2)でI/Oのタイムアウトの管理をしたい場合は、実行中のシステムコールを中断する | |
} else { | |
act.sa_flags |= SA_RESTART; //シグナルに割り込まれたシステムコールを再起動する | |
} | |
if(signo == SIGCHLD){ | |
act.sa_handler = SIG_IGN; /*シグナルを無視*/ | |
act.sa_flags |= SA_NOCLDWAIT; /*子プロセスをゾンビプロセスにしない(Linux2.6以降での機能)*/ | |
} | |
Sigaction(signo, &act, &oact); //独自に定義したラッパー関数e_Sigactionを呼び出す、sigaction(2)が失敗するとexitする | |
//if(sigaction(signo, &act, &oact) < 0) retrun NULL; //エラーの扱いに関する責任が呼び出し元にある場合は例えばNULLを返す | |
return (oact.sa_handler); /*以前のシグナルの設定を戻り値として返す*/ | |
} | |
/* | |
SIGCHLDの注意点 | |
SIGCHLDはデフォルトでシグナルを無視するのだが, | |
ハンドラの設定が,SIG_DFLの場合だとゾンビプロセスが残ってしまう. | |
ハンドラの設定が,SIG_IGNの場合だとゾンビプロセスが残らない. | |
同じ無視でも明示的に無視しないとゾンビプロセスが生成される. | |
*/ | |
int | |
e_Sigaction(int signum, const struct sigaction *act, struct sigaction *oldact, | |
const char *file, const char *function, int line) | |
{ | |
int n; | |
if((n = sigaction(signum, act, oldact)) < 0){ | |
err_msg(file, function, line, "error","[%d]=sigaction(%d,%p,%p):%s", n, signum, act, oldact, strerror(errno)); | |
exit(1); | |
} | |
return n; | |
} | |
void | |
err_msg(const char *file, const char *function, int line, const char *type, const char *fmt, ...) | |
{ | |
time_t timer; | |
time(&timer); | |
char *t = ctime(&timer); | |
t[strlen(t)-1] = '\0'; | |
fprintf(stderr, "%s ", t); /* 現在時刻を表示 */ | |
fprintf(stderr, "%d ", getpid()); /* プロセスIDを出力 */ | |
fprintf(stderr, "%s %s %d %s ", file, function, line, type); | |
va_list ap; | |
va_start(ap, fmt); | |
vfprintf(stderr, fmt, ap); /* fmtの書式に従って可変個数引数を順次呼び出す */ | |
va_end(ap); | |
fprintf(stderr, " %s(%d)", strerror(errno), errno); /* エラーメッセージを出力 */ | |
fputc('\n', stderr); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment