というわけで、httpd が SIGABRT で死ぬ原因を探しました。
dmesg がこんな感じ。
pid 49335 (httpd), uid 80: exited on signal 6 pid 61486 (httpd), uid 80: exited on signal 6 pid 61530 (httpd), uid 80: exited on signal 6 pid 62145 (httpd), uid 80: exited on signal 6 pid 62139 (httpd), uid 80: exited on signal 6 pid 62714 (httpd), uid 80: exited on signal 6 pid 62771 (httpd), uid 80: exited on signal 6 pid 61289 (httpd), uid 80: exited on signal 6
このとき http-error.log はこんな感じ。
httpd in free(): error: recursive call [notice] child pid 62714 exit signal Abort trap (6) httpd in free(): error: recursive call [notice] child pid 62771 exit signal Abort trap (6) httpd in free(): error: recursive call [notice] child pid 61289 exit signal Abort trap (6)
結論としてはシグナルハンドラで余計なことするなということで。
パッチを作ろうかと思ったけども思いのほか根が深くて断念。
とりあえず max_execution_time=0 で回避。
1. パフォーマンスタイマーの設定
まず発端は main/main.c にて。
PHP_INI_ENTRY("max_execution_time","30",PHP_INI_ALL,OnUpdateTimeout)
によって、max_execution_time の設定で OnUpdateTimeout() が呼ばれます。
そして、同じく main/main.c にて
zend_set_timeout(EG(timeout_seconds));
と、zend_set_timeout() が呼ばれます。この実体は Zend/zend_execute_API.c にあって
setitimer(ITIMER_PROF, &t_r, NULL); signal(SIGPROF, zend_timeout);
と、これで指定時間後に SIGPROF が飛んできて、zend_timeout() が呼ばれます。
2. タイムアウトでシグナル拿捕
zend_timeout() も同じく Zend/zend_execute_API.c にあって
zend_error(E_ERROR, "Maximum execution time of %d second%s exceeded", EG(timeout_seconds), EG(timeout_seconds) == 1 ? "" : "s");
エラーメッセージを表示して終了します。
この zend_error() は Zend/zend.c に実体があり
/* The error may not be safe to handle in user-space */
zend_error_cb(type, error_filename, error_lineno, format, args);
こんなコメントと共にコールバック関数へと飛びます。
zend_error_cb は関数ポインタで、Zend/zend.c の zend_startup で初期化されて、
実際の値は main/main.c の php_error_cb() を指しています。
ここで
buffer_len = vspprintf(&buffer, PG(log_errors_max_len), format, args);
やら
efree(buffer);
やらした挙句に
zend_bailout();
で終了します。
3. ベイルアウトぉぉぉーーー
zend_bailout() は Zend/zend.c に実体があって
longjmp(*EG(bailout), FAILURE);
と。ちなみに Zend/zend.h には
#define zend_try ... #define zend_catch ... #define zend_end_try() ...
と、まぁいわゆる try - catch の C 言語版でしょうか。
setjump - longjump で実現しているわけですね。