20
signal のの ののの Zend Signals のののの 2016/12/11 のののの PHP ののの do_aki updated 2016-12-13

signal の話 或いは Zend Signals とは何か

  • Upload
    doaki

  • View
    2.640

  • Download
    3

Embed Size (px)

Citation preview

Page 1: signal の話 或いは Zend Signals とは何か

signal の話或いは

Zend Signals とは何か

2016/12/11 第七回闇 PHP 勉強会

do_akiupdated 2016-12-13

Page 2: signal の話 或いは Zend Signals とは何か

@do_aki

@do_aki

http://do-aki.net/

Page 3: signal の話 或いは Zend Signals とは何か

signal とは

• UNIX 系 OS に古くからあるプロセス間通信の一つ

• プロセスがシグナル ( 実態は整数 ) を受信すると、あらかじめ設定した処理 ( シグナルハンドラ ) が実行される(乱暴に言えば割り込みが発生する)

• シグナルハンドラが設定されてないシグナルは、無視されるかあるいは既定の動きをする(その多くはプログラムの終了)

Page 4: signal の話 或いは Zend Signals とは何か

php においては

• pcntl 拡張を利用することで signal 処理を管理することが可能

• pcntl_signal(signo, callback)

Page 5: signal の話 或いは Zend Signals とは何か

pcntl_signal の利用例<?php

declare(ticks=1);

$signal_callback_function = function ($signo) { echo "receive signal: {$signo}\n"; exit;};

pcntl_signal(SIGINT, $signal_callback_function);

while(1) { sleep(1);}

// 通常の動きだけでは永久ループ// Ctrl + C 押下で、 "receive signal: 2" を出力して終了

Page 6: signal の話 或いは Zend Signals とは何か

pcntl による signal 処理

これは単純に

“ シグナルを受信したら   callback が実行される”

     というものではない

Page 7: signal の話 或いは Zend Signals とは何か

pcntl_signal が行うこと

• signal_table に シグナル番号とコールバック関数を登録

• 該当シグナル番号に対するシグナルハンドラとして pcntl_signal_handler を (実行環境に対して ) 登録

• 実際にコールバック関数を呼ぶのは pcntl_signal_dispatch

Page 8: signal の話 或いは Zend Signals とは何か

signal handling

pcntl_signal_handlersigno

pcntl_signal_dispatch

SIGHUP funcA

SIGINT funcB

SIGALRM funcC

……

signal table

lookup &

call

signo pending signal

queue

[receive signal]

[tick or vm_interrupt]

Page 9: signal の話 或いは Zend Signals とは何か

シグナルハンドラの制約

• どんなタイミングであっても呼ばれる可能性がある– 当然 php のスタックフレームは無視

• 呼び出し可能なシステムコールが限られる– man signal 7 を参照

最小限の処理 ( 受信したことの記録 ) だけ行い、あとから適切なタイミングでコールバックを実行 (dispatch) している

なので

Page 10: signal の話 或いは Zend Signals とは何か

tick による dispatch• declare(ticks = N); // (N >= 1)

– N個の tick 可能命令ごとに ZEND_TICKS opcode が発行される

– 詳しくは以前書いた記事を参照http://d.hatena.ne.jp/do_aki/20151204/1449197226

• ticks=1 ならば、だいたい php スクリプト 1行ごとに発行されてる– 1行ごとに pcntl_signal_dispatch が呼ばれるイ

メージ• ファイル単位で、コンパイル時に影響

– ticks 指定忘れるとシグナルコールバックされない

Page 11: signal の話 或いは Zend Signals とは何か

vm_interrupt による dispatch

• pcntl_async_signals(true); // 7.1~– declare(ticks=1) が不要になる– pcntl_signal_handler が EG(vm_interrupt) = 1 するようになる

• EG(vm_interrupt) が 1 の場合、 PHP VM は、zend_interrupt_function (関数ポインタ) を呼ぶ– Opcode ひとつ処理するたびにチェックしている– pcntl の MINIT で

zend_interrupt_function = pcntl_interrupt_functionしてて、このなかで pcntl_signal_dispatch を呼ぶ

– ZEND_TICKS Opcode で毎回呼ばれるよりも低コスト– (async_signals しなくても pcntl 以外が vm_interrupt を

セットすれば dispatch される気がする)

Page 12: signal の話 或いは Zend Signals とは何か

