Bug #595 » ensure_fiber2.patch
| cont.c (working copy) | ||
|---|---|---|
|
{
|
||
|
switch(argc) {
|
||
|
case 0:
|
||
|
case -2:
|
||
|
return Qnil;
|
||
|
case 1:
|
||
|
return argv[0];
|
||
| ... | ... | |
|
rb_fiber_transfer(return_fiber(), 1, &value);
|
||
|
}
|
||
|
static VALUE
|
||
|
fiber_start_i(VALUE tag, rb_context_t *cont)
|
||
|
{
|
||
|
rb_thread_t *th = GET_THREAD();
|
||
|
rb_proc_t *proc;
|
||
|
int argc;
|
||
|
VALUE *argv, args;
|
||
|
GetProcPtr(cont->saved_thread.first_proc, proc);
|
||
|
args = cont->value;
|
||
|
argv = (argc = cont->argc) > 1 ? RARRAY_PTR(args) : &args;
|
||
|
cont->value = Qnil;
|
||
|
th->errinfo = Qnil;
|
||
|
th->root_lep = rb_vm_ep_local_ep(proc->block.ep);
|
||
|
th->root_svar = Qnil;
|
||
|
cont->value = rb_vm_invoke_proc(th, proc, proc->block.self, argc, argv, 0);
|
||
|
return Qfalse;
|
||
|
}
|
||
|
void
|
||
|
rb_fiber_start(void)
|
||
|
{
|
||
|
rb_thread_t *th = GET_THREAD();
|
||
|
rb_fiber_t *fib;
|
||
|
rb_context_t *cont;
|
||
|
rb_proc_t *proc;
|
||
|
int state;
|
||
|
GetFiberPtr(th->fiber, fib);
|
||
| ... | ... | |
|
TH_PUSH_TAG(th);
|
||
|
if ((state = EXEC_TAG()) == 0) {
|
||
|
int argc;
|
||
|
VALUE *argv, args;
|
||
|
GetProcPtr(cont->saved_thread.first_proc, proc);
|
||
|
args = cont->value;
|
||
|
argv = (argc = cont->argc) > 1 ? RARRAY_PTR(args) : &args;
|
||
|
cont->value = Qnil;
|
||
|
th->errinfo = Qnil;
|
||
|
th->root_lep = rb_vm_ep_local_ep(proc->block.ep);
|
||
|
th->root_svar = Qnil;
|
||
|
fib->status = RUNNING;
|
||
|
cont->value = rb_vm_invoke_proc(th, proc, proc->block.self, argc, argv, 0);
|
||
|
rb_catch_obj(-2, fiber_start_i, (VALUE)cont);
|
||
|
}
|
||
|
TH_POP_TAG();
|
||
| ... | ... | |
|
/* restored */
|
||
|
GetFiberPtr(th->fiber, fib);
|
||
|
if (fib->cont.argc == -1) rb_exc_raise(fib->cont.value);
|
||
|
else if (fib->cont.argc == -2) rb_throw_obj(-2, Qnil);
|
||
|
return fib->cont.value;
|
||
|
}
|
||
|
#if !FIBER_USE_NATIVE
|
||
| ... | ... | |
|
return rb_fiber_current();
|
||
|
}
|
||
|
static void
|
||
|
fiber_terminate_on_th(rb_thread_t *th, int ignore_mark)
|
||
|
{
|
||
|
VALUE fibval, current_fibval;
|
||
|
rb_fiber_t *fib, *root_fib, *prev_fiber;
|
||
|
rb_thread_t *_th = GET_THREAD();
|
||
|
fibval = th->root_fiber;
|
||
|
if (!RTEST(fibval)) return;
|
||
|
GetFiberPtr(fibval, root_fib);
|
||
|
rb_thread_set_current(th);
|
||
|
fib = root_fib->prev_fiber;
|
||
|
current_fibval = rb_fiber_current();
|
||
|
while (fib != root_fib) {
|
||
|
prev_fiber = fib->prev_fiber;
|
||
|
fibval = fib->cont.self;
|
||
|
if (fib->status == RUNNING && current_fibval != fibval) {
|
||
|
if(ignore_mark || !rb_gc_marked_p(fibval)) {
|
||
|
fib->prev = current_fibval;
|
||
|
fiber_switch(fibval, -2, 0, 0);
|
||
|
}
|
||
|
}
|
||
|
fib = prev_fiber;
|
||
|
}
|
||
|
rb_thread_set_current(_th);
|
||
|
}
|
||
|
static int
|
||
|
fiber_terminate_unused_i(st_data_t key, st_data_t val, st_data_t data)
|
||
|
{
|
||
|
rb_thread_t *th;
|
||
|
GetThreadPtr((VALUE)key, th);
|
||
|
fiber_terminate_on_th(th, FALSE);
|
||
|
return ST_CONTINUE;
|
||
|
}
|
||
|
void
|
||
|
rb_fiber_terminate_unused(void)
|
||
|
{
|
||
|
st_foreach(GET_VM()->living_threads, fiber_terminate_unused_i, 0);
|
||
|
}
|
||
|
void
|
||
|
rb_thread_terminate_fibers(rb_thread_t *th)
|
||
|
{
|
||
|
fiber_terminate_on_th(th, TRUE);
|
||
|
}
|
||
|
/*
|
||
| eval.c (working copy) | ||
|---|---|---|
|
rb_thread_t *th = GET_THREAD();
|
||
|
int nerr;
|
||
|
PUSH_TAG();
|
||
|
if ((state = EXEC_TAG()) == 0) {
|
||
|
rb_thread_terminate_fibers(th);
|
||
|
}
|
||
|
POP_TAG();
|
||
|
rb_threadptr_interrupt(th);
|
||
|
rb_threadptr_check_signal(th);
|
||
|
PUSH_TAG();
|
||
| gc.c (working copy) | ||
|---|---|---|
|
return TRUE;
|
||
|
}
|
||
|
int
|
||
|
rb_gc_marked_p(VALUE p)
|
||
|
{
|
||
|
return MARKED_IN_BITMAP(GET_HEAP_BITMAP(p), p);
|
||
|
}
|
||
|
static void
|
||
|
before_gc_sweep(rb_objspace_t *objspace)
|
||
|
{
|
||
|
int _dont_gc;
|
||
|
_dont_gc = dont_gc;
|
||
|
during_gc = 0;
|
||
|
objspace->flags.dont_lazy_sweep = 1;
|
||
|
dont_gc = 1;
|
||
|
rb_fiber_terminate_unused();
|
||
|
dont_gc = _dont_gc;
|
||
|
during_gc = 0;
|
||
|
objspace->flags.dont_lazy_sweep = 0;
|
||
|
objspace->heap.do_heap_free = (size_t)((heaps_used * HEAP_OBJ_LIMIT) * 0.65);
|
||
|
objspace->heap.free_min = (size_t)((heaps_used * HEAP_OBJ_LIMIT) * 0.2);
|
||
|
if (objspace->heap.free_min < initial_free_min) {
|
||
| internal.h (working copy) | ||
|---|---|---|
|
/* cont.c */
|
||
|
VALUE rb_obj_is_fiber(VALUE);
|
||
|
void rb_fiber_reset_root_local_storage(VALUE);
|
||
|
void rb_fiber_terminate_unused(void);
|
||
|
/* debug.c */
|
||
|
PRINTF_ARGS(void ruby_debug_printf(const char*, ...), 1, 2);
|
||
| ... | ... | |
|
/* gc.c */
|
||
|
void Init_heap(void);
|
||
|
void *ruby_mimmalloc(size_t size);
|
||
|
int rb_gc_marked_p(VALUE);
|
||
|
/* inits.c */
|
||
|
void rb_call_inits(void);
|
||
| test/ruby/test_fiber.rb (working copy) | ||
|---|---|---|
|
assert_equal(0, status.exitstatus, bug5700)
|
||
|
assert_equal(false, status.signaled?, bug5700)
|
||
|
end
|
||
|
def test_ensure
|
||
|
bug595 = '[ruby-dev:36511]'
|
||
|
assert_in_out_err([], <<-EOS, ["ok"], [], bug595)
|
||
|
Fiber.new{
|
||
|
begin
|
||
|
Fiber.yield
|
||
|
ensure
|
||
|
puts "ok"
|
||
|
end
|
||
|
}.resume
|
||
|
EOS
|
||
|
assert_in_out_err([], <<-EOS, ["ok"] * 1000, [], "[ruby-dev:41035]")
|
||
|
1000.times do
|
||
|
Fiber.new do
|
||
|
begin
|
||
|
Fiber.yield
|
||
|
ensure
|
||
|
puts "ok"
|
||
|
end
|
||
|
end.resume
|
||
|
GC.start
|
||
|
end
|
||
|
EOS
|
||
|
|
||
|
assert_in_out_err([], <<-EOS, ["ok"], [], "[ruby-dev:41035]")
|
||
|
Thread.new do
|
||
|
Fiber.new do
|
||
|
begin
|
||
|
Fiber.yield
|
||
|
ensure
|
||
|
puts "ok"
|
||
|
end
|
||
|
end.resume
|
||
|
end
|
||
|
sleep 1
|
||
|
EOS
|
||
|
assert_normal_exit %q{
|
||
|
Fiber.new do
|
||
|
begin
|
||
|
Fiber.yield
|
||
|
ensure
|
||
|
raise
|
||
|
end
|
||
|
end.resume
|
||
|
}
|
||
|
assert_normal_exit %q{
|
||
|
Thread.new do
|
||
|
Fiber.new do
|
||
|
begin
|
||
|
Fiber.yield
|
||
|
ensure
|
||
|
raise
|
||
|
end
|
||
|
end.resume
|
||
|
sleep
|
||
|
end
|
||
|
sleep 0.1
|
||
|
}
|
||
|
end
|
||
|
end
|
||
| thread.c (working copy) | ||
|---|---|---|
|
/* delete self other than main thread from living_threads */
|
||
|
if (th != main_th) {
|
||
|
TH_PUSH_TAG(th);
|
||
|
if (EXEC_TAG() == 0) {
|
||
|
rb_thread_terminate_fibers(th);
|
||
|
}
|
||
|
TH_POP_TAG();
|
||
|
st_delete_wrap(th->vm->living_threads, th->self);
|
||
|
}
|
||
| vm_core.h (working copy) | ||
|---|---|---|
|
VALUE rb_name_err_mesg_new(VALUE obj, VALUE mesg, VALUE recv, VALUE method);
|
||
|
void rb_vm_stack_to_heap(rb_thread_t *th);
|
||
|
void ruby_thread_init_stack(rb_thread_t *th);
|
||
|
void rb_thread_terminate_fibers(rb_thread_t *);
|
||
|
NOINLINE(void rb_gc_save_machine_context(rb_thread_t *));
|
||
|
void rb_gc_mark_machine_stack(rb_thread_t *th);
|
||
- « Previous
- 1
- 2
- Next »