pselectでシグナルを無視する
selectは、ブロック中にシグナルを受け取るとEINTRを返します。 ここでは、pselectを利用して指定したシグナルに関してはEINTRを返さないでselect処理を実行する方法を説明したいと思います。
selectを横から止める
pselectは、selectの応用例のようなものです。 selectとEINTRに関しては「selectを横から止める方法」をご覧下さい。
サンプルコード
下記サンプルコードは、pselectに入るとずっとブロックし続けます。 ブロッキング状態を解除するためには、下記サンプルコードにUSR2シグナルを送信します。 シグナルハンドラが登録されていないシグナルを受け取ると、アプリケーションは終了してしまいます。 そのため、下記サンプルではprintfだけ行って何もしないシグナルハンドラを登録しています。 ハンドラを登録せずに、SIGUSR2をignoreするように書いても、同様の事はできます。
今回のサンプルでは、SIGUSR1を送信してもpselectはブロッキング状態を維持します。 これは、pselectに渡す引数でSIGUSR1を無視するように設定してあるからです。 今回のサンプルにSIGUSR2を送信するとpselectはEINTRで返ります。
シグナルの送信には「kill」コマンドを使います。 Linuxでは、「kill -s SIGUSR1 サンプルアプリPID」とするとUSR1シグナルがサンプルアプリに送信されます。 SIGUSR1の部分をSIGUSR2にするとUSR2シグナルが送信されます。 サンプルアプリのPIDを調べるには「ps」コマンド等を利用してください。
#include <stdio.h>
#include <signal.h>
#include <sys/select.h>
void
sigusr1_handler(int sig)
{
write(fileno(stdout), "signal USR1 called\n", 19);
}
void
sigusr2_handler(int sig)
{
write(fileno(stdout), "signal USR2 called\n", 19);
}
int
main()
{
fd_set readfds;
int n;
sigset_t sigset;
/* SIGUSR1のシグナルハンドラを設定 */
signal(SIGUSR1, sigusr1_handler);
/* SIGUSR2のシグナルハンドラを設定 */
signal(SIGUSR2, sigusr2_handler);
/* SIGUSR1のシグナルを設定 */
sigemptyset(&sigset);
sigaddset(&sigset, SIGUSR1);
FD_ZERO(&readfds);
printf("before select\n");
/* SIGUSR2が来るまでselectはblockし続けます */
/* SIGUSR1ではEINTRは返りません */
n = pselect(0, &readfds, NULL, NULL, NULL, &sigset);
printf("after select : %d\n", n);
/* errnoがEINTRになっているのを確認して下さい */
perror("after select");
return 0;
}