[#47790] [ruby-trunk - Bug #7097][Open] Thread locals don't work inside Enumerator — "tenderlovemaking (Aaron Patterson)" <aaron@...>

32 messages 2012/10/01
[#47791] [ruby-trunk - Bug #7097][Assigned] Thread locals don't work inside Enumerator — "kosaki (Motohiro KOSAKI)" <kosaki.motohiro@...> 2012/10/01

[#47792] Re: [ruby-trunk - Bug #7097][Assigned] Thread locals don't work inside Enumerator — Aaron Patterson <tenderlove@...> 2012/10/01

On Tue, Oct 02, 2012 at 03:05:17AM +0900, kosaki (Motohiro KOSAKI) wrote:

[#47798] Re: [ruby-trunk - Bug #7097][Assigned] Thread locals don't work inside Enumerator — SASADA Koichi <ko1@...> 2012/10/01

(2012/10/02 3:12), Aaron Patterson wrote:

[#47800] Re: [ruby-trunk - Bug #7097][Assigned] Thread locals don't work inside Enumerator — SASADA Koichi <ko1@...> 2012/10/01

(2012/10/02 8:22), SASADA Koichi wrote:

[#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@...>

18 messages 2012/10/04

[#47847] [ruby-trunk - Bug #7110][Open] CGI: Add support for HTML5 <header> tag — "stomar (Marcus Stollsteimer)" <redmine@...>

16 messages 2012/10/05

[#47870] [ruby-trunk - Bug #7123][Open] Segmentation fault in ruby 1.9.3-p194 — "mscottford (M. Scott Ford)" <scott@...>

13 messages 2012/10/09

[#47880] [ruby-trunk - Bug #7134][Open] Signal handling bug in Mac OS X — "auastro (Andy Kitchen)" <kitchen.andy+rubybug@...>

17 messages 2012/10/10

[#47881] [ruby-trunk - Bug #7135][Open] GC bug in Ruby 1.9.3-p194? — "alexdowad (Alex Dowad)" <alexinbeijing@...>

21 messages 2012/10/10

[#47887] [ruby-trunk - Bug #7137][Open] Date.parse overly lenient when attempting to parse Monday? — "garysweaver (Gary Weaver)" <garysweaver@...>

12 messages 2012/10/10

[#47930] [ruby-trunk - Feature #7148][Open] Improved Tempfile w/o DelegateClass — "Glass_saga (Masaki Matsushita)" <glass.saga@...>

14 messages 2012/10/12

[#47970] [ruby-trunk - Bug #7158][Open] require is slow in its bookkeeping; can make Rails startup 2.2x faster — "gregprice (Greg Price)" <price@...>

30 messages 2012/10/14

[#48027] [Backport93 - Backport #7172][Open] [[Ruby 1.9:]] fix rbconfig for --enable-load-relative (v2) — "mpapis (Michal Papis)" <mpapis@...>

13 messages 2012/10/16

[#48053] [ruby-trunk - Bug #7180][Open] set_trace_func with error in proc block locks up Ruby with 100% cpu usage and no way to exit without killing proc — "garysweaver (Gary Weaver)" <garysweaver@...>

8 messages 2012/10/17

[#48072] [ruby-trunk - Bug #7184][Open] --disable-gems commandline parameter does not show up with ruby -h — "steenslag (siep korteling)" <s.korteling@...>

10 messages 2012/10/18

[#48130] [ruby-trunk - Bug #7200][Open] Setting external encoding with BOM| — "brixen (Brian Ford)" <brixen@...>

14 messages 2012/10/21

[#48191] [ANN] 2.0.0 feature freeze — Yusuke Endoh <mame@...>

Japanese later; 日本語は後で

37 messages 2012/10/24
[#48696] Re: [ANN] 2.0.0 feature freeze — SASADA Koichi <ko1@...> 2012/11/01

(2012/10/24 5:39), Yusuke Endoh wrote:

[#48260] [ruby-trunk - Bug #7214][Open] Ruby 2.0 breaks support for some debugging tools — "banister (john mair)" <jrmair@...>

22 messages 2012/10/25

[#48315] [ruby-trunk - Bug #7220][Open] StringIO#initialize_copy causes aliasing between the objects — "brixen (Brian Ford)" <brixen@...>

13 messages 2012/10/26

[#48413] [ruby-trunk - Bug #7221][Open] Unable to compile kgio under 1.9.3 with error: ruby-1.9.3-<plvl>/lib/ruby/1.9.1/mkmf.rb:597:in `Integer': can't convert nil into Integer (TypeError) — "davidderyldowney (David Deryl Downey)" <me@...>

9 messages 2012/10/27

[#48549] [ruby-trunk - Feature #7240][Open] Inheritable #included/#extended Hooks For Modules — "apotonick (Nick Sutterer)" <apotonick@...>

14 messages 2012/10/29

[#48551] [ruby-trunk - Feature #7241][Open] Enumerable#to_h proposal — "nathan.f77 (Nathan Broadbent)" <nathan.f77@...>

23 messages 2012/10/29

[#48552] [ruby-trunk - Bug #7242][Open] Bignum mathematical accuracy regression in r31695 — "mhall (Matthew Hall)" <mhall@...>

11 messages 2012/10/29

[ruby-core:47770] [ruby-trunk - Feature #17] deadlock detection for 1.9

From: "fahmisetiawan (Fahmi Setiawan)" <fahmisetiawand@...>
Date: 2012-10-01 11:01:17 UTC
List: ruby-core #47770
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/

In This Thread

Prev Next