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)
1
Mon Oct  4 18:14:47 2010  Mark Somerville  <mark@scottishclimbs.com>
2

  
3
	* process.c, signal.c, test/ruby/test_signal.rb,
4
	  test/thread/test_timer_thread.rb: use the timer thread only when
5
	  needed to schedule Ruby threads [bug #3436].
6

  
1 7
Mon Oct  4 12:43:47 2010  Nobuyoshi Nakada  <nobu@ruby-lang.org>
2 8

  
3 9
	* parse.y (regexp): dregexp has literal string only at the head
thread.c (working copy)
402 402
static VALUE rb_threadptr_raise(rb_thread_t *, int, VALUE *);
403 403
void rb_thread_recycle_stack_release(VALUE *);
404 404

  
405
static int
406
vm_living_thread_num(rb_vm_t *vm)
407
{
408
    return vm->living_threads->num_entries;
409
}
410

  
405 411
void
412
rb_thread_start_timer_thread(void)
413
{
414
    system_working = 1;
415
    if (vm_living_thread_num(GET_VM()) > 1) {
416
        rb_thread_create_timer_thread();
417
    }
418
}
419

  
420
void
406 421
ruby_thread_init_stack(rb_thread_t *th)
407 422
{
408 423
    native_thread_init_stack(th);
......
562 577
	th->status = THREAD_KILLED;
563 578
	rb_raise(rb_eThreadError, "can't create Thread (%d)", err);
564 579
    }
580
    rb_thread_start_timer_thread();
565 581
    return thval;
566 582
}
567 583

  
......
577 593
	rb_raise(rb_eThreadError, "uninitialized thread - check `%s#initialize'",
578 594
		 rb_class2name(klass));
579 595
    }
596
    rb_thread_start_timer_thread();
580 597
    return thread;
581 598
}
582 599

  
......
629 646
    return thread_create_core(rb_thread_alloc(rb_cThread), (VALUE)arg, fn);
630 647
}
631 648

  
632

  
633 649
/* +infty, for this purpose */
634 650
#define DELAY_INFTY 1E30
635 651

  
......
711 727
    thread_debug("thread_join: success (thid: %p)\n",
712 728
		 (void *)target_th->thread_id);
713 729

  
730
    rb_disable_interrupt();
731
    if (vm_living_thread_num(th->vm) == 1 && rb_signal_buff_size() == 0) {
732
        rb_thread_stop_timer_thread();
733
    }
734
    rb_enable_interrupt();
735

  
714 736
    if (target_th->errinfo != Qnil) {
715 737
	VALUE err = target_th->errinfo;
716 738

  
......
2107 2129
    return ST_CONTINUE;
2108 2130
}
2109 2131

  
2110
static int
2111
vm_living_thread_num(rb_vm_t *vm)
2112
{
2113
    return vm->living_threads->num_entries;
2114
}
2115

  
2116 2132
int
2117 2133
rb_thread_alone(void)
2118 2134
{
......
2719 2735
    native_reset_timer_thread();
2720 2736
}
2721 2737

  
2722
void
2723
rb_thread_start_timer_thread(void)
2724
{
2725
    system_working = 1;
2726
    rb_thread_create_timer_thread();
2727
}
2728

  
2729 2738
static int
2730 2739
clear_coverage_i(st_data_t key, st_data_t val, st_data_t dummy)
2731 2740
{
......
4262 4271
	}
4263 4272
    }
4264 4273

  
4265
    rb_thread_create_timer_thread();
4274
    rb_thread_start_timer_thread();
4266 4275

  
4267 4276
    (void)native_mutex_trylock;
4268 4277
}
process.c (working copy)
998 998
#define before_exec() \
999 999
    (rb_enable_interrupt(), (void)(forked_child ? 0 : (rb_thread_stop_timer_thread(), 1)))
1000 1000
#define after_exec() \
1001
  (rb_thread_reset_timer_thread(), rb_thread_start_timer_thread(), forked_child = 0, rb_disable_interrupt())
1001
  (rb_thread_reset_timer_thread(), rb_thread_start_timer_thread(), forked_child = 0)
1002 1002
#define before_fork() before_exec()
1003 1003
#define after_fork() (GET_THREAD()->thrown_errinfo = 0, after_exec())
1004 1004

  
test/ruby/test_signal.rb (working copy)
181 181
    w.close
182 182
    assert_equal(r.read, "foo")
183 183
  end
184

  
185
  def test_signals_before_and_after_timer_thread
186
    count = 0
187
    Signal.trap(:USR1) { count += 1 }
188

  
189
    Process.kill :USR1, Process.pid
190
    assert_equal 1, count
191

  
192
    th = Thread.new { sleep 0.5 }
193
    Process.kill :USR1, Process.pid
194
    assert_equal 2, count
195

  
196
    th.join
197
    Process.kill :USR1, Process.pid
198
    assert_equal 3, count
199
  end
184 200
end
test/thread/test_timer_thread.rb (revision 0)
1
require 'test/unit'
2
require 'thread'
3

  
4
class TestTimerThread < Test::Unit::TestCase
5
  def number_of_lwps
6
    `ps -o nlwp #{Process.pid} | tail -n1`.strip.to_i
7
  end
8

  
9
  def test_timer_is_created_and_destroyed
10
    # TODO: enable this test on other platforms
11
    return if /linux/ !~ RUBY_PLATFORM
12

  
13
    assert_equal 1, number_of_lwps
14

  
15
    th = Thread.new { sleep 0.1 }
16
    assert_equal 3, number_of_lwps
17

  
18
    th.join
19
    assert_equal 1, number_of_lwps
20
  end
21
end
signal.c (working copy)
519 519
#if !defined(BSD_SIGNAL) && !defined(POSIX_SIGNAL)
520 520
    ruby_signal(sig, sighandler);
521 521
#endif
522

  
523
    rb_vm_t *vm = GET_VM();
524
    if (vm->running_thread == vm->main_thread) {
525
        rb_threadptr_check_signal(vm->main_thread);
526
    }
522 527
}
523 528

  
524 529
int