Project

General

Profile

Feature #3436 » bug_3436-spawn_the_timer_thread_lazily.patch

A patch against trunk to add this feature - Spakman (Mark Somerville), 10/05/2010 03:09 AM

View differences:

ChangeLog (working copy)
Mon Oct 4 18:14:47 2010 Mark Somerville <mark@scottishclimbs.com>
* process.c, signal.c, test/ruby/test_signal.rb,
test/thread/test_timer_thread.rb: use the timer thread only when
needed to schedule Ruby threads [bug #3436].
Mon Oct 4 12:43:47 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
* parse.y (regexp): dregexp has literal string only at the head
thread.c (working copy)
static VALUE rb_threadptr_raise(rb_thread_t *, int, VALUE *);
void rb_thread_recycle_stack_release(VALUE *);
static int
vm_living_thread_num(rb_vm_t *vm)
{
return vm->living_threads->num_entries;
}
void
rb_thread_start_timer_thread(void)
{
system_working = 1;
if (vm_living_thread_num(GET_VM()) > 1) {
rb_thread_create_timer_thread();
}
}
void
ruby_thread_init_stack(rb_thread_t *th)
{
native_thread_init_stack(th);
......
th->status = THREAD_KILLED;
rb_raise(rb_eThreadError, "can't create Thread (%d)", err);
}
rb_thread_start_timer_thread();
return thval;
}
......
rb_raise(rb_eThreadError, "uninitialized thread - check `%s#initialize'",
rb_class2name(klass));
}
rb_thread_start_timer_thread();
return thread;
}
......
return thread_create_core(rb_thread_alloc(rb_cThread), (VALUE)arg, fn);
}
/* +infty, for this purpose */
#define DELAY_INFTY 1E30
......
thread_debug("thread_join: success (thid: %p)\n",
(void *)target_th->thread_id);
rb_disable_interrupt();
if (vm_living_thread_num(th->vm) == 1 && rb_signal_buff_size() == 0) {
rb_thread_stop_timer_thread();
}
rb_enable_interrupt();
if (target_th->errinfo != Qnil) {
VALUE err = target_th->errinfo;
......
return ST_CONTINUE;
}
static int
vm_living_thread_num(rb_vm_t *vm)
{
return vm->living_threads->num_entries;
}
int
rb_thread_alone(void)
{
......
native_reset_timer_thread();
}
void
rb_thread_start_timer_thread(void)
{
system_working = 1;
rb_thread_create_timer_thread();
}
static int
clear_coverage_i(st_data_t key, st_data_t val, st_data_t dummy)
{
......
}
}
rb_thread_create_timer_thread();
rb_thread_start_timer_thread();
(void)native_mutex_trylock;
}
process.c (working copy)
#define before_exec() \
(rb_enable_interrupt(), (void)(forked_child ? 0 : (rb_thread_stop_timer_thread(), 1)))
#define after_exec() \
(rb_thread_reset_timer_thread(), rb_thread_start_timer_thread(), forked_child = 0, rb_disable_interrupt())
(rb_thread_reset_timer_thread(), rb_thread_start_timer_thread(), forked_child = 0)
#define before_fork() before_exec()
#define after_fork() (GET_THREAD()->thrown_errinfo = 0, after_exec())
test/ruby/test_signal.rb (working copy)
w.close
assert_equal(r.read, "foo")
end
def test_signals_before_and_after_timer_thread
count = 0
Signal.trap(:USR1) { count += 1 }
Process.kill :USR1, Process.pid
assert_equal 1, count
th = Thread.new { sleep 0.5 }
Process.kill :USR1, Process.pid
assert_equal 2, count
th.join
Process.kill :USR1, Process.pid
assert_equal 3, count
end
end
test/thread/test_timer_thread.rb (revision 0)
require 'test/unit'
require 'thread'
class TestTimerThread < Test::Unit::TestCase
def number_of_lwps
`ps -o nlwp #{Process.pid} | tail -n1`.strip.to_i
end
def test_timer_is_created_and_destroyed
# TODO: enable this test on other platforms
return if /linux/ !~ RUBY_PLATFORM
assert_equal 1, number_of_lwps
th = Thread.new { sleep 0.1 }
assert_equal 3, number_of_lwps
th.join
assert_equal 1, number_of_lwps
end
end
signal.c (working copy)
#if !defined(BSD_SIGNAL) && !defined(POSIX_SIGNAL)
ruby_signal(sig, sighandler);
#endif
rb_vm_t *vm = GET_VM();
if (vm->running_thread == vm->main_thread) {
rb_threadptr_check_signal(vm->main_thread);
}
}
int
(1-1/5)