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」コマンドを使います。 Mac OS Xでは、「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)
{
  printf("signal USR1 called\n");
}

void
sigusr2_handler(int sig)
{
  printf("signal USR2 called\n");
}

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;
}