[#47787] Ruby Parallelism — Miguel Palhas <mpalhas@...>
Greetings
[#47790] [ruby-trunk - Bug #7097][Open] Thread locals don't work inside Enumerator — "tenderlovemaking (Aaron Patterson)" <aaron@...>
I don't have any objection.
On Fri, Oct 26, 2012 at 02:40:53PM +0900, SASADA Koichi wrote:
On Tue, Oct 02, 2012 at 03:05:17AM +0900, kosaki (Motohiro KOSAKI) wrote:
(2012/10/02 3:12), Aaron Patterson wrote:
(2012/10/02 8:22), SASADA Koichi wrote:
On Tue, Oct 02, 2012 at 08:32:51AM +0900, SASADA Koichi wrote:
>> For example:
[#47832] [ruby-trunk - Feature #7106][Open] FileUtils.touch should allow touching the symlink itself rather than the file the link points to — "cirrusthinking (Alessandro Diaferia)" <alessandro@...>
[#47841] [ruby-trunk - Bug #7109][Open] File.utime doesn't set nanoseconds — "bkabrda (Bohuslav Kabrda)" <bkabrda@...>
2012/10/5 bkabrda (Bohuslav Kabrda) <bkabrda@redhat.com>:
[#47847] [ruby-trunk - Bug #7110][Open] CGI: Add support for HTML5 <header> tag — "stomar (Marcus Stollsteimer)" <redmine@...>
[#47880] [ruby-trunk - Bug #7134][Open] Signal handling bug in Mac OS X — "auastro (Andy Kitchen)" <kitchen.andy+rubybug@...>
[#47881] [ruby-trunk - Bug #7135][Open] GC bug in Ruby 1.9.3-p194? — "alexdowad (Alex Dowad)" <alexinbeijing@...>
[#47887] [ruby-trunk - Bug #7137][Open] Date.parse overly lenient when attempting to parse Monday? — "garysweaver (Gary Weaver)" <garysweaver@...>
[#47927] new ruby 1.9.3 maintainer — "U.Nakamura" <usa@...>
Hello everyone of the Ruby development community
[#47930] [ruby-trunk - Feature #7148][Open] Improved Tempfile w/o DelegateClass — "Glass_saga (Masaki Matsushita)" <glass.saga@...>
[#47963] [ruby-trunk - Bug #7154][Open] For whatever reason \s doesn't match \u00a0. — "t0d0r (Todor Dragnev)" <todor.dragnev@...>
[#47970] [ruby-trunk - Bug #7158][Open] require is slow in its bookkeeping; can make Rails startup 2.2x faster — "gregprice (Greg Price)" <price@...>
(2012/10/28 7:10), h.shirosaki (Hiroshi Shirosaki) wrote:
Thank you for the careful work.
[#48032] [Backport93 - Backport #7174][Open] Advocating for backporting 36811 — "jonforums (Jon Forums)" <redmine@...>
[#48040] Should Hash#dup automatically rehash — Aaron Patterson <tenderlove@...>
Hi,
Hello,
On Wed, Oct 17, 2012 at 11:21:15AM +0900, U.Nakamura wrote:
[#48072] [ruby-trunk - Bug #7184][Open] --disable-gems commandline parameter does not show up with ruby -h — "steenslag (siep korteling)" <s.korteling@...>
[#48132] [ruby-trunk - Bug #7201][Open] Setting default_external affects STDIN encoding but default_internal does not — "brixen (Brian Ford)" <brixen@...>
[#48154] Patch to test_ssl to validate server-side support for SNI — Patrick Toomey <ptoomey3@...>
I recently made a pull request to JRuby (
We have incorporated Patrick's SNI patch for upcoming release JRuby
[#48191] [ANN] 2.0.0 feature freeze — Yusuke Endoh <mame@...>
Japanese later; 日本語は後で
Em 24-10-2012 09:39, Yusuke Endoh escreveu:
(2012/10/24 5:39), Yusuke Endoh wrote:
Hello ko1,
Hi,
AFAIK matz has not accepted #6636 completely yet.
Sorry, late to the party, but what's the status of #6679?
What status of #6638 <https://bugs.ruby-lang.org/issues/6638>
[#48260] [ruby-trunk - Bug #7214][Open] Ruby 2.0 breaks support for some debugging tools — "banister (john mair)" <jrmair@...>
[#48292] [ruby-trunk - Bug #7216][Open] object.c defines clone method for objects that cannot be cloned. — "therevmj (Michael Johnson)" <mj@...>
[#48315] [ruby-trunk - Bug #7220][Open] StringIO#initialize_copy causes aliasing between the objects — "brixen (Brian Ford)" <brixen@...>
[#48475] [ruby-trunk - Feature #3222] Can bignums have singleton class & methods? — "matz (Yukihiro Matsumoto)" <matz@...>
(2012/10/27 23:25), matz (Yukihiro Matsumoto) wrote:
[#48551] [ruby-trunk - Feature #7241][Open] Enumerable#to_h proposal — "nathan.f77 (Nathan Broadbent)" <nathan.f77@...>
On Tue, Oct 30, 2012 at 07:58:33PM +0900, rosenfeld (Rodrigo Rosenfeld Rosas) wrote:
Em 30-10-2012 16:23, Aaron Patterson escreveu:
[#48679] [ruby-trunk - Feature #905] Add String.new(fixnum) to preallocate large buffer — "headius (Charles Nutter)" <headius@...>
[ruby-core:47770] [ruby-trunk - Feature #17] deadlock detection for 1.9
Issue #17 has been updated by fahmisetiawan (Fahmi Setiawan).
http://alkian.blogspot.com/2012/09/cara-menyembuhkan-asam-urat-dan-kolestrol-secara-alami.html
http://alkian.blogspot.com/2012/09/keretamini-keretamall-komediputar-ya-keretaminikucom.html
http://alkian.blogspot.com/2012/09/harga-spesifikasi-samsung-galaxy-y-duos-terbaru.html
http://alkian.blogspot.com/2012/09/download-one-piece-grand-battle-2.html
http://alkian.blogspot.com/2012/09/harga-dan-spesifikasi-toyota-agya.html
http://alkian.blogspot.com/2012/09/harga-dan-spesifikasi-daihatsu-ayla.html
http://alkian.blogspot.com/2012/09/download-harvestmoon-backtonature-bahasa-indonesia.html
http://alkian.blogspot.com/2012/09/download-gratis-game-onet-untuk-windows.html
http://alkian.blogspot.com/2012/09/cara-download-dengan-jumbofiles.html
http://alkian.blogspot.com/2012/09/cara-mengganti-bahasa-indonesia-di-blackbery.html
http://alkian.blogspot.com/2012/09/free-download-windows-xp-sp3-black-edition-terbaru-full-version-2012.html
http://alkian.blogspot.com/2012/09/free-download-kamus-bahasa-arab.html
http://alkian.blogspot.com/2012/09/free-download-corel-draw-x5-portable.html
http://alkian.blogspot.com/2012/09/cara-membuat-related-post-artikel-terkait.html
http://alkian.blogspot.com/2012/09/daftar-harga-lengkap-hp-mito-terbaru.html
http://alkian.blogspot.com/2012/09/download-theme-tron-legacy-for-windows-7.html
http://alkian.blogspot.com/2012/09/download-alquran-digital-3d-untuk-pc-komputer.html
http://alkian.blogspot.com/2012/09/kumpulan-kata-kata-renungan-terbaik-2012.html
http://alkian.blogspot.com/2012/09/kumpulan-website-sosbuk-social-bookmarking.html
http://alkian.blogspot.com/2012/09/template-seo-friendly-simple-blue.html
http://alkian.blogspot.com/2012/09/harga-hp-nokia-september-2012-terbaru.html
http://alkian.blogspot.com/2012/09/foto-ariel-noah-terbaru.html
http://alkian.blogspot.com/2012/09/download-serial-number-windows-seven.html
http://alkian.blogspot.com/2012/09/biodata-foto-iqbaal-dhiafakhri-ramadhan.html
http://alkian.blogspot.com/2012/09/harga-dan-spesifikasi-samsung-galaxy-camera.html
http://alkian.blogspot.com/2012/09/biodata-akb48-lengkap-dengan-foto.html
http://alkian.blogspot.com/2012/08/arti-dan-makna-kata-noah.html
----------------------------------------
Feature #17: deadlock detection for 1.9
https://bugs.ruby-lang.org/issues/17#change-29832
Author: mame (Yusuke Endoh)
Status: Closed
Priority: Normal
Assignee: mame (Yusuke Endoh)
Category:
Target version:
=begin
遠藤です。
# redmine から投稿してみます。
1.9 のスレッドにデッドロック検出を実装してみました。
- スレッドの状態種別に THREAD_STOPPED_FOREVER を追加。
無期限の sleep 状態と mutex 解放待ち状態を表す。
- rb_vm_t に変数 sleeper を追加。
THREAD_STOPPED_FOREVER 状態のスレッドの数を表す。
- rb_thread_t に変数 locking_mutex を追加。
このスレッドが待っている mutex を表す。
- rb_thread_t に st_table *keeping_mutexes を追加。
このスレッドがロックしている mutex たちを表す。
- mutex_t に変数 cond_notified を追加。
cond_signal されてまだ起動していないスレッドの数を表す。
- スレッドの終了時にロックしていた mutex をすべて
解放するようにした。
- rb_mutex_lock や rb_mutex_unlock で追加した変数たちを
適宜更新するようにした。
- 唯一動いていそうなスレッドが native_cond_wait しそうな
時は、lock_func を抜けてデッドロック検査するようにした。
- rb_check_deadlock では vm->living_threads を列挙して、
- 例外状態のスレッド、または
- locking_mutex のロックに成功したスレッド、または
- locking_mutex が誰にもロックされていないスレッド、
のいずれもなければ main_thread にデッドロックを投げる
ようにした。
どんなもんでしょう。
Index: thread_pthread.c
===================================================================
--- thread_pthread.c (revision 16676)
+++ thread_pthread.c (working copy)
@@ -418,7 +418,14 @@
}
}
- th->status = THREAD_STOPPED;
+ if (tv) {
+ th->status = THREAD_STOPPED;
+ }
+ else {
+ th->status = THREAD_STOPPED_FOREVER;
+ th->vm->sleeper++;
+ rb_check_deadlock(th->vm);
+ }
thread_debug("native_sleep %ld\n", tv ? tv->tv_sec : -1);
GVL_UNLOCK_BEGIN();
@@ -455,9 +462,10 @@
th->unblock_function_arg = 0;
pthread_mutex_unlock(&th->interrupt_lock);
- th->status = prev_status;
}
GVL_UNLOCK_END();
+ th->status = prev_status;
+ if (!tv) th->vm->sleeper--;
RUBY_VM_CHECK_INTS();
thread_debug("native_sleep done\n");
Index: bootstraptest/test_thread.rb
===================================================================
--- bootstraptest/test_thread.rb (revision 16676)
+++ bootstraptest/test_thread.rb (working copy)
@@ -268,3 +268,66 @@
at_exit { Fiber.new{}.resume }
}
+assert_equal 'ok', %q{
+ begin
+ Thread.new { sleep }
+ sleep
+ :ng
+ rescue Exception
+ :ok
+ end
+}
+
+assert_equal 'ok', %q{
+ begin
+ m1, m2 = Mutex.new, Mutex.new
+ Thread.new { m1.lock; sleep 1; m2.lock }
+ m2.lock; sleep 1; m1.lock
+ sleep
+ :ng
+ rescue Exception
+ :ok
+ end
+}
+
+assert_equal 'ok', %q{
+ begin
+ m = Mutex.new
+ Thread.new { m.lock }; m.lock
+ :ok
+ rescue Exception
+ :ng
+ end
+}
+
+assert_equal 'ok', %q{
+ begin
+ m = Mutex.new
+ Thread.new { m.lock }.join; m.lock
+ :ok
+ rescue Exception
+ :ng
+ end
+}
+
+assert_equal 'ok', %q{
+ begin
+ m = Mutex.new
+ Thread.new { m.lock; sleep 2 }
+ sleep 1; m.lock
+ :ok
+ rescue Exception
+ :ng
+ end
+}
+
+assert_equal 'ok', %q{
+ begin
+ m = Mutex.new
+ Thread.new { m.lock; sleep 2; m.unlock }
+ sleep 1; m.lock
+ :ok
+ rescue Exception
+ :ng
+ end
+}
Index: vm_core.h
===================================================================
--- vm_core.h (revision 16676)
+++ vm_core.h (working copy)
@@ -300,6 +300,7 @@
int running;
int thread_abort_on_exception;
unsigned long trace_flag;
+ volatile int sleeper;
/* object management */
VALUE mark_object_ary;
@@ -354,6 +355,7 @@
THREAD_TO_KILL,
THREAD_RUNNABLE,
THREAD_STOPPED,
+ THREAD_STOPPED_FOREVER,
THREAD_KILLED,
};
@@ -421,6 +423,8 @@
rb_unblock_function_t *unblock_function;
void *unblock_function_arg;
rb_thread_lock_t interrupt_lock;
+ VALUE locking_mutex;
+ st_table *keeping_mutexes;
struct rb_vm_tag *tag;
struct rb_vm_trap_tag *trap_tag;
Index: thread.c
===================================================================
--- thread.c (revision 16676)
+++ thread.c (working copy)
@@ -62,6 +62,9 @@
struct timeval rb_time_interval(VALUE);
static int rb_thread_dead(rb_thread_t *th);
+static int unlock_i(st_data_t key, st_data_t val, rb_thread_t *th);
+static void rb_check_deadlock(rb_vm_t *vm);
+
void rb_signal_exec(rb_thread_t *th, int sig);
void rb_disable_interrupt(void);
@@ -92,13 +95,13 @@
rb_thread_set_current(_th_stored); \
} while(0)
-#define BLOCKING_REGION(exec, ubf, ubfarg) do { \
+#define BLOCKING_REGION(exec, ubf, ubfarg, stopped) do { \
rb_thread_t *__th = GET_THREAD(); \
int __prev_status = __th->status; \
rb_unblock_function_t *__oldubf; \
void *__oldubfarg; \
set_unblock_function(__th, ubf, ubfarg, &__oldubf, &__oldubfarg); \
- __th->status = THREAD_STOPPED; \
+ if (stopped) __th->status = THREAD_STOPPED; \
thread_debug("enter blocking region (%p)\n", __th); \
GVL_UNLOCK_BEGIN(); {\
exec; \
@@ -107,10 +110,9 @@
thread_debug("leave blocking region (%p)\n", __th); \
remove_signal_thread_list(__th); \
set_unblock_function(__th, __oldubf, __oldubfarg, 0, 0); \
- if (__th->status == THREAD_STOPPED) { \
+ if (stopped && __th->status == THREAD_STOPPED) { \
__th->status = __prev_status; \
} \
- RUBY_VM_CHECK_INTS(); \
} while(0)
#if THREAD_DEBUG
@@ -197,19 +199,11 @@
set_unblock_function(rb_thread_t *th, rb_unblock_function_t *func, void *arg,
rb_unblock_function_t **oldfunc, void **oldarg)
{
- check_ints:
- RUBY_VM_CHECK_INTS(); /* check signal or so */
native_mutex_lock(&th->interrupt_lock);
- if (th->interrupt_flag) {
- native_mutex_unlock(&th->interrupt_lock);
- goto check_ints;
- }
- else {
- if (oldfunc) *oldfunc = th->unblock_function;
- if (oldarg) *oldarg = th->unblock_function_arg;
- th->unblock_function = func;
- th->unblock_function_arg = arg;
- }
+ if (oldfunc) *oldfunc = th->unblock_function;
+ if (oldarg) *oldarg = th->unblock_function_arg;
+ th->unblock_function = func;
+ th->unblock_function_arg = arg;
native_mutex_unlock(&th->interrupt_lock);
}
@@ -259,6 +253,11 @@
thread_debug("rb_thread_terminate_all (main thread: %p)\n", th);
st_foreach(vm->living_threads, terminate_i, (st_data_t)th);
+ /* unlock all locking mutexes */
+ if (th->keeping_mutexes) {
+ st_foreach(th->keeping_mutexes, unlock_i, 0);
+ }
+
while (!rb_thread_alone()) {
PUSH_TAG();
if (EXEC_TAG() == 0) {
@@ -354,6 +353,17 @@
}
TH_POP_TAG();
+ /* locking_mutex must be Qfalse */
+ if (th->locking_mutex != Qfalse) {
+ rb_bug("thread_start_func_2: locking_mutex must be NULL (%p:%p)", th, (void*)th->locking_mutex);
+ }
+
+ /* unlock all locking mutexes */
+ if (th->keeping_mutexes) {
+ st_foreach(th->keeping_mutexes, unlock_i, 0);
+ }
+
+ /* delete self from living_threads */
st_delete_wrap(th->vm->living_threads, th->self);
/* wake up joinning threads */
@@ -363,7 +373,7 @@
rb_thread_interrupt(join_th);
join_th = join_th->join_list_next;
}
- st_delete_wrap(th->vm->living_threads, th->self);
+ rb_check_deadlock(th->vm);
if (!th->root_fiber) {
rb_thread_recycle_stack_release(th->stack);
@@ -775,7 +785,8 @@
BLOCKING_REGION({
val = func(data1);
- }, ubf, data2);
+ }, ubf, data2, 1);
+ RUBY_VM_CHECK_INTS();
return val;
}
@@ -1135,6 +1146,7 @@
switch (th->status) {
case THREAD_RUNNABLE:
case THREAD_STOPPED:
+ case THREAD_STOPPED_FOREVER:
case THREAD_TO_KILL:
rb_ary_push(ary, th->self);
default:
@@ -1329,6 +1341,7 @@
case THREAD_RUNNABLE:
return "run";
case THREAD_STOPPED:
+ case THREAD_STOPPED_FOREVER:
return "sleep";
case THREAD_TO_KILL:
return "aborting";
@@ -1428,7 +1441,7 @@
if (rb_thread_dead(th))
return Qtrue;
- if (th->status == THREAD_STOPPED)
+ if (th->status == THREAD_STOPPED || th->status == THREAD_STOPPED_FOREVER)
return Qtrue;
return Qfalse;
}
@@ -1868,14 +1881,16 @@
if (except) *except = orig_except;
wait = &wait_100ms;
} while (__th->interrupt_flag == 0 && (timeout == 0 || subst(timeout, &wait_100ms)));
- }, 0, 0);
+ }, 0, 0, 1);
+ RUBY_VM_CHECK_INTS();
} while (result == 0 && (timeout == 0 || subst(timeout, &wait_100ms)));
}
#else
BLOCKING_REGION({
result = select(n, read, write, except, timeout);
if (result < 0) lerrno = errno;
- }, ubf_select, GET_THREAD());
+ }, ubf_select, GET_THREAD(), 1);
+ RUBY_VM_CHECK_INTS();
#endif
errno = lerrno;
@@ -2070,6 +2085,7 @@
st_foreach(vm->living_threads, terminate_atfork_i, (st_data_t)th);
st_clear(vm->living_threads);
st_insert(vm->living_threads, thval, (st_data_t) th->thread_id);
+ vm->sleeper = 0;
}
static int
@@ -2096,6 +2112,7 @@
st_foreach(vm->living_threads, terminate_atfork_before_exec_i, (st_data_t)th);
st_clear(vm->living_threads);
st_insert(vm->living_threads, thval, (st_data_t) th->thread_id);
+ vm->sleeper = 0;
}
struct thgroup {
@@ -2312,7 +2329,7 @@
rb_thread_lock_t lock;
rb_thread_cond_t cond;
rb_thread_t volatile *th;
- volatile int cond_waiting;
+ volatile int cond_waiting, cond_notified;
} mutex_t;
#define GetMutexPtr(obj, tobj) \
@@ -2384,6 +2401,15 @@
return mutex->th ? Qtrue : Qfalse;
}
+static void
+mutex_locked(rb_thread_t *th, VALUE self)
+{
+ if (!th->keeping_mutexes) {
+ th->keeping_mutexes = st_init_numtable();
+ }
+ st_insert(th->keeping_mutexes, self, (st_data_t) th->thread_id);
+}
+
/*
* call-seq:
* mutex.try_lock => true or false
@@ -2406,6 +2432,8 @@
if (mutex->th == 0) {
mutex->th = GET_THREAD();
locked = Qtrue;
+
+ mutex_locked(GET_THREAD(), self);
}
native_mutex_unlock(&mutex->lock);
@@ -2413,17 +2441,23 @@
}
static int
-lock_func(rb_thread_t *th, mutex_t *mutex)
+lock_func(rb_thread_t *th, mutex_t *mutex, int last_thread)
{
int interrupted = Qfalse;
native_mutex_lock(&mutex->lock);
while (mutex->th || (mutex->th = th, 0)) {
+ if (last_thread) {
+ interrupted = 2;
+ break;
+ }
+
mutex->cond_waiting++;
native_cond_wait(&mutex->cond, &mutex->lock);
+ mutex->cond_notified--;
- if (th->interrupt_flag) {
- interrupted = Qtrue;
+ if (RUBY_VM_INTERRUPTED(th)) {
+ interrupted = 1;
break;
}
}
@@ -2438,6 +2472,7 @@
native_mutex_lock(&mutex->lock);
if (mutex->cond_waiting > 0) {
native_cond_broadcast(&mutex->cond);
+ mutex->cond_notified += mutex->cond_waiting;
mutex->cond_waiting = 0;
}
native_mutex_unlock(&mutex->lock);
@@ -2460,11 +2495,30 @@
while (mutex->th != th) {
int interrupted;
+ int prev_status = th->status;
+ int last_thread = 0;
+ th->locking_mutex = self;
+ th->status = THREAD_STOPPED_FOREVER;
+ th->vm->sleeper++;
+ if (th->vm->living_threads->num_entries == th->vm->sleeper) {
+ last_thread = 1;
+ }
+
BLOCKING_REGION({
- interrupted = lock_func(th, mutex);
- }, lock_interrupt, mutex);
+ interrupted = lock_func(th, mutex, last_thread);
+ }, lock_interrupt, mutex, 0);
+ th->locking_mutex = Qfalse;
+ if (interrupted == 2) {
+ /* assert: mutex->th != th */
+ rb_check_deadlock(th->vm);
+ }
+ th->status = prev_status;
+ th->vm->sleeper--;
+
+ if (mutex->th == th) mutex_locked(th, self);
+
if (interrupted) {
RUBY_VM_CHECK_INTS();
}
@@ -2473,15 +2527,8 @@
return self;
}
-/*
- * call-seq:
- * mutex.unlock => self
- *
- * Releases the lock.
- * Raises +ThreadError+ if +mutex+ wasn't locked by the current thread.
- */
-VALUE
-rb_mutex_unlock(VALUE self)
+static char *
+mutex_unlock(VALUE self)
{
mutex_t *mutex;
char *err = NULL;
@@ -2501,16 +2548,45 @@
/* waiting thread */
native_cond_signal(&mutex->cond);
mutex->cond_waiting--;
+ mutex->cond_notified++;
}
}
native_mutex_unlock(&mutex->lock);
+ return err;
+}
+
+/*
+ * call-seq:
+ * mutex.unlock => self
+ *
+ * Releases the lock.
+ * Raises +ThreadError+ if +mutex+ wasn't locked by the current thread.
+ */
+VALUE
+rb_mutex_unlock(VALUE self)
+{
+ char *err;
+
+ err = mutex_unlock(self);
+
+ if (!err) st_delete_wrap(GET_THREAD()->keeping_mutexes, self);
if (err) rb_raise(rb_eThreadError, err);
return self;
}
+static int
+unlock_i(st_data_t key, st_data_t val, rb_thread_t *th)
+{
+ VALUE mtxval = key;
+
+ mutex_unlock(mtxval);
+
+ return ST_CONTINUE;
+}
+
static VALUE
rb_mutex_sleep_forever(VALUE time)
{
@@ -2579,6 +2655,51 @@
return rb_ensure(func, arg, rb_mutex_unlock, mutex);
}
+static int
+check_deadlock_i(st_data_t key, st_data_t val, int *found)
+{
+ VALUE thval = key;
+ rb_thread_t *th;
+ GetThreadPtr(thval, th);
+
+ if (th->status != THREAD_STOPPED_FOREVER) {
+ rb_bug("check_deadlock_i: thread that is not THREAD_STOPPED_FOREVER found (%p:%d)", th, th->status);
+ }
+
+ if (RUBY_VM_INTERRUPTED(th)) {
+ *found = 1;
+ }
+ else if (th->locking_mutex) {
+ mutex_t *mutex;
+ GetMutexPtr(th->locking_mutex, mutex);
+
+ native_mutex_lock(&mutex->lock);
+ if (mutex->th == th || (!mutex->th && mutex->cond_notified)) {
+ *found = 1;
+ }
+ native_mutex_unlock(&mutex->lock);
+ }
+
+ return (*found) ? ST_STOP : ST_CONTINUE;
+}
+
+static void
+rb_check_deadlock(rb_vm_t *vm)
+{
+ int found = 0;
+
+ if (vm->living_threads->num_entries != vm->sleeper) return;
+
+ st_foreach(vm->living_threads, check_deadlock_i, (st_data_t)&found);
+
+ if (!found) {
+ VALUE argv[2];
+ argv[0] = rb_eFatal;
+ argv[1] = rb_str_new2("deadlock detected");
+ rb_thread_raise(2, argv, vm->main_thread);
+ }
+}
+
/*
* Document-class: Barrier
*/
Index: vm.c
===================================================================
--- vm.c (revision 16676)
+++ vm.c (working copy)
@@ -1445,6 +1445,13 @@
RUBY_FREE_UNLESS_NULL(th->stack);
}
+ if (th->locking_mutex != Qfalse) {
+ rb_bug("thread_free: locking_mutex must be NULL (%p:%d)", th, th->locking_mutex);
+ }
+ if (th->keeping_mutexes) {
+ st_free_table(th->keeping_mutexes);
+ }
+
if (th->local_storage) {
st_free_table(th->local_storage);
}
@@ -1512,6 +1519,12 @@
RUBY_MARK_UNLESS_NULL(th->root_fiber);
RUBY_MARK_UNLESS_NULL(th->stat_insn_usage);
+ RUBY_MARK_UNLESS_NULL(th->locking_mutex);
+
+ if (th->keeping_mutexes) {
+ st_foreach(th->keeping_mutexes, vm_mark_each_thread_func, 0);
+ }
+
rb_mark_tbl(th->local_storage);
if (GET_THREAD() != th && th->machine_stack_start && th->machine_stack_end) {
--
Yusuke ENDOH <mame@tsg.ne.jp>
=end
--
http://bugs.ruby-lang.org/