Project

General

Profile

Bug #595 ยป ensure_fiber2.patch

wanabe (_ wanabe), 08/05/2012 01:05 PM

View differences:

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);