PHPでシグナルを扱う

PHP でシグナルを扱うにはプロセス制御を利用する。 その際に必要なticks関数の設定についてメモする。

その前に

pcntl が使えるか確認する。以下で実行可能か確認しておく。

1
2
$ php -i | awk /[p]cntl\ support/
pcntl support => enabled

OSXで標準で入っているのはコンパイルオプション--enable-pcntlが有効になってなかった。 公式に従ってインストールしてしまうphpenvで有効なバージョンを入れる。phpenvでインストールした。

1
2
3
4
# phpenvでbuildする時のオプションの確認
$ awk /pcntl/ ~/.phpenv/plugins/php-build/share/php-build/default_configure_options
--enable-pcntl
$ phpenv intall 5.5.5

declare(ticks = 1)を有効にする

シグナルハンドラの登録はpcntl-signalを使う。 で 4.3.0以降はdeclare(ticks = 1);をコードブロックに記述しないと動かない。

ticks関数のpcntl_signal_dispatchが呼ばれることでシグナルハンドラが叩かれる仕組みになっているのだけれど、 ticksは効率が悪いって事で、 4.3.0以降ではdeclareによる明記が必要になったため。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
// test.php
declare(ticks = 1);
pcntl_signal(SIGHUP, handler);
function handler($signo) {
  echo 'in '. __FUNCTION__. PHP_EOL;
  exit(1);
}
while (true) {
  echo 'in loop. '. __FILE__. PHP_EOL;
  sleep(1);
}

動かした感じ。

```bash
$ php -d open_basedir=/ test.php
in loop test.php
in loop test.php
in loop test.php
...
# 別ターミナルで
$ kill -s 1 $PID
# 動いてた方が応えている
in handler

declareの位置を注意する

グローバル環境でdeclare設定されると呼び出されたコードブロックの中でも設定は有効。 だけど呼び出された側のグローバル環境で設定しても呼び出し元には影響しない。 なので下のコードはSIGHUPを受け取ってくれない。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<?php
// test.php
pcntl_signal(SIGHUP, handler);
function handler($signo) {
  echo 'in '. __FUNCTION__. PHP_EOL;
  exit(1);
}
require 'required.php';
while (true) {
  echo 'in loop. '. __FILE__. PHP_EOL;
  sleep(1);
}
1
2
3
<?php
// required.php
declare(ticks = 1);
comments powered by Disqus