AnyEvent のコールバックの coro は main coro じゃないことを知り、coro の PID はアドレス値であることを知る修行
AnyEvent::timer の callback coro
AnyEvent::timer のコールバックが実行されるのはイベントループだからメイン coro なんだろうと思っていた。が、次のプログラムを走らせてみて、そうではないことを知った。
use strict; use warnings; use Coro; use AnyEvent; my $head = 'Coro=HASH(0x'; my $head_len = length $head; sub p { my $coro = shift; my $addr = hex substr($coro, index($coro, $head) + $head_len, -1); print "coro ".$coro->desc." ".$coro.":$addr\n"; } my $cv = AE::cv; my $w = AE::timer 0, 0, sub { p $Coro::main; p $Coro::current; use Coro::Debug; Coro::Debug::command 'ps'; print Coro::nready."\n"; $cv->send; }; $cv->recv; __END__
実行結果は次のようになる。
[takeyuki@sunya ~]$ perl b.pl coro [main::] Coro=HASH(0x907c3d4):151503828 coro [AnyEvent idle process] Coro=HASH(0x920839c):153125788 PID SC RSS USES Description Where 151503828 -C 17k 0 [main::] [AnyEvent.pm:1719] 151485828 N- 116 0 [coro manager] - 151485996 N- 116 0 [unblock_sub scheduler] - 153125788 UC 2484 1 [AnyEvent idle process] [b.pl:19] 0
main coro とコールバックが実行されている coro は違っている。でもって ready queue は空。
coro の PID は、その coro の格納アドレスに等しいらしいことが、coro を文字列コンテキストで評価したときの "Coro=HASH(0xXXXXXXX)" の 16 進数部分を無理矢理 10 進数に直してみてわかった。じゃあ、Coro::Debug::command を使って eval したり bt したりできるのかな。後でやってみよう。
unblock_sub callback coro
上のプログラムのコールバックを sub から unblock_sub に変更すると次のような実行結果になる。
[takeyuki@sunya ~]$ perl b.pl coro [main::] Coro=HASH(0x86013ec):140514284 coro [async_pool] Coro=HASH(0x8616864):140601444 PID SC RSS USES Description Where 140514284 -C 17k 0 [main::] [AnyEvent.pm:1719] 140496284 N- 116 0 [coro manager] - 140496452 R- 1436 1 [unblock_sub scheduler] [Coro.pm:428] 142136208 -- 1604 1 [AnyEvent idle process] [Coro.pm:428] 140601444 UC 2232 1 [async_pool] [b.pl:19] 1
unblock_sub にすると coro が増えるのはわかっていたけど、description から判断するに、coro プールに所属する coro らしい。なるほど、それはいい。$Coro::POOL_SIZE を超えても async_pool するんだろうな。後でやってみよう。
無理矢理作り出した PID と Coro::Debug::command でやなことをしてみる
次のプログラムは停止しない。
use strict; use warnings; use Coro; my $head = 'Coro=HASH(0x'; my $head_len = length $head; sub pid { my $coro = shift; return hex substr($coro, index($coro, $head) + $head_len, -1); } sub cmd { use Coro::Debug; Coro::Debug::command shift; } my $m = $Coro::main; my $c = async { while (1) { cede; } }; $c->on_destroy(sub {print "terminated.\n"}); cede; my $m_pid = pid $m; my $c_pid = pid $c; print "--- ps ---\n"; cmd 'ps'; print "--- backtrace ---\n"; cmd "bt $c_pid"; print "--- eval ---\n"; cmd "eval $c_pid \$Coro::current->desc"; cmd "cancel $c_pid"; print "--- backtrace ---\n"; cmd "bt $m_pid"; print "--- eval ---\n"; cmd "eval $m_pid \$Coro::current->desc"; cmd "cancel $m_pid";
実行結果。
[takeyuki@sunya ~]$ perl a.pl --- ps --- PID SC RSS USES Description Where 143955172 UC 17k 1 [main::] [a.pl:15] 143937172 N- 116 0 [coro manager] - 143937340 N- 116 0 [unblock_sub scheduler] - 143318332 R- 1436 1 [a.pl:21] 145577684 N- 116 0 [AnyEvent idle process] - --- backtrace --- coroutine is at a.pl line 21 main::__ANON__ called at /usr/lib/perl5/site_perl/5.8.8/i386-linux-thread-multi/Coro.pm line 428 Coro::_coro_run called at a.pl line 0 --- eval --- [main::] terminated. --- backtrace --- coroutine is at /usr/lib/perl5/site_perl/5.8.8/i386-linux-thread-multi/Coro/Debug.pm line 325 Coro::Debug::command('bt 143955172') called at a.pl line 15 main::cmd('bt 143955172') called at a.pl line 37 --- eval --- [main::]
実行結果からわかること。
- backtrace は実行できる
- eval は pid のコンテキストで実行されるとあるが、main coro で実行されているっぽい
- cancel も実行できる
- main coro を cancel するとプログラムが停止しない
今のところ、[coro manager] や [unblock_sub scheduler] の PID をプログラムの中から知る方法がわからない (ps して標準出力に吐かれるのを無理矢理パースすればできないこともないけど)。これらの PID を知ることができて、なおかつ、そのコンテキストで eval できるといろいろ面白い実験ができそうだ。