summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormame <mame@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-02-23 16:20:06 +0000
committermame <mame@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-02-23 16:20:06 +0000
commitc55dd9b7d8cf71f62709dab492f4221f090a6a79 (patch)
tree4de67f5809f04b800ca09e16f671fcdde88d41dc
parent7019187067b9cc611f09ccf1445f484d9f609e2d (diff)
* thread.c (thread_cleanup_func): unlock all locked mutexes even when
forking. [ruby-core:22269] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@22577 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog5
-rw-r--r--bootstraptest/test_thread.rb12
-rw-r--r--thread.c22
3 files changed, 28 insertions, 11 deletions
diff --git a/ChangeLog b/ChangeLog
index 944b258d365..8c08e154452 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Tue Feb 24 01:19:38 2009 Yusuke Endoh <mame@tsg.ne.jp>
+
+ * thread.c (thread_cleanup_func): unlock all locked mutexes even when
+ forking. [ruby-core:22269]
+
Tue Feb 24 00:54:16 2009 Yukihiro Matsumoto <matz@ruby-lang.org>
* insns.def (opt_minus): inline float operation.
diff --git a/bootstraptest/test_thread.rb b/bootstraptest/test_thread.rb
index ce90737ebfd..e586ee274e7 100644
--- a/bootstraptest/test_thread.rb
+++ b/bootstraptest/test_thread.rb
@@ -216,6 +216,18 @@ assert_equal 'true', %{
end
}
+assert_equal 'ok', %{
+ open("zzz.rb", "w") do |f|
+ f.puts <<-END
+ Thread.new { fork { GC.start } }.join
+ pid, status = Process.wait2
+ $result = status.success? ? :ok : :ng
+ END
+ end
+ require "zzz.rb"
+ $result
+}
+
assert_finish 3, %{
th = Thread.new {sleep 2}
th.join(1)
diff --git a/thread.c b/thread.c
index f18dbcac942..38e46c3daa8 100644
--- a/thread.c
+++ b/thread.c
@@ -291,7 +291,7 @@ typedef struct rb_mutex_struct
struct rb_mutex_struct *next_mutex;
} mutex_t;
-static void rb_mutex_unlock_all(mutex_t *mutex);
+static void rb_mutex_unlock_all(mutex_t *mutex, rb_thread_t *th);
void
rb_thread_terminate_all(void)
@@ -305,7 +305,7 @@ rb_thread_terminate_all(void)
/* unlock all locking mutexes */
if (th->keeping_mutexes) {
- rb_mutex_unlock_all(th->keeping_mutexes);
+ rb_mutex_unlock_all(th->keeping_mutexes, GET_THREAD());
}
thread_debug("rb_thread_terminate_all (main thread: %p)\n", (void *)th);
@@ -339,6 +339,12 @@ static void
thread_cleanup_func(void *th_ptr)
{
rb_thread_t *th = th_ptr;
+
+ /* unlock all locking mutexes */
+ if (th->keeping_mutexes) {
+ rb_mutex_unlock_all(th->keeping_mutexes, th);
+ th->keeping_mutexes = NULL;
+ }
thread_cleanup_func_before_exec(th_ptr);
native_thread_destroy(th);
}
@@ -434,12 +440,6 @@ thread_start_func_2(rb_thread_t *th, VALUE *stack_start, VALUE *register_stack_s
(void *)th, th->locking_mutex);
}
- /* unlock all locking mutexes */
- if (th->keeping_mutexes) {
- rb_mutex_unlock_all(th->keeping_mutexes);
- th->keeping_mutexes = NULL;
- }
-
/* delete self other than main thread from living_threads */
if (th != main_th) {
st_delete_wrap(th->vm->living_threads, th->self);
@@ -457,7 +457,6 @@ thread_start_func_2(rb_thread_t *th, VALUE *stack_start, VALUE *register_stack_s
}
join_th = join_th->join_list_next;
}
- if (th != main_th) rb_check_deadlock(th->vm);
if (!th->root_fiber) {
rb_thread_recycle_stack_release(th->stack);
@@ -465,6 +464,7 @@ thread_start_func_2(rb_thread_t *th, VALUE *stack_start, VALUE *register_stack_s
}
}
thread_cleanup_func(th);
+ if (th != main_th) rb_check_deadlock(th->vm);
if (th->vm->main_thread == th) {
ruby_cleanup(state);
}
@@ -3146,7 +3146,7 @@ rb_mutex_unlock(VALUE self)
}
static void
-rb_mutex_unlock_all(mutex_t *mutexes)
+rb_mutex_unlock_all(mutex_t *mutexes, rb_thread_t *th)
{
const char *err;
mutex_t *mutex;
@@ -3156,7 +3156,7 @@ rb_mutex_unlock_all(mutex_t *mutexes)
/* rb_warn("mutex #<%p> remains to be locked by terminated thread",
mutexes); */
mutexes = mutex->next_mutex;
- err = mutex_unlock(mutex, GET_THREAD());
+ err = mutex_unlock(mutex, th);
if (err) rb_bug("invalid keeping_mutexes: %s", err);
}
}