dispatch by vm_interrupt

pcntl_signal_handler

pcntl_signal_dispatch

[receive signal]

EG(vm_interrup

t)

PHP VM

zend_interrupt_function =

pcntl_interrupt_function

[each opcode]

set1

Page 13: signal の話 或いは Zend Signals とは何か

EG(vm_interrupt)• 元は Safe timeout handling により導入さ

れた仕組み

• EG(vm_interrupt) かつ EG(timed_out) ならば (zend_interrupt_function ではなく ) zend_timeout(0) を呼ぶ (おそらくこちらが本命 )

• EG(timed_out) は php スクリプトの実行時間が max_execution_time を超えたときに設定される

Page 14: signal の話 或いは Zend Signals とは何か

max_execution_time の実装

• setitimer (ITIMER_PROF)を利用 (!WIN32)– プログラムの実行時間が指定時間経過すると SIGPROF

が飛ぶ– php に kill –PROF すると終了する

• zend engine でシグナルハンドラ を設定してる– 7.0まで : signalシステムコールを利用

(直接 zend_timeout が呼ばれてた )– 7.1から : zend_signalを利用 (ZEND_SIGNALS)

      (zend_timeout_handler)

この中で EG(timed_out) = 1

Page 15: signal の話 或いは Zend Signals とは何か

Safe timeout handling

zend_timeout_handler

PHP VM

zend_timeout

set1

zend_timeout

~7.0 (or !ZEND_SIGNALS)

7.1~ (with ZEND_SIGNALS)

EG(vm_interrup

t)EG(timed_out)

Page 16: signal の話 或いは Zend Signals とは何か

ZEND_SIGNALS• ZendEngineや SAPI,拡張 と 実行環境 の間に作ら

れた signal 処理の中間層– 環境依存な signal 処理を画一的に扱うための仕組み– 7.1 から デフォルトで有効

• php スクリプトにおける pcntl のようなものを、C言語で (コアや拡張向けに ) 提供した感じ– zend_signal によって実行環境に登録されるシグナル

ハンドラは zend_signal_handler_defer に統一される (シグナルハンドラとして指定した関数はここから間接的に呼ばれる )

Page 17: signal の話 或いは Zend Signals とは何か

Deferred Signals• ZEND_SIGNAL_BLOCK_INTERRUPTIONS (= HANDLE_BLOCK_INTERRUPTIONS) により、シグナルハンドラの実行を延期することが可能– 現状使ってるのは opcache のみ– 解放は ZEND_SIGNAL_UNBLOCK_INTERRUPTIONS– シグナルハンドラの実行タイミングを制御すること

で、共有メモリ操作時の不安定な動きを解消している(らしい)

– 以前はメモリ操作周りでも利用されていたが、 7.0 でのメモリマネージャ刷新によって不要になった?

Page 18: signal の話 或いは Zend Signals とは何か

ZEND SIGNALS

zend_signal_handler_defer

1 handler1

2 hanlder2

3 hanlder3

……SIGG(handlers)

zend signal queue

signo

signal blocked(HANDLE_BLOCK_INTERRUPTIONS)

signal unblocked

HANDLE_UNBLOCK_INTERRUPTIONS

signo

callzend_signal_handler

Page 19: signal の話 或いは Zend Signals とは何か

まとめ– pcntl signal – EG(vm_interrupt)– Safe timeout handling – ZEND_SIGNALS

• について話しました

• 7.1 で php における signal 処理はだいぶ大きく変容します– おそらく ふつーに php スクリプト書いている人には気づ

かれないような変化。けど、これにより安定化とパフォーマンス向上が図られているのです

Page 20: signal の話 或いは Zend Signals とは何か

参照• Zend Signal Handling

– https://wiki.php.net/rfc/zendsignals– https://

github.com/php/php-src/commit/939875133a2c389d621a9999a8ede3ddbc9b6637

• Asynchronous Signal Handling (without TICKs) – https://wiki.php.net/rfc/async_signals– https://

github.com/php/php-src/commit/c03ccfe78d6b13cab9546efb616a42a8f3e8a4e0

• Safe execution timeout handling– https://www.mail-archive.com/[email protected]/msg76907.html– https://github.com/php/php-src/pull/1876

• Enable Zend Signals by Default– https://www.mail-archive.com/[email protected]/msg86428.html