シグナル通信 普通の割込みとソフトウェア割込み ソフトウェア割込みとシグナル キーボードからのシグナル 例外 (exception) キーボードからのシグナルの応用 シグナルの種類 ソフトウェア割込み(シグナル)の利用法 signalシステム・コール signalプログラミング シグナルalarmプログラミング シグナルkillプログラミング
Ctrl-C 普通の割込みとソフトウェア割込み 普通の割込み(ハードウェアによる割込み)は、オペレーティング・システム のカーネルにおいて利用されている。 ソフトウェア割込みとは、本来はオペレーティング・システムのカーネルしか 使えない割込みの機能を、ソフトウェアにより実現して、一般の利用者プログ ラム(プロセス)でも使えるようにしたものである。 Ctrl-C プロセス A プロセス B ソフトウェア割込み カーネル
Ctrl-C ソフトウェア割込みとシグナル ソフトウェア割込みの機能は、シグナル(signal)という名前で実現 されている。 シグナルとは、本来はプロセス間通信の一種で、あるイベントが起き たことを他のプロセスに知らせることである。 シグナルで伝わるのは、あるイベントが 起きたかどうかだけで、イベントの種類の区別ができることがあるが、 データを送ることはできない。 Ctrl-C プロセス A プロセス B プロセス間通信 シグナル カーネル
キーボードからのシグナル プロセス間でシグナルにより通信をする他に、キーボードからシグナルを送ることも できる。 キーボードからのシグナルは、「ソフトウェア割込み」として、プロセス1つひとつに割込みボタンが付いているようなものである。 プロセスA signal(SIGINT,stop); void stop() { … } プロセスB Ctrl-C シグナル
例外 (exception) プログラムの中で例外 (exception)が起きた時にも、ハードウェアの割込みと同様に、ソフトウェ ア割込みが生じる。 例外 (exception)も、他のシグナルと同じように受け取ることができる。 プロセスA signal(SIGINT,stop); void stop() { … } プロセスB Ctrl-C 例外 (exception) シグナル
キーボードからのシグナルの応用 $ cat > gomi a b c Ctrl-Z [1]+ Stopped cat >gomi $ fg cat >gomi d e f $ cat gomi $ Ctrl-Z 再開 Ctrl-C
alarmシステムコールからのタイマーシグナル シグナルの種類 種類 発生原因 デフォルト動作 SIGHUP 端末のハングアップ 終了 SIGINT Ctrl-C SIGQUIT Ctrl-\ コアダンプ SIGILL 不正な命令 SIGTRAP トレース SIGABRT abort関数の実行 SIGBUS バスエラー SIGFPE 浮動小数点例外 SIGKILL killシグナル SIGUSR1 ユーザ定義シグナル SIGSEGV 不正なメモリ参照 SIGUSR2 SIGPIPE バイプの破壊 SIGALRM alarmシステムコールからのタイマーシグナル SIGTERM 終了シグナル SIGCLD 子プロセスの停止、終了 無視 SIGCONT いったん停止からの再開 SIGSTOP プロセスのいったん停止 停止 SIGTSTP Ctrl-Z
ソフトウェア割込み(シグナル)の利用法 受け側(割り込まれる方、シグナルを受け取る方) 割込みハンドラの定義。割込みが起きた時に実行される関数を定義する。 割込みハンドラの登録。定義した関数を登録する。signal(2), sigvector(2), などを使う。 割込みマスク(割込みを禁止のビット・ベクトル)の制御。 sigsetmask(2) など。 送り側(割り込む方、シグナルを送る方) 割込みの発生。kill(2) など。 キーボード。 例外。 タイマ割り込み。alarm(2)。 割り込みハンドラが設定されていない時には、プロセスは、デフォルトの動き をする。デフォルトには、次の3つがある。 プロセスが終了させられる。 プロセスが一時停止させられる。 なにも起らない(シグナルが無視される)。 signal の種類は、man 7 signal (Linux) で表示される。
signalシステム・コール プロセス シグナルを受け取ったときの処理を指定 インクルードファイル #include <signal.h> 書式 sighandler_t signal(int signum, sighandler_t sighandler); 引数 signum シグナルの種類 sighandler シグナルハンドラのアドレス デフォルト動作: sighandler=SIG_DFL シグナルを無視: sighandler=SIG_IGN 戻値 成功時 前回のシグナルハンドラのアドレス 失敗時 SIG_ERR 使用例 void stop(); signal(SIGINT, &stop); プロセス signal(SIGINT,stop); void stop() { … } シグナル
signalプログラミング(1/2) signal-int.c signal() で、割込み処理ハンドラを関数 sigint_handler()登録している。この段階で、関数 sigint_handler() は呼び出されない。また、プログラムのどこからも、関数 sigint_handler() は明示的には呼び出されていない。 main() は、無限ループになっている。 pause() は、割込みを待つシステムコールである。システムコールの実行中に 割込みが発生するまで待つ。発生すると、割込み処理ハンドラの実行後にリターンする。 sigint_handler() は、main() から呼び出されないが、割込みが発生すると実行される。内部では、大域変数 sigint_count を減らして、0 以下になれば終 了している。
signalプログラミング(2/2) timer.c signal() で、割込み処理ハンドラ関数 sigint_handler()を登録している。この段階で、関数 sigint_handler() は呼び出されない。また、プログラムのどこからも、関数 sigint_handler() は明示的には呼び出されていない。 main() は、 "."を永久ループにより1秒毎に出力。 sigint_handler() は、main() から呼び出されないが、割込みが発生すると実行され、SIGINT を受け付けて終了(経過時間をプリント)。
シグナルalarmプログラミング(1/2) alarm.c alarm(秒) は、指定した秒の経過後にSIGALRMを発生 signal() で、割込み処理ハンドラ関数 func()を登録している。この段階で、関数 func() は呼び出されない。また、プログラムのどこからも、関数 func() は明示的には呼び出されていない。 main() は、 alarm()で1秒後にSIGALRMの発生を指示、そして永久ループに入る。 func() は、main() から呼び出されないが、割込みが発生すると実行され、 SIGALRMを受け付けてメッセージをプリントし、再び、 alarm()で1秒後にSIGALRMの発生を指示。 結果、毎秒、割込み処理ハンドラ関数 func() が呼び出され、メッセージをプリント。 alarm.c
シグナルalarmプログラミング(2/2) alarm-pause.c signal() で、割込み処理ハンドラ関数 func()を登録している。この段階で、関数 func() は呼び出されない。また、プログラムのどこからも、関数 func() は明示的には呼び出されていない。 main() は、 alarm()で1秒後にSIGALRMの発生を指示、そしてpause() により割り込みの発生を待つ。 func() は、main() から呼び出されないが、割込みが発生すると実行され、 SIGALRMを受け付けてメッセージをプリント alarm-pause.c
シグナルkillプログラミング(1/3) kill-group.c kill(0,1) 自分と同じグループIDを持つプロセス全てに、プロセスの強制終了シグナルを送信 (シグナル番号に 0 を入れる)
シグナルkillプログラミング(2/3) kill-pid.c kill(pid,1)
シグナルkillプログラミング(3/3) kill(pid,0) kill-query-pid.c if(kill(pid,0) != EOF) プロセスは存在する kill-query-pid.c