Rubyコンテキストスイッチの不思議・その2
Rubyコンテキストスイッチの不思議 - LinuxとApacheの憂鬱の続き
Ruby extension内ではコンテキストスイッチは起きないハズなのに
EventMachine内では確かに起きてる!の謎
EventMachineのソースを読む
詳しい事は省略するが
- pure_ruby.rb => run_machine
ココでextensionの世界に入って来る。
んで、地続きで進み・・・
- cmain.cpp => EventMachine->Run()
で、EventMachineに入る
- em.cpp => EventMachine->Run() => _RunEpollOnce() => epoll_wait
ココが問題の個所。
でもあからさまに変な奴がいるぜ!
#ifdef BUILD_FOR_RUBY : TRAP_BEG; s = epoll_wait (epfd, epoll_events, MaxEvents, 0); TRAP_END;
100% 間違いない!!w
で、em.h に居ました。
#define TRAP_BEG rb_enable_interrupt() #define TRAP_END do { rb_disable_interrupt(); rb_thread_check_ints(); } while(0)
へー
rb_enable_interrupt();
なんてモノがあるんだね〜
早速使ってみる。
#include "rubysig.h" : : VALUE method_myext3(VALUE self) { printf("TEST2 START\n"); fflush(stdout); TRAP_BEG; // ### Allow to interrupt sleep(3); TRAP_END; // ### Deny to interrupt printf("TEST2 END **** HERE ****\n"); fflush(stdout); return Qnil; }
しかし、コンパイル時に警告!
動くんだけどさ・・・
#warning rubysig.h is obsolete
Obsoluteじゃ仕方ない。。。
最新のやり方はどうすんのさ?
ヘッダを攫うと"intern.h"ってのが有るけど・・・情報が少ないなぁ。。
http://www.ruby-forum.com/topic/2914075#1029667
BLOCKING_REGION ってマクロ使うと簡単だぜ!
エライ!
って・・・
どこにも定義されてねーじゃんかYO!!1.9.2の話かっ!!
もういいや、このままコピってこよ
#!/usr/bin/env ruby puts '=== Interruptable mode ===' require 'myext' include MyExt def test1(i) myext1 i end def test2 myext3 end
#define BLOCKING_REGION(func, arg) (long)rb_thread_blocking_region((func), (arg), RUBY_UBF_IO, 0) VALUE mysleep(void *a){ sleep(3); return 0; } VALUE method_myext3(VALUE self) { printf("TEST3 START\n"); fflush(stdout); (void)BLOCKING_REGION(mysleep, 0); printf("TEST3 END **** HERE ****\n"); fflush(stdout); return Qnil; }
結果
=== Interruptable mode === test1 (0) start test1 end test1 (1) start test1 end TEST3 START test1 (2) start test1 end test1 (3) start test1 end test1 (4) start test1 end TEST3 END **** HERE ****
ちゃんとコンテキストスイッチが動いたー!
なるほどね!良く考えられてるな〜
でもこれは結構恐ろしい機構なので、不用意には使えない。
自分の使ってるExtensionも念の為にgrepしとこ・・・