From: SASADA Koichi Date: 2008-12-22T09:37:09+09:00 Subject: [ruby-dev:37531] Re: [Bug: trunk] GC from blocking region  ささだです. U.Nakamura wrote:: > In message "[ruby-dev:37448] [Bug: trunk] GC from blocking region" > on Dec.15,2008 22:44:31, wrote: >> (c) blocking_region の中で,さらに ruby な環境にさわれる状態になり(GVL >> を取得する),メモリ確保を行う,ということが考えられます.性能はもちろん >> 落ちますが(使いどころを間違えると,とてもとても遅くなります),どーして >> も必要な場合は使う,ってことが出来るかと思います. > > 現状これができるAPIがないわけですが、追加できるものならすると > しても、いつ頃これが可能になりそうですか?  作ってみました.これで動くかやってもらえませんか.あと,名前のセンスが 悪すぎるとか,そういう話もあるかと思うので,いい名前募集中です. 注意: - rb_thread_call_with_gvl() に渡す関数の返値は VALUE だと mark されないことがあるので,VALUE の受け渡しは基本的にしない  ちなみに,[ruby-dev:37448] で示した解決策は穴があって,xmalloc したメ モリは xfree しなければならないという制約があります.なので,以下のよう にするのがよいのではないかと思います. (a) malloc 試行 -> 失敗 (b) rb_thread_call_with_gvl() を使って GC を強制発生 (c) malloc 試行 -> 失敗 (d) C レベルでの資源を回収(後始末) (e) rb_thread_call_with_gvl() で呼び出した関数中で NoMemoryError 発生 Index: vm_core.h =================================================================== --- vm_core.h (リビジョン 20894) +++ vm_core.h (作業コピー) @@ -363,6 +363,7 @@ typedef struct rb_thread_struct int slice; native_thread_data_t native_thread_data; + void *blocking_region_buffer; VALUE thgroup; VALUE value; Index: thread.c =================================================================== --- thread.c (リビジョン 20894) +++ thread.c (作業コピー) @@ -947,6 +947,7 @@ static inline void blocking_region_begin(rb_thread_t *th, struct rb_blocking_region_buffer *region, rb_unblock_function_t *func, void *arg) { + th->blocking_region_buffer = region; region->prev_status = th->status; set_unblock_function(th, func, arg, ®ion->oldubf); th->status = THREAD_STOPPED; @@ -1033,6 +1034,32 @@ rb_thread_blocking_region( }, ubf, data2); return val; +} + +/* alias of rb_thread_blocking_region() */ +VALUE +rb_thread_call_without_gvl( + rb_blocking_function_t *func, void *data1, + rb_unblock_function_t *ubf, void *data2) +{ + return rb_thread_blocking_region(func, data1, ubf, data2); +} + +void * +rb_thread_call_with_gvl(void *(*func)(void *), void *data1) +{ + rb_thread_t *th = ruby_thread_from_native(); + struct rb_blocking_region_buffer *brb = + (struct rb_blocking_region_buffer *)th->blocking_region_buffer; + struct rb_unblock_callback prev_unblock = th->unblock; + void *r; + + blocking_region_end(th, brb); + /* enter to the Ruby world */ + r = (*func)(data1); + /* levae from Ruby world */ + blocking_region_begin(th, brb, prev_unblock.func, prev_unblock.arg); + return r; } /* -- // SASADA Koichi at atdot dot net