59
64
rb_gc_mark_locations(cont->machine_stack,
60
65
cont->machine_stack + cont->machine_stack_size);
68
if (cont->machine_register_stack) {
69
rb_gc_mark_locations(cont->machine_register_stack,
70
cont->machine_register_stack + cont->machine_register_stack_size);
63
MARK_REPORT_LEAVE("cont");
74
RUBY_MARK_LEAVE("cont");
67
78
cont_free(void *ptr)
69
FREE_REPORT_ENTER("cont");
80
RUBY_FREE_ENTER("cont");
71
82
rb_context_t *cont = ptr;
72
FREE_UNLESS_NULL(cont->saved_thread.stack);
73
FREE_UNLESS_NULL(cont->machine_stack);
74
FREE_UNLESS_NULL(cont->vm_stack);
83
RUBY_FREE_UNLESS_NULL(cont->saved_thread.stack);
84
RUBY_FREE_UNLESS_NULL(cont->machine_stack);
86
RUBY_FREE_UNLESS_NULL(cont->machine_register_stack);
88
RUBY_FREE_UNLESS_NULL(cont->vm_stack);
77
FREE_REPORT_LEAVE("cont");
91
RUBY_FREE_LEAVE("cont");
81
95
cont_save_machine_stack(rb_thread_t *th, rb_context_t *cont)
85
rb_gc_set_stack_end(&th->machine_stack_end);
98
rb_thread_t *sth = &cont->saved_thread;
100
SET_MACHINE_STACK_END(&th->machine_stack_end);
102
th->machine_register_stack_end = rb_ia64_bsp();
86
105
if (th->machine_stack_start > th->machine_stack_end) {
87
106
size = cont->machine_stack_size = th->machine_stack_start - th->machine_stack_end;
88
107
cont->machine_stack_src = th->machine_stack_end;
108
146
rb_context_t *cont;
109
147
volatile VALUE contval;
110
rb_thread_t *th = GET_THREAD(), *sth;
148
rb_thread_t *th = GET_THREAD();
112
150
contval = Data_Make_Struct(klass, rb_context_t,
113
151
cont_mark, cont_free, cont);
114
153
cont->self = contval;
115
154
cont->alive = Qtrue;
156
/* save thread context */
118
157
cont->saved_thread = *th;
119
sth = &cont->saved_thread;
124
void th_stack_to_heap(rb_thread_t *th);
162
void vm_stack_to_heap(rb_thread_t *th);
127
165
cont_capture(volatile int *stat)
129
167
rb_context_t *cont;
168
rb_thread_t *th = GET_THREAD(), *sth;
169
volatile VALUE contval;
132
th_stack_to_heap(GET_THREAD());
133
cont = cont_new(rb_cCont);
134
th = &cont->saved_thread;
171
vm_stack_to_heap(th);
172
cont = cont_new(rb_cContinuation);
173
contval = cont->self;
174
sth = &cont->saved_thread;
136
176
cont->vm_stack = ALLOC_N(VALUE, th->stack_size);
137
177
MEMCPY(cont->vm_stack, th->stack, VALUE, th->stack_size);
140
180
cont_save_machine_stack(th, cont);
184
234
th->first_proc = sth->first_proc;
186
236
/* restore machine stack */
239
/* workaround for x64 SEH */
242
((_JUMP_BUFFER*)(&cont->jmpbuf))->Frame =
243
((_JUMP_BUFFER*)(&buf))->Frame;
187
246
if (cont->machine_stack_src) {
188
247
MEMCPY(cont->machine_stack_src, cont->machine_stack,
189
248
VALUE, cont->machine_stack_size);
252
if (cont->machine_register_stack_src) {
253
MEMCPY(cont->machine_register_stack_src, cont->machine_register_stack,
254
VALUE, cont->machine_register_stack_size);
192
258
ruby_longjmp(cont->jmpbuf, 1);
195
261
NORETURN(NOINLINE(static void cont_restore_0(rb_context_t *, VALUE *)));
264
#define C(a) rse_##a##0, rse_##a##1, rse_##a##2, rse_##a##3, rse_##a##4
265
#define E(a) rse_##a##0= rse_##a##1= rse_##a##2= rse_##a##3= rse_##a##4
266
static volatile int C(a), C(b), C(c), C(d), C(e);
267
static volatile int C(f), C(g), C(h), C(i), C(j);
268
static volatile int C(k), C(l), C(m), C(n), C(o);
269
static volatile int C(p), C(q), C(r), C(s), C(t);
270
int rb_dummy_false = 0;
271
NORETURN(NOINLINE(static void register_stack_extend(rb_context_t *, VALUE *)));
273
register_stack_extend(rb_context_t *cont, VALUE *curr_bsp)
275
if (rb_dummy_false) {
276
/* use registers as much as possible */
277
E(a) = E(b) = E(c) = E(d) = E(e) =
278
E(f) = E(g) = E(h) = E(i) = E(j) =
279
E(k) = E(l) = E(m) = E(n) = E(o) =
280
E(p) = E(q) = E(r) = E(s) = E(t) = 0;
281
E(a) = E(b) = E(c) = E(d) = E(e) =
282
E(f) = E(g) = E(h) = E(i) = E(j) =
283
E(k) = E(l) = E(m) = E(n) = E(o) =
284
E(p) = E(q) = E(r) = E(s) = E(t) = 0;
286
if (curr_bsp < cont->machine_register_stack_src+cont->machine_register_stack_size) {
287
register_stack_extend(cont, (VALUE*)rb_ia64_bsp());
289
cont_restore_1(cont);
198
296
cont_restore_0(rb_context_t *cont, VALUE *addr_in_prev_frame)
387
495
*th->cfp->lfp = 0;
388
496
th->cfp->dfp = th->stack;
389
497
th->cfp->self = Qnil;
391
499
th->cfp->iseq = 0;
392
500
th->cfp->proc = 0;
393
501
th->cfp->block_iseq = 0;
395
th->first_proc = rb_block_proc();
504
th->first_proc = proc;
397
506
MEMCPY(&cont->jmpbuf, &th->root_jmpbuf, rb_jmpbuf_t, 1);
402
static VALUE rb_fiber_yield(int argc, VALUE *args, VALUE fval);
512
rb_fiber_new(VALUE (*func)(ANYARGS), VALUE obj)
514
return fiber_alloc(rb_cFiber, rb_proc_new(func, obj));
518
rb_fiber_s_new(VALUE self)
520
return fiber_alloc(self, rb_block_proc());
527
VALUE curr = rb_fiber_current();
528
GetContPtr(curr, cont);
530
if (cont->prev == Qnil) {
531
rb_thread_t *th = GET_THREAD();
533
if (th->root_fiber != curr) {
534
return th->root_fiber;
537
rb_raise(rb_eFiberError, "can't yield from root fiber");
541
VALUE prev = cont->prev;
547
VALUE rb_fiber_transfer(VALUE fib, int argc, VALUE *argv);
405
550
rb_fiber_terminate(rb_context_t *cont)
407
rb_context_t *prev_cont;
408
552
VALUE value = cont->value;
410
GetContPtr(cont->prev, prev_cont);
412
553
cont->alive = Qfalse;
415
if (prev_cont->alive == Qfalse) {
416
rb_fiber_yield(1, &value, GET_THREAD()->root_fiber);
419
rb_fiber_yield(1, &value, cont->prev);
554
rb_fiber_transfer(return_fiber(), 1, &value);
499
rb_fiber_yield(int argc, VALUE *argv, VALUE fval)
638
fiber_switch(VALUE fib, int argc, VALUE *argv, int is_resume)
502
641
rb_context_t *cont;
503
642
rb_thread_t *th = GET_THREAD();
505
GetContPtr(fval, cont);
644
GetContPtr(fib, cont);
507
646
if (cont->saved_thread.self != th->self) {
508
647
rb_raise(rb_eFiberError, "fiber called across threads");
510
if (cont->saved_thread.trap_tag != th->trap_tag) {
649
else if (cont->saved_thread.trap_tag != th->trap_tag) {
511
650
rb_raise(rb_eFiberError, "fiber called across trap");
652
else if (!cont->alive) {
514
653
rb_raise(rb_eFiberError, "dead fiber called");
657
cont->prev = rb_fiber_current();
517
660
cont->value = make_passing_arg(argc, argv);
519
662
if ((value = cont_store(cont)) == Qundef) {
520
cont_restore_0(cont, (VALUE *)&cont);
521
rb_bug("rb_fiber_yield: unreachable");
663
cont_restore_0(cont, &value);
664
rb_bug("rb_fiber_resume: unreachable");
667
RUBY_VM_CHECK_INTS();
528
rb_fiber_prev(VALUE fval)
531
GetContPtr(fval, cont);
536
rb_fiber_alive_p(VALUE fval)
539
GetContPtr(fval, cont);
673
rb_fiber_transfer(VALUE fib, int argc, VALUE *argv)
675
return fiber_switch(fib, argc, argv, 0);
679
rb_fiber_resume(VALUE fib, int argc, VALUE *argv)
682
GetContPtr(fib, cont);
684
if (cont->prev != Qnil) {
685
rb_raise(rb_eFiberError, "double resume");
688
return fiber_switch(fib, argc, argv, 1);
692
rb_fiber_yield(int argc, VALUE *argv)
694
return rb_fiber_transfer(return_fiber(), argc, argv);
698
rb_fiber_alive_p(VALUE fib)
701
GetContPtr(fib, cont);
540
702
return cont->alive;
706
rb_fiber_m_resume(int argc, VALUE *argv, VALUE fib)
708
return rb_fiber_resume(fib, argc, argv);
712
rb_fiber_m_transfer(int argc, VALUE *argv, VALUE fib)
714
return rb_fiber_transfer(fib, argc, argv);
718
rb_fiber_s_yield(int argc, VALUE *argv, VALUE klass)
720
return rb_fiber_yield(argc, argv);
544
724
rb_fiber_s_current(VALUE klass)
546
return rb_fiber_current(GET_THREAD());
550
rb_fiber_s_prev(VALUE klass)
552
return rb_fiber_prev(rb_fiber_s_current(Qnil));
556
rb_fiber_s_yield(int argc, VALUE *argv, VALUE fval)
558
return rb_fiber_yield(argc, argv, rb_fiber_s_prev(Qnil));
726
return rb_fiber_current();
564
rb_cCont = rb_define_class("Continuation", rb_cObject);
565
rb_undef_alloc_func(rb_cCont);
566
rb_undef_method(CLASS_OF(rb_cCont), "new");
567
rb_define_method(rb_cCont, "call", rb_cont_call, -1);
568
rb_define_method(rb_cCont, "[]", rb_cont_call, -1);
569
rb_define_global_function("callcc", rb_callcc, 0);
571
732
rb_cFiber = rb_define_class("Fiber", rb_cObject);
572
733
rb_undef_alloc_func(rb_cFiber);
573
rb_define_method(rb_cFiber, "yield", rb_fiber_yield, -1);
574
rb_define_method(rb_cFiber, "prev", rb_fiber_prev, 0);
734
rb_eFiberError = rb_define_class("FiberError", rb_eStandardError);
738
Init_Continuation_body(void)
740
rb_cContinuation = rb_define_class("Continuation", rb_cObject);
741
rb_undef_alloc_func(rb_cContinuation);
742
rb_undef_method(CLASS_OF(rb_cContinuation), "new");
743
rb_define_method(rb_cContinuation, "call", rb_cont_call, -1);
744
rb_define_method(rb_cContinuation, "[]", rb_cont_call, -1);
745
rb_define_global_function("callcc", rb_callcc, 0);
749
Init_Fiber_body(void)
751
rb_define_singleton_method(rb_cFiber, "new", rb_fiber_s_new, 0);
752
rb_define_method(rb_cFiber, "resume", rb_fiber_m_resume, -1);
753
rb_define_method(rb_cFiber, "transfer", rb_fiber_m_transfer, -1);
575
754
rb_define_method(rb_cFiber, "alive?", rb_fiber_alive_p, 0);
755
rb_define_singleton_method(rb_cFiber, "yield", rb_fiber_s_yield, -1);
577
756
rb_define_singleton_method(rb_cFiber, "current", rb_fiber_s_current, 0);
578
rb_define_singleton_method(rb_cFiber, "prev", rb_fiber_s_prev, 0);
579
rb_define_singleton_method(rb_cFiber, "yield", rb_fiber_s_yield, -1);
580
rb_define_singleton_method(rb_cFiber, "new", rb_fiber_s_new, 0);
582
rb_eFiberError = rb_define_class("FiberError", rb_eStandardError);