SlideShare a Scribd company logo
signal の話
或いは
Zend Signals とは何か
2016/12/11
第七回闇PHP勉強会
do_aki
updated 2016-12-13
@do_aki
@do_aki
http://do-aki.net/
signal とは
• UNIX系OS に古くからあるプロセス間通信の
一つ
• プロセスがシグナル(実態は整数) を受信す
ると、あらかじめ設定した処理(シグナルハ
ンドラ)が実行される(乱暴に言えば割り込
みが発生する)
• シグナルハンドラが設定されてないシグナル
は、無視されるかあるいは既定の動きをする
(その多くはプログラムの終了)
php においては
• pcntl 拡張を利用することで signal 処
理を管理することが可能
• pcntl_signal(signo, callback)
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" を出力して終了
pcntl による signal 処理
これは単純に
“シグナルを受信したら
callback が実行される”
というものではない
pcntl_signal が行うこと
• signal_table に シグナル番号とコール
バック関数を登録
• 該当シグナル番号に対するシグナルハン
ドラとして pcntl_signal_handler を
(実行環境に対して) 登録
• 実際にコールバック関数を呼ぶのは
pcntl_signal_dispatch
signal handling
pcntl_signal_handler
signo
pcntl_signal_dispatch
SIGHUP funcA
SIGINT funcB
SIGALRM funcC
……
signal table
lookup
&
call
signo
pending signal queue
[receive signal]
[tick or vm_interrupt]
シグナルハンドラの制約
• どんなタイミングであっても呼ばれる可能性
がある
– 当然 php のスタックフレームは無視
• 呼び出し可能なシステムコールが限られる
– man signal 7 を参照
最小限の処理(受信したことの記録) だけ
行い、あとから適切なタイミングでコール
バックを実行(dispatch)している
なので
tick による dispatch
• declare(ticks = N); // (N >= 1)
– N個の tick 可能命令ごとに ZEND_TICKS opcode
が発行される
– 詳しくは以前書いた記事を参照
http://d.hatena.ne.jp/do_aki/20151204/14491
97226
• ticks=1 ならば、だいたい php スクリプト1行
ごとに発行されてる
– 1行ごとに pcntl_signal_dispatch が呼ばれるイ
メージ
• ファイル単位で、コンパイル時に影響
– ticks 指定忘れるとシグナルコールバックされない
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 される気がする)
dispatch by vm_interrupt
pcntl_signal_handler
pcntl_signal_dispatch
[receive signal]
EG(vm_in
terrupt)
PHP VM
zend_interrupt_function =
pcntl_interrupt_function
[each opcode]
set1
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 を超えたとき
に設定される
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
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_in
terrupt)
EG(timed
_out)
ZEND_SIGNALS
• ZendEngineやSAPI,拡張 と 実行環境 の間に作ら
れた signal 処理の中間層
– 環境依存な signal 処理を画一的に扱うための仕組み
– 7.1 から デフォルトで有効
• php スクリプトにおける pcntl のようなものを、
C言語で(コアや拡張向けに) 提供した感じ
– zend_signal によって実行環境に登録されるシグナル
ハンドラは zend_signal_handler_defer に統一さ
れる (シグナルハンドラとして指定した関数はここか
ら間接的に呼ばれる)
Deferred Signals
• ZEND_SIGNAL_BLOCK_INTERRUPTIONS (=
HANDLE_BLOCK_INTERRUPTIONS) により、
シグナルハンドラの実行を延期することが可
能
– 現状使ってるのは opcache のみ
– 解放は ZEND_SIGNAL_UNBLOCK_INTERRUPTIONS
– シグナルハンドラの実行タイミングを制御するこ
とで、共有メモリ操作時の不安定な動きを解消し
ている(らしい)
– 以前はメモリ操作周りでも利用されていたが、
7.0 でのメモリマネージャ刷新によって不要に
なった?
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
まとめ
– pcntl signal
– EG(vm_interrupt)
– Safe timeout handling
– ZEND_SIGNALS
• について話しました
• 7.1 で php における signal 処理はだいぶ大き
く変容します
– おそらく ふつーに php スクリプト書いている人に
は気づかれないような変化。
けど、これにより安定化とパフォーマンス向上が図
られているのです
参照
• 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/internals@lists.php.net/msg76907.html
– https://github.com/php/php-src/pull/1876
• Enable Zend Signals by Default
– https://www.mail-archive.com/internals@lists.php.net/msg86428.html

More Related Content

