SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

signalについて

signalについて(中篇)

シグナルの実装


4. シグナルの実装(アボート、待機)

4.9 アボート

 アボート(abort(3))はその名の通り、中止や中断といった意味です。この関数はSIGABRTシグナルを送信しています。

 SIGABRTシグナルは捕捉可能で、無視する事も可能です。しかし無視してもちゃんとプロセスは終了します。

 abort(3)は、プロセス側でSIGABRTを無視設定していても、それらを解除しています。また、プロセス側がハンドラで捕捉している場合、ハンドラが叩かれた後でプロセスが終了するようにしています。

 内部では、無視設定されている場合は初期動作に戻します。

 また、ハンドラ設定されている場合を想定し、自プロセスに2回送信する事で確実に終了させています。ライブラリ内でシグナルを捕捉する関数を用意する場合、参考になると思います。

signal_test_abort.c
/*
gcc signal_test_abort.c -o signal_test_abort -W -Wall -g
*/
#include <sys/signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> void signal_handle( int sig ); void abort( ); int main( ) { struct sigaction sa; sa.sa_handler = signal_handle; sa.sa_flags = SA_RESTART; sigemptyset( &sa.sa_mask ); sigaction( SIGABRT, &sa, 0 ); printf( "in mail before abort!!\n" ); abort( ); printf( "in mail after abort!!\n" ); } void signal_handle( int sig ) { ( void )sig; char * msg = "in signal_handle!!\n"; write( 1, msg, strlen( msg )); } void abort( void ) { sigset_t mask; struct sigaction sa; sigaction( SIGABRT, 0, &sa ); if( sa.sa_handler == SIG_IGN ) { sa.sa_handler = SIG_DFL; sigaction( SIGABRT, &sa, 0 ); } sigfillset( &mask ); sigdelset( &mask, SIGABRT ); sigprocmask( SIG_SETMASK, &mask, 0 ); kill( getpid( ), SIGABRT ); sa.sa_handler = SIG_DFL; sigaction( SIGABRT, &sa, 0 ); sigprocmask( SIG_SETMASK, &mask, 0 ); kill( getpid(), SIGABRT ); exit( 1 ); }

4.10 待機

 シグナルはプロセスにとって非同期に送信されるもので、だからこそシグナルハンドラで捕捉し、その中で処理します。しかし場合によっては特定のシグナルの到着を待機する必要があります。つまりシグナルを同期的な処理です。待機中はプロセスが止まっているので、意図的にプロセスのサスペンドとレジュームを実装することが可能になります。

 実装は、sigprocmaskで対象シグナルをマスクし、sigsuspendによってサスペンドします。

 下記の例はCtrl+Cを押下されると子プロセスを止め、もう一度Ctrl+Cを押下されると子プロセスを再開します。

signal_test_process.c
/*
gcc signal_test_process.c -o signal_test_process -W -Wall -g
*/
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <signal.h> #include <errno.h> #include <unistd.h> #include <sys/wait.h> void signal_set ( ); void signal_handler ( int num ); void child_handler ( int num ); void suspend_handler( int num ); void resume_handler ( int num ); void end_handler ( int num ); pid_t g_pid; int max_cnt; int end_flg; int main( int argc, char ** argv ) { if( argc < 2 ) { exit( 1 ); } int i; signal_set( ); max_cnt = atoi( argv[1] ); g_pid = 0; fprintf( stdout, "parent:[%d][%d] Start!! \n", getpid( ), getpgrp( )); for( i = 0; i < max_cnt; i ++ ) { pid_t pid = fork( ); if( pid == 0 ) { /* child process */ fprintf( stdout, "child:[%d][%d][%d] Start!! \n", i, getpid( ), getpgrp( )); if( g_pid == 0 ) { g_pid = getpid( ); } setpgid( 0, g_pid ); fprintf( stdout, "child:[%d][%d][%d] Start!! \n", i, getpid( ), getpgrp( )); int count = 20; while( count ) { sleep( 1 ); fprintf( stdout, "process:[%d] count:[%d]\n", getpid( ), count ); count --; } exit( 0 ); } else if( pid > 0 ) { /* parent processs */ if( g_pid == 0 ) { g_pid = pid; } } } while( end_flg == 0 ) { pause( ); } return 0; } void signal_set( ) { struct sigaction sa1, sa2, sa3, sa4, sa5; sigemptyset( &sa1.sa_mask ); sa1.sa_handler = signal_handler; sa1.sa_flags = SA_RESTART; sigaction( SIGINT, &sa1, 0 ); sigemptyset( &sa2.sa_mask ); sa2.sa_handler = child_handler; sa2.sa_flags = SA_RESTART; sigaction( SIGCHLD, &sa2, 0 ); sigemptyset( &sa3.sa_mask ); sa3.sa_handler = suspend_handler; sa3.sa_flags = 0; sigaction( SIGUSR1, &sa3, 0 ); sigemptyset( &sa4.sa_mask ); sa4.sa_handler = resume_handler; sa4.sa_flags = 0; sigaction( SIGUSR2, &sa4, 0 ); sigemptyset( &sa5.sa_mask ); sa5.sa_handler = end_handler; sa5.sa_flags = 0; sigaction( SIGQUIT, &sa5, 0 ); } void signal_handler( int num ) { ( void )num; static int flg = 0; int no = 0; if( flg == 0 ) { no = SIGUSR1; } else { no = SIGUSR2; } kill( -g_pid, no ); flg ^= 1; } void child_handler( int num ) { ( void )num; while( waitpid( -1, 0, WNOHANG ) > 0 ); return; } void suspend_handler( int num ) { ( void )num; sigset_t signal_set; fprintf( stdout, "process:[%d] suspend!!\n", getpid( )); sigemptyset( &signal_set ); sigaddset( &signal_set, SIGUSR2 ); int no = 0; sigwait( &signal_set, &no ); return ; } void resume_handler( int num ) { ( void )num; fprintf( stdout, "process:[%d] resume!!\n", getpid( )); return; } void end_handler( int num ) { ( void )num; kill( -g_pid, SIGKILL ); end_flg = 1; }

 引数は1つで、子プロセス数を表します。カウントダウンを始めて20秒後に子プロセスは終了しますが、Ctrl+Cを押下されるとカウントダウンをストップします。再度Ctrl+Cを押下するとカウントダウンを開始します。親プロセスにSIGQUIT(画面からCtrl+\ 押下)を送信すると、全プロセスを終了します。

修正履歴

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
signalについて連載記事一覧

もっと読む

この記事の著者

赤松 エイト(エイト)

(株)DTSに勤てます。WebアプリやJavaやLL等の上位アプリ環境を密かに憧れつつも、ず~っとLinuxとかHP-UXばかり、ここ数年はカーネル以上アプリ未満のあたりを行ったり来たりしています。mixiもやってまして、こちらは子育てとか日々の日記メインです。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/1590 2008/08/20 15:56

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー