Bug #595 ยป ensure_fiber2.patch
cont.c (working copy) | ||
---|---|---|
880 | 880 |
{ |
881 | 881 |
switch(argc) { |
882 | 882 |
case 0: |
883 |
case -2: |
|
883 | 884 |
return Qnil; |
884 | 885 |
case 1: |
885 | 886 |
return argv[0]; |
... | ... | |
1133 | 1134 |
rb_fiber_transfer(return_fiber(), 1, &value); |
1134 | 1135 |
} |
1135 | 1136 | |
1137 |
static VALUE |
|
1138 |
fiber_start_i(VALUE tag, rb_context_t *cont) |
|
1139 |
{ |
|
1140 |
rb_thread_t *th = GET_THREAD(); |
|
1141 |
rb_proc_t *proc; |
|
1142 |
int argc; |
|
1143 |
VALUE *argv, args; |
|
1144 |
GetProcPtr(cont->saved_thread.first_proc, proc); |
|
1145 |
args = cont->value; |
|
1146 |
argv = (argc = cont->argc) > 1 ? RARRAY_PTR(args) : &args; |
|
1147 |
cont->value = Qnil; |
|
1148 |
th->errinfo = Qnil; |
|
1149 |
th->root_lep = rb_vm_ep_local_ep(proc->block.ep); |
|
1150 |
th->root_svar = Qnil; |
|
1151 | ||
1152 |
cont->value = rb_vm_invoke_proc(th, proc, proc->block.self, argc, argv, 0); |
|
1153 | ||
1154 |
return Qfalse; |
|
1155 |
} |
|
1156 | ||
1136 | 1157 |
void |
1137 | 1158 |
rb_fiber_start(void) |
1138 | 1159 |
{ |
1139 | 1160 |
rb_thread_t *th = GET_THREAD(); |
1140 | 1161 |
rb_fiber_t *fib; |
1141 | 1162 |
rb_context_t *cont; |
1142 |
rb_proc_t *proc; |
|
1143 | 1163 |
int state; |
1144 | 1164 | |
1145 | 1165 |
GetFiberPtr(th->fiber, fib); |
... | ... | |
1147 | 1167 | |
1148 | 1168 |
TH_PUSH_TAG(th); |
1149 | 1169 |
if ((state = EXEC_TAG()) == 0) { |
1150 |
int argc; |
|
1151 |
VALUE *argv, args; |
|
1152 |
GetProcPtr(cont->saved_thread.first_proc, proc); |
|
1153 |
args = cont->value; |
|
1154 |
argv = (argc = cont->argc) > 1 ? RARRAY_PTR(args) : &args; |
|
1155 |
cont->value = Qnil; |
|
1156 |
th->errinfo = Qnil; |
|
1157 |
th->root_lep = rb_vm_ep_local_ep(proc->block.ep); |
|
1158 |
th->root_svar = Qnil; |
|
1159 | ||
1160 | 1170 |
fib->status = RUNNING; |
1161 |
cont->value = rb_vm_invoke_proc(th, proc, proc->block.self, argc, argv, 0);
|
|
1171 |
rb_catch_obj(-2, fiber_start_i, (VALUE)cont);
|
|
1162 | 1172 |
} |
1163 | 1173 |
TH_POP_TAG(); |
1164 | 1174 | |
... | ... | |
1253 | 1263 |
/* restored */ |
1254 | 1264 |
GetFiberPtr(th->fiber, fib); |
1255 | 1265 |
if (fib->cont.argc == -1) rb_exc_raise(fib->cont.value); |
1266 |
else if (fib->cont.argc == -2) rb_throw_obj(-2, Qnil); |
|
1256 | 1267 |
return fib->cont.value; |
1257 | 1268 |
} |
1258 | 1269 |
#if !FIBER_USE_NATIVE |
... | ... | |
1496 | 1507 |
return rb_fiber_current(); |
1497 | 1508 |
} |
1498 | 1509 | |
1510 |
static void |
|
1511 |
fiber_terminate_on_th(rb_thread_t *th, int ignore_mark) |
|
1512 |
{ |
|
1513 |
VALUE fibval, current_fibval; |
|
1514 |
rb_fiber_t *fib, *root_fib, *prev_fiber; |
|
1515 |
rb_thread_t *_th = GET_THREAD(); |
|
1516 | ||
1517 |
fibval = th->root_fiber; |
|
1518 |
if (!RTEST(fibval)) return; |
|
1519 |
GetFiberPtr(fibval, root_fib); |
|
1520 | ||
1521 |
rb_thread_set_current(th); |
|
1522 |
fib = root_fib->prev_fiber; |
|
1523 |
current_fibval = rb_fiber_current(); |
|
1524 |
while (fib != root_fib) { |
|
1525 |
prev_fiber = fib->prev_fiber; |
|
1526 |
fibval = fib->cont.self; |
|
1527 |
if (fib->status == RUNNING && current_fibval != fibval) { |
|
1528 |
if(ignore_mark || !rb_gc_marked_p(fibval)) { |
|
1529 |
fib->prev = current_fibval; |
|
1530 |
fiber_switch(fibval, -2, 0, 0); |
|
1531 |
} |
|
1532 |
} |
|
1533 |
fib = prev_fiber; |
|
1534 |
} |
|
1535 |
rb_thread_set_current(_th); |
|
1536 |
} |
|
1537 | ||
1538 |
static int |
|
1539 |
fiber_terminate_unused_i(st_data_t key, st_data_t val, st_data_t data) |
|
1540 |
{ |
|
1541 |
rb_thread_t *th; |
|
1542 | ||
1543 |
GetThreadPtr((VALUE)key, th); |
|
1544 |
fiber_terminate_on_th(th, FALSE); |
|
1545 |
return ST_CONTINUE; |
|
1546 |
} |
|
1547 | ||
1548 |
void |
|
1549 |
rb_fiber_terminate_unused(void) |
|
1550 |
{ |
|
1551 |
st_foreach(GET_VM()->living_threads, fiber_terminate_unused_i, 0); |
|
1552 |
} |
|
1553 | ||
1554 |
void |
|
1555 |
rb_thread_terminate_fibers(rb_thread_t *th) |
|
1556 |
{ |
|
1557 |
fiber_terminate_on_th(th, TRUE); |
|
1558 |
} |
|
1559 | ||
1499 | 1560 | |
1500 | 1561 | |
1501 | 1562 |
/* |
eval.c (working copy) | ||
---|---|---|
158 | 158 |
rb_thread_t *th = GET_THREAD(); |
159 | 159 |
int nerr; |
160 | 160 | |
161 |
PUSH_TAG(); |
|
162 |
if ((state = EXEC_TAG()) == 0) { |
|
163 |
rb_thread_terminate_fibers(th); |
|
164 |
} |
|
165 |
POP_TAG(); |
|
166 | ||
161 | 167 |
rb_threadptr_interrupt(th); |
162 | 168 |
rb_threadptr_check_signal(th); |
163 | 169 |
PUSH_TAG(); |
gc.c (working copy) | ||
---|---|---|
2163 | 2163 |
return TRUE; |
2164 | 2164 |
} |
2165 | 2165 | |
2166 |
int |
|
2167 |
rb_gc_marked_p(VALUE p) |
|
2168 |
{ |
|
2169 |
return MARKED_IN_BITMAP(GET_HEAP_BITMAP(p), p); |
|
2170 |
} |
|
2171 | ||
2166 | 2172 |
static void |
2167 | 2173 |
before_gc_sweep(rb_objspace_t *objspace) |
2168 | 2174 |
{ |
2175 |
int _dont_gc; |
|
2176 | ||
2177 |
_dont_gc = dont_gc; |
|
2178 |
during_gc = 0; |
|
2179 |
objspace->flags.dont_lazy_sweep = 1; |
|
2180 |
dont_gc = 1; |
|
2181 |
rb_fiber_terminate_unused(); |
|
2182 |
dont_gc = _dont_gc; |
|
2183 |
during_gc = 0; |
|
2184 |
objspace->flags.dont_lazy_sweep = 0; |
|
2185 | ||
2169 | 2186 |
objspace->heap.do_heap_free = (size_t)((heaps_used * HEAP_OBJ_LIMIT) * 0.65); |
2170 | 2187 |
objspace->heap.free_min = (size_t)((heaps_used * HEAP_OBJ_LIMIT) * 0.2); |
2171 | 2188 |
if (objspace->heap.free_min < initial_free_min) { |
internal.h (working copy) | ||
---|---|---|
70 | 70 |
/* cont.c */ |
71 | 71 |
VALUE rb_obj_is_fiber(VALUE); |
72 | 72 |
void rb_fiber_reset_root_local_storage(VALUE); |
73 |
void rb_fiber_terminate_unused(void); |
|
73 | 74 | |
74 | 75 |
/* debug.c */ |
75 | 76 |
PRINTF_ARGS(void ruby_debug_printf(const char*, ...), 1, 2); |
... | ... | |
107 | 108 |
/* gc.c */ |
108 | 109 |
void Init_heap(void); |
109 | 110 |
void *ruby_mimmalloc(size_t size); |
111 |
int rb_gc_marked_p(VALUE); |
|
110 | 112 | |
111 | 113 |
/* inits.c */ |
112 | 114 |
void rb_call_inits(void); |
test/ruby/test_fiber.rb (working copy) | ||
---|---|---|
261 | 261 |
assert_equal(0, status.exitstatus, bug5700) |
262 | 262 |
assert_equal(false, status.signaled?, bug5700) |
263 | 263 |
end |
264 | ||
265 |
def test_ensure |
|
266 |
bug595 = '[ruby-dev:36511]' |
|
267 | ||
268 |
assert_in_out_err([], <<-EOS, ["ok"], [], bug595) |
|
269 |
Fiber.new{ |
|
270 |
begin |
|
271 |
Fiber.yield |
|
272 |
ensure |
|
273 |
puts "ok" |
|
274 |
end |
|
275 |
}.resume |
|
276 |
EOS |
|
277 | ||
278 |
assert_in_out_err([], <<-EOS, ["ok"] * 1000, [], "[ruby-dev:41035]") |
|
279 |
1000.times do |
|
280 |
Fiber.new do |
|
281 |
begin |
|
282 |
Fiber.yield |
|
283 |
ensure |
|
284 |
puts "ok" |
|
285 |
end |
|
286 |
end.resume |
|
287 |
GC.start |
|
288 |
end |
|
289 |
EOS |
|
290 |
|
|
291 |
assert_in_out_err([], <<-EOS, ["ok"], [], "[ruby-dev:41035]") |
|
292 |
Thread.new do |
|
293 |
Fiber.new do |
|
294 |
begin |
|
295 |
Fiber.yield |
|
296 |
ensure |
|
297 |
puts "ok" |
|
298 |
end |
|
299 |
end.resume |
|
300 |
end |
|
301 |
sleep 1 |
|
302 |
EOS |
|
303 | ||
304 |
assert_normal_exit %q{ |
|
305 |
Fiber.new do |
|
306 |
begin |
|
307 |
Fiber.yield |
|
308 |
ensure |
|
309 |
raise |
|
310 |
end |
|
311 |
end.resume |
|
312 |
} |
|
313 | ||
314 |
assert_normal_exit %q{ |
|
315 |
Thread.new do |
|
316 |
Fiber.new do |
|
317 |
begin |
|
318 |
Fiber.yield |
|
319 |
ensure |
|
320 |
raise |
|
321 |
end |
|
322 |
end.resume |
|
323 |
sleep |
|
324 |
end |
|
325 |
sleep 0.1 |
|
326 |
} |
|
327 |
end |
|
264 | 328 |
end |
265 | 329 |
thread.c (working copy) | ||
---|---|---|
507 | 507 | |
508 | 508 |
/* delete self other than main thread from living_threads */ |
509 | 509 |
if (th != main_th) { |
510 |
TH_PUSH_TAG(th); |
|
511 |
if (EXEC_TAG() == 0) { |
|
512 |
rb_thread_terminate_fibers(th); |
|
513 |
} |
|
514 |
TH_POP_TAG(); |
|
510 | 515 |
st_delete_wrap(th->vm->living_threads, th->self); |
511 | 516 |
} |
512 | 517 |
vm_core.h (working copy) | ||
---|---|---|
736 | 736 |
VALUE rb_name_err_mesg_new(VALUE obj, VALUE mesg, VALUE recv, VALUE method); |
737 | 737 |
void rb_vm_stack_to_heap(rb_thread_t *th); |
738 | 738 |
void ruby_thread_init_stack(rb_thread_t *th); |
739 |
void rb_thread_terminate_fibers(rb_thread_t *); |
|
739 | 740 | |
740 | 741 |
NOINLINE(void rb_gc_save_machine_context(rb_thread_t *)); |
741 | 742 |
void rb_gc_mark_machine_stack(rb_thread_t *th); |