PPTX
PHPとシグナル、その裏側
PPTX
PHP と SAPI と ZendEngine3 と
PDF
OPcache の最適化器の今
PPTX
php-src の歩き方
PPTX
PHP AST 徹底解説
PDF
Task Spooler を試した
PDF
JIT のコードを読んでみた
PPTX
PHP AST 徹底解説(補遺)
PHPとシグナル、その裏側
PHP と SAPI と ZendEngine3 と
OPcache の最適化器の今
php-src の歩き方
PHP AST 徹底解説
Task Spooler を試した
JIT のコードを読んでみた
PHP AST 徹底解説(補遺)

What's hot (20)

PDF
PECL を数えてみた
PPTX
php7's ast
PPTX
php and sapi and zendengine2 and...
PDF
PECL operator で演算子オーバーロード
PDF
ZynqMPのQEMU
PDF
Zynq VIPを利用したテストベンチ
PPTX
Php in ruby
ODP
LLVM overview 20110122
PDF
Async design with Unity3D
PDF
あるコンテキストスイッチの話
PDF
Adaptive optimization of JIT compiler
PDF
PHPでマルチスレッド
PDF
OPcacheの新機能ファイルベースキャッシュの内部実装を読んでみた
ODP
Android デバッグ小ネタ
PDF
最近の PHP の話
PDF
ttwrite
PDF
ラボユース最終成果報告会(Web公開版)
PDF
Dive into RTS - another side
PDF
Synthesijer fpgax 20150201
PDF
PECL を数えてみた
php7's ast
php and sapi and zendengine2 and...
PECL operator で演算子オーバーロード
ZynqMPのQEMU
Zynq VIPを利用したテストベンチ
Php in ruby
LLVM overview 20110122
Async design with Unity3D
あるコンテキストスイッチの話
Adaptive optimization of JIT compiler
PHPでマルチスレッド
OPcacheの新機能ファイルベースキャッシュの内部実装を読んでみた
Android デバッグ小ネタ
最近の PHP の話
ttwrite
ラボユース最終成果報告会(Web公開版)
Dive into RTS - another side
Synthesijer fpgax 20150201
Ad

More from do_aki (20)

