Permalink
Browse files

Fix fast-thread leak @ http://code.google.com/p/rubyenterpriseedition…

  • Loading branch information...
1 parent 3721d05 commit 5f56ad6f17f31b86a966736fb9c730a40dbb30b1 @rgbenson rgbenson committed Feb 12, 2011
Showing with 105 additions and 0 deletions.
  1. +9 −0 b/source/stack_free_safe.sh
  2. +96 −0 eval.c
@@ -0,0 +1,9 @@
+#!/bin/bash
+set -x
+
+set -e; make optflags='-DSTACK_FREE_SAFE_DEBUG=1' && sudo make install; set +e
+#set -e; make optflags='-DXXXSTACK_FREE_SAFE_DEBUG=1' && sudo make install; set +e
+PATH="/cnu/PACKAGES/ruby-ree-1.8.7-p253-thread-2-debian5/bin:$PATH" make test-all 2>&1 | tee log.txt
+
+grep 'calling stack_free' log.txt | wc -l
+grep 'calling stack_free' log.txt | grep stack_free_safe_all_dead_threads | wc -l
View
96 eval.c
@@ -1141,6 +1141,20 @@ rb_thread_t rb_main_thread;
#define main_thread rb_main_thread
#define curr_thread rb_curr_thread
+
+#ifndef STACK_FREE_SAFE_DEBUG
+#define STACK_FREE_SAFE_DEBUG 0
+#endif
+
+#if STACK_FREE_SAFE_DEBUG
+#define stack_free_safe(TH,MSG) _stack_free_safe(TH,MSG)
+#else
+#define stack_free_safe(TH,MSG) _stack_free_safe(TH)
+#endif
+
+
+static void stack_free_safe_all_dead_threads();
+
static void scope_dup _((struct SCOPE *));
#define POP_SCOPE() \
@@ -10999,6 +11013,9 @@ rb_thread_restore_context_0(rb_thread_t th, int exit)
static int ex;
static VALUE tval;
+ /* Free any dead thread's stk_ptr. */
+ stack_free_safe_all_dead_threads();
+
rb_trap_immediate = 0; /* inhibit interrupts from here */
if (ruby_sandbox_restore != NULL) {
ruby_sandbox_restore(th);
@@ -11130,12 +11147,57 @@ rb_thread_ready(th)
}
}
+static
+rb_thread_t dead_thread_needs_stack_free = 0;
+
+static
+int dead_threads_need_stack_free = 0;
+
+static int
+_stack_free_safe (th
+#if STACK_FREE_SAFE_DEBUG
+ , msg
+#endif
+ )
+ rb_thread_t th;
+#if STACK_FREE_SAFE_DEBUG
+ const char *msg;
+#endif
+{
+ if ( th->status == THREAD_KILLED && th->stk_ptr ) {
+ void *sp = (void*) &th;
+#if STACK_FREE_SAFE_DEBUG
+ fprintf(stderr, "\n%s: stack_free_safe(%p): sp (%p): stk [%p, %p): ",
+ msg, th, sp, th->stk_ptr, th->stk_ptr + th->stk_size);
+#endif
+ if ( (void*) th->stk_ptr <= sp && sp < (void*) (th->stk_ptr + th->stk_size) ) {
+#if STACK_FREE_SAFE_DEBUG
+ fprintf(stderr, " cannot call stack_free(), yet. \n");
+ fflush(stderr);
+#endif
+ dead_thread_needs_stack_free = th;
+ ++ dead_threads_need_stack_free;
+ } else {
+#if STACK_FREE_SAFE_DEBUG
+ fprintf(stderr, " calling stack_free(). \n");
+ fflush(stderr);
+#endif
+ if ( dead_thread_needs_stack_free == th )
+ dead_thread_needs_stack_free = 0;
+ stack_free(th);
+ return 1; /* stack freed. */
+ }
+ }
+ return 0; /* stack not freed */
+}
+
static void
rb_thread_die(th)
rb_thread_t th;
{
th->thgroup = 0;
th->status = THREAD_KILLED;
+ stack_free_safe(th, "rb_thread_die");
}
static void
@@ -13145,6 +13207,40 @@ rb_thread_wait_other_threads()
}
}
+static void
+stack_free_safe_all_dead_threads()
+{
+ if ( dead_threads_need_stack_free ) {
+ rb_thread_t curr, th;
+ int left = dead_threads_need_stack_free;
+
+#if STACK_FREE_SAFE_DEBUG
+ fprintf(stderr, "\nstack_free_safe_all_dead_threads(): %d\n", dead_threads_need_stack_free);
+ fflush(stderr);
+#endif
+
+ /* stack_free_safe() will increment this flag if stack_free_safe(th) cannot call stack_free(). */
+ dead_threads_need_stack_free = 0;
+
+ /*
+ ** Check the last known dead thread that needs stack_free().
+ ** That thread might have been rb_thread_remove()'ed from the thread ring.
+ ** Otherwise, start after current thread's stk_ptr, it should not be freeable anyway.
+ */
+ if ( th = dead_thread_needs_stack_free ) {
+ if ( stack_free_safe(th, "stack_free_safe_all_dead_threads") )
+ if ( -- left <= 0 ) return;
+ }
+
+ curr = curr_thread;
+ FOREACH_THREAD_FROM(curr, th) {
+ if ( stack_free_safe(th, "stack_free_safe_all_dead_threads") )
+ if ( -- left <= 0 ) return;
+ }
+ END_FOREACH_FROM(curr, th);
+ }
+}
+
static void
rb_thread_cleanup()
{

0 comments on commit 5f56ad6

Please sign in to comment.