C言語でprefork型のデーモンを書く(2): 非デーモン prefork シグナルハンドラ付き
1つの親プロセスとたくさんの子プロセスという構成。親プロセスに SIGTERM を送ると、すべての子プロセスをきれいに終了させた後で終了するようにシグナルハンドラを追加したサンプル。
- my_prefork_signal.c
シグナルハンドラ付きのソース
#include <stdio.h> #include <string.h> #include <apr_hash.h> #include <sys/types.h> #include <unistd.h> #include <sys/wait.h> #include <signal.h> #define MAX_CHILDREN 16 //子プロセスの数 void kill_all_children(int); void signal_handler(int); // 子プロセスの管理にハッシュテーブルを使う static apr_pool_t* pool; static apr_hash_t* hChildren; int main(void){ // SIGTERM ですべての子プロセスを殺すようにシグナルハンドラを設定 signal(SIGTERM, kill_all_children); // ハッシュの初期化 apr_initialize(); apr_pool_create(&pool, NULL); hChildren = apr_hash_make(pool); //親プロセスのループ while(1){ while( apr_hash_count(hChildren) >= MAX_CHILDREN ){ int status; pid_t child_pid = wait( &status ); //子プロセスが死ぬまで待つ apr_hash_set(hChildren, &child_pid, sizeof(child_pid), NULL); //死んだ子プロセスをハッシュテーブルから削除 } pid_t *pid = apr_palloc(pool, sizeof(pid_t)); *pid = fork(); //フォーク if(*pid==0){ signal(SIGTERM, signal_handler); goto CHILDREN; //子プロセスだったら、ループから抜ける } apr_hash_set(hChildren, pid, sizeof(pid_t), 1); //子プロセスをハッシュテーブルに追加 usleep(100); } CHILDREN: while(1){ //子プロセスの処理をここに書く sleep(1); } } void kill_all_children(int sig){ apr_hash_index_t *hi; apr_ssize_t klen; pid_t *child_pid_ptr; int val; for( hi=apr_hash_first(pool, hChildren); hi; hi=apr_hash_next(hi) ){ apr_hash_this(hi, &child_pid_ptr, &klen, &val); int ret = kill(*child_pid_ptr, SIGTERM); } exit(0); } void signal_handler(int sig){ exit(0); }
細かいところはいい加減なので、警告がやたらでるので本番で使うときは -Wall を付けて警告がなくなるまで要修正。
# gcc -g -I /usr/include/apr-1 -L/usr/lib/apr-1 -lapr-1 my_prefork_signal.c -o my_prefork_signal
- 実行
$ ./my_prefork_signal & [1] 8502 $ ps -ef|grep my_prefork_signal 503 8502 4614 0 23:32 pts/3 00:00:00 ./my_prefork_signal 503 8503 8502 0 23:32 pts/3 00:00:00 ./my_prefork_signal 503 8504 8502 0 23:32 pts/3 00:00:00 ./my_prefork_signal 503 8505 8502 0 23:32 pts/3 00:00:00 ./my_prefork_signal 503 8506 8502 0 23:32 pts/3 00:00:00 ./my_prefork_signal 503 8507 8502 0 23:32 pts/3 00:00:00 ./my_prefork_signal 503 8508 8502 0 23:32 pts/3 00:00:00 ./my_prefork_signal 503 8509 8502 0 23:32 pts/3 00:00:00 ./my_prefork_signal 503 8510 8502 0 23:32 pts/3 00:00:00 ./my_prefork_signal 503 8511 8502 0 23:32 pts/3 00:00:00 ./my_prefork_signal 503 8512 8502 0 23:32 pts/3 00:00:00 ./my_prefork_signal 503 8513 8502 0 23:32 pts/3 00:00:00 ./my_prefork_signal 503 8514 8502 0 23:32 pts/3 00:00:00 ./my_prefork_signal 503 8515 8502 0 23:32 pts/3 00:00:00 ./my_prefork_signal 503 8516 8502 0 23:32 pts/3 00:00:00 ./my_prefork_signal 503 8517 8502 0 23:32 pts/3 00:00:00 ./my_prefork_signal 503 8518 8502 0 23:32 pts/3 00:00:00 ./my_prefork_signal 503 8521 4614 0 23:33 pts/3 00:00:00 grep my_prefork_signal
- プロセスの終了方法
親プロセスに対してシグナルを送信すれば終了できる。
シグナルの送信方法は、
親プロセスのプロセスIDを調べる # ps -ef そのプロセスIDにSIGTERMを送る。 # kill 8502
参考
C言語でprefork型のデーモンを書く(1): 非デーモン prefork サンプル - Sleepless geek in Seattle