PPTX
Tritonn から Elasticsearch への移行話
PPTX
再考:列挙型
PPTX
Writing php extensions in golang
PPTX
N対1 レプリケーション + Optimizer Hint
PPTX
20150212 プレゼンテーションzen
PPTX
MySQL Casual Talks 7 「N:1 レプリケーション ~進捗どうですか?~」
PPTX
20141017 introduce razor
PPTX
20141011 mastering mysqlnd
PPTX
php in ruby
PPTX
PHP から Groonga を使うにはこんなコードになるよ!
PPTX
N:1 Replication meets MHA
PDF
Php radomize
PPTX
セキュアそうでセキュアじゃない少しセキュアな気分になれるmysql_config_editor
PPTX
マスタN対スレーブ1レプリケーションの作り方 ~あれから~
PPTX
Immortal
PPTX
Excel is image viewer
PDF
A bridge between php and ruby
PDF
Ruby and comparison_and...php
PPTX
Sore php
PPTX
Ruby enumerable source code reading
Tritonn から Elasticsearch への移行話
再考:列挙型
Writing php extensions in golang
N対1 レプリケーション + Optimizer Hint
20150212 プレゼンテーションzen
MySQL Casual Talks 7 「N:1 レプリケーション ~進捗どうですか?~」
20141017 introduce razor
20141011 mastering mysqlnd
php in ruby
PHP から Groonga を使うにはこんなコードになるよ!
N:1 Replication meets MHA
Php radomize
セキュアそうでセキュアじゃない少しセキュアな気分になれるmysql_config_editor
マスタN対スレーブ1レプリケーションの作り方 ~あれから~
Immortal
Excel is image viewer
A bridge between php and ruby
Ruby and comparison_and...php
Sore php
Ruby enumerable source code reading
Ad

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

  • 1. signal の話 或いは Zend Signals とは何か 2016/12/11 第七回闇PHP勉強会 do_aki updated 2016-12-13
  • 3. signal とは • UNIX系OS に古くからあるプロセス間通信の 一つ • プロセスがシグナル(実態は整数) を受信す ると、あらかじめ設定した処理(シグナルハ ンドラ)が実行される(乱暴に言えば割り込 みが発生する) • シグナルハンドラが設定されてないシグナル は、無視されるかあるいは既定の動きをする (その多くはプログラムの終了)
  • 4. php においては • pcntl 拡張を利用することで signal 処 理を管理することが可能 • pcntl_signal(signo, callback)
  • 5. 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" を出力して終了
  • 6. pcntl による signal 処理 これは単純に “シグナルを受信したら callback が実行される” というものではない
  • 7. pcntl_signal が行うこと • signal_table に シグナル番号とコール バック関数を登録 • 該当シグナル番号に対するシグナルハン ドラとして pcntl_signal_handler を (実行環境に対して) 登録 • 実際にコールバック関数を呼ぶのは pcntl_signal_dispatch
  • 8. signal handling pcntl_signal_handler signo pcntl_signal_dispatch SIGHUP funcA SIGINT funcB SIGALRM funcC …… signal table lookup & call signo pending signal queue [receive signal] [tick or vm_interrupt]
  • 9. シグナルハンドラの制約 • どんなタイミングであっても呼ばれる可能性 がある – 当然 php のスタックフレームは無視 • 呼び出し可能なシステムコールが限られる – man signal 7 を参照 最小限の処理(受信したことの記録) だけ 行い、あとから適切なタイミングでコール バックを実行(dispatch)している なので
  • 10. tick による dispatch • declare(ticks = N); // (N >= 1) – N個の tick 可能命令ごとに ZEND_TICKS opcode が発行される – 詳しくは以前書いた記事を参照 http://d.hatena.ne.jp/do_aki/20151204/14491 97226 • ticks=1 ならば、だいたい php スクリプト1行 ごとに発行されてる – 1行ごとに pcntl_signal_dispatch が呼ばれるイ メージ • ファイル単位で、コンパイル時に影響 – ticks 指定忘れるとシグナルコールバックされない
  • 11. 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 される気がする)
  • 12. dispatch by vm_interrupt pcntl_signal_handler pcntl_signal_dispatch [receive signal] EG(vm_in terrupt) PHP VM zend_interrupt_function = pcntl_interrupt_function [each opcode] set1
  • 13. 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 を超えたとき に設定される
  • 14. 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
  • 15. 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_in terrupt) EG(timed _out)
  • 16. ZEND_SIGNALS • ZendEngineやSAPI,拡張 と 実行環境 の間に作ら れた signal 処理の中間層 – 環境依存な signal 処理を画一的に扱うための仕組み – 7.1 から デフォルトで有効 • php スクリプトにおける pcntl のようなものを、 C言語で(コアや拡張向けに) 提供した感じ – zend_signal によって実行環境に登録されるシグナル ハンドラは zend_signal_handler_defer に統一さ れる (シグナルハンドラとして指定した関数はここか ら間接的に呼ばれる)
  • 17. Deferred Signals • ZEND_SIGNAL_BLOCK_INTERRUPTIONS (= HANDLE_BLOCK_INTERRUPTIONS) により、 シグナルハンドラの実行を延期することが可 能 – 現状使ってるのは opcache のみ – 解放は ZEND_SIGNAL_UNBLOCK_INTERRUPTIONS – シグナルハンドラの実行タイミングを制御するこ とで、共有メモリ操作時の不安定な動きを解消し ている(らしい) – 以前はメモリ操作周りでも利用されていたが、 7.0 でのメモリマネージャ刷新によって不要に なった?
  • 18. 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
  • 19. まとめ – pcntl signal – EG(vm_interrupt) – Safe timeout handling – ZEND_SIGNALS • について話しました • 7.1 で php における signal 処理はだいぶ大き く変容します – おそらく ふつーに php スクリプト書いている人に は気づかれないような変化。 けど、これにより安定化とパフォーマンス向上が図 られているのです
  • 20. 参照 • 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/internals@lists.php.net/msg76907.html – https://github.com/php/php-src/pull/1876 • Enable Zend Signals by Default – https://www.mail-archive.com/internals@lists.php.net/msg86428.html

Editor's Notes

  • #9: process が signal を受け取ると、 pcntl_signal_handler が受け取る。 signal handler は実行できることが限られるため、任意の処理を行えないようにしている。 tick あるいは pcntl_signal_dispatch php 関数が呼ばれると、 pcntl_signal_dispatch C関数が呼ばれ、 pending signal queue から一つずつ 受信した signal 番号を取り出し、signal table に登録されている関数を callback する。 7.1からは、環境が siginfo に対応している場合には siginfo (シグナルの呼び出し元pidやuid 等の詳細情報)も保持する。、 これを array に変換したものが pcntl_signal で設定した callback 関数の第2引数として渡ってくる (まだドキュメントにはない)