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 »