28 #if !defined(FIBER_USE_NATIVE) 29 # if defined(HAVE_GETCONTEXT) && defined(HAVE_SETCONTEXT) 31 # elif defined(__NetBSD__) 37 # define FIBER_USE_NATIVE 0 41 # define FIBER_USE_NATIVE 0 42 # elif defined(__ia64) 45 # define FIBER_USE_NATIVE 0 46 # elif defined(__GNU__) 52 # define FIBER_USE_NATIVE 0 54 # define FIBER_USE_NATIVE 1 56 # elif defined(_WIN32) 57 # define FIBER_USE_NATIVE 1 60 #if !defined(FIBER_USE_NATIVE) 61 #define FIBER_USE_NATIVE 0 70 #define RB_PAGE_SIZE (pagesize) 71 #define RB_PAGE_MASK (~(RB_PAGE_SIZE - 1)) 75 #define CAPTURE_JUST_VALID_VM_STACK 1 85 #ifdef CAPTURE_JUST_VALID_VM_STACK 104 VALUE *register_stack;
105 VALUE *register_stack_src;
106 int register_stack_size;
136 #define FIBER_CREATED_P(fib) ((fib)->status == FIBER_CREATED) 137 #define FIBER_RESUMED_P(fib) ((fib)->status == FIBER_RESUMED) 138 #define FIBER_SUSPENDED_P(fib) ((fib)->status == FIBER_SUSPENDED) 139 #define FIBER_TERMINATED_P(fib) ((fib)->status == FIBER_TERMINATED) 140 #define FIBER_RUNNABLE_P(fib) (FIBER_CREATED_P(fib) || FIBER_SUSPENDED_P(fib)) 142 #if FIBER_USE_NATIVE && !defined(_WIN32) 143 #define MAX_MACHINE_STACK_CACHE 10 144 static int machine_stack_cache_index = 0;
145 typedef struct machine_stack_cache_struct {
148 } machine_stack_cache_t;
149 static machine_stack_cache_t machine_stack_cache[MAX_MACHINE_STACK_CACHE];
150 static machine_stack_cache_t terminated_machine_stack;
195 if (0) fprintf(stderr,
"fib: %p, status: %s -> %s\n", fib, fiber_status_name(fib->
status), fiber_status_name(s));
202 static VALUE rb_cContinuation;
203 static VALUE rb_cFiber;
204 static VALUE rb_eFiberError;
206 #define GetContPtr(obj, ptr) \ 207 TypedData_Get_Struct((obj), rb_context_t, &cont_data_type, (ptr)) 209 #define GetFiberPtr(obj, ptr) do {\ 210 TypedData_Get_Struct((obj), rb_fiber_t, &fiber_data_type, (ptr)); \ 211 if (!(ptr)) rb_raise(rb_eFiberError, "uninitialized fiber"); \ 216 #define THREAD_MUST_BE_RUNNING(th) do { \ 217 if (!(th)->ec.tag) rb_raise(rb_eThreadError, "not running thread"); \ 238 #ifdef CAPTURE_JUST_VALID_VM_STACK 255 const rb_thread_t *th = rb_thread_ptr(cont_thread_value(cont));
265 if (cont->
machine.register_stack) {
267 cont->
machine.register_stack + cont->
machine.register_stack_size);
294 if (fib->fib_handle) {
295 DeleteFiber(fib->fib_handle);
299 if (th && th->
ec.
fiber != fib) {
302 rb_bug(
"Illegal root fiber parameter");
304 munmap((
void*)fib->ss_sp, fib->ss_size);
329 cont_memsize(
const void *ptr)
334 size =
sizeof(*cont);
336 #ifdef CAPTURE_JUST_VALID_VM_STACK 348 if (cont->
machine.register_stack) {
349 size += cont->
machine.register_stack_size *
sizeof(*cont->
machine.register_stack);
358 #if VM_CHECK_MODE > 0 384 fiber_mark(
void *ptr)
391 cont_mark(&fib->
cont);
396 fiber_free(
void *ptr)
405 cont_free(&fib->
cont);
410 fiber_memsize(
const void *ptr)
420 size += cont_memsize(&fib->
cont);
442 th->machine.register_stack_end = rb_ia64_bsp();
466 size = cont->
machine.register_stack_size = th->machine.register_stack_end - th->machine.register_stack_start;
467 cont->
machine.register_stack_src = th->machine.register_stack_start;
468 if (cont->
machine.register_stack) {
481 {cont_mark, cont_free, cont_memsize,},
509 cont_save_thread(cont, th);
517 cont_new(
VALUE klass)
520 volatile VALUE contval;
525 cont->
self = contval;
531 cont_capture(
volatile int *
volatile stat)
535 volatile VALUE contval;
540 cont = cont_new(rb_cContinuation);
541 contval = cont->
self;
543 #ifdef CAPTURE_JUST_VALID_VM_STACK 556 cont_save_machine_stack(th, cont);
617 #ifdef CAPTURE_JUST_VALID_VM_STACK 648 fiber_set_stack_location(
void)
658 fiber_entry(
void *arg)
660 fiber_set_stack_location();
670 #if defined(MAP_STACK) && !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) 671 #define FIBER_STACK_FLAGS (MAP_PRIVATE | MAP_ANON | MAP_STACK) 673 #define FIBER_STACK_FLAGS (MAP_PRIVATE | MAP_ANON) 677 fiber_machine_stack_alloc(
size_t size)
681 if (machine_stack_cache_index > 0) {
682 if (machine_stack_cache[machine_stack_cache_index - 1].size == (size /
sizeof(
VALUE))) {
683 ptr = machine_stack_cache[machine_stack_cache_index - 1].ptr;
684 machine_stack_cache_index--;
685 machine_stack_cache[machine_stack_cache_index].ptr =
NULL;
686 machine_stack_cache[machine_stack_cache_index].size = 0;
690 rb_bug(
"machine_stack_cache size is not canonicalized");
698 ptr = mmap(
NULL, size, PROT_READ | PROT_WRITE, FIBER_STACK_FLAGS, -1, 0);
699 if (ptr == MAP_FAILED) {
705 if (mprotect(page, RB_PAGE_SIZE, PROT_NONE) < 0) {
706 rb_raise(rb_eFiberError,
"mprotect failed");
715 fiber_initialize_machine_stack_context(
rb_fiber_t *fib,
size_t size)
720 # if defined(_MSC_VER) && _MSC_VER <= 1200 721 # define CreateFiberEx(cs, stacksize, flags, entry, param) \ 722 CreateFiber((stacksize), (entry), (param)) 724 fib->fib_handle = CreateFiberEx(size - 1, size, 0, fiber_entry,
NULL);
725 if (!fib->fib_handle) {
728 fib->fib_handle = CreateFiberEx(size - 1, size, 0, fiber_entry,
NULL);
729 if (!fib->fib_handle) {
730 rb_raise(rb_eFiberError,
"can't create fiber");
735 ucontext_t *context = &fib->context;
740 ptr = fiber_machine_stack_alloc(size);
741 context->uc_link =
NULL;
742 context->uc_stack.ss_sp =
ptr;
743 context->uc_stack.ss_size =
size;
751 sth->machine.register_stack_maxsize = sth->machine.stack_maxsize;
783 fiber_restore_thread(th, newfib);
786 if (!newfib->context.uc_stack.ss_sp && th->
root_fiber != newfib) {
787 rb_bug(
"non_root_fiber->context.uc_stac.ss_sp should not be NULL");
792 SwitchToFiber(newfib->fib_handle);
794 swapcontext(&oldfib->context, &newfib->context);
804 cont_restore_thread(cont);
812 ((_JUMP_BUFFER*)(&cont->
jmpbuf))->Frame =
813 ((_JUMP_BUFFER*)(&
buf))->Frame;
823 if (cont->
machine.register_stack_src) {
835 #define C(a) rse_##a##0, rse_##a##1, rse_##a##2, rse_##a##3, rse_##a##4 836 #define E(a) rse_##a##0= rse_##a##1= rse_##a##2= rse_##a##3= rse_##a##4 837 static volatile int C(a),
C(b),
C(c),
C(d),
C(e);
838 static volatile int C(
f),
C(g),
C(h),
C(i),
C(j);
839 static volatile int C(k),
C(l),
C(m),
C(n),
C(o);
840 static volatile int C(p),
C(q),
C(r),
C(s),
C(t);
844 int rb_dummy_false = 0;
849 if (rb_dummy_false) {
851 E(a) = E(b) = E(c) = E(d) = E(e) =
852 E(
f) = E(g) = E(h) = E(i) = E(j) =
853 E(k) = E(l) = E(m) = E(n) = E(o) =
854 E(p) = E(q) = E(r) = E(s) = E(t) = 0;
855 E(a) = E(b) = E(c) = E(d) = E(e) =
856 E(
f) = E(g) = E(h) = E(i) = E(j) =
857 E(k) = E(l) = E(m) = E(n) = E(o) =
858 E(p) = E(q) = E(r) = E(s) = E(t) = 0;
860 if (curr_bsp < cont->machine.register_stack_src+cont->
machine.register_stack_size) {
861 register_stack_extend(cont, vp, (
VALUE*)rb_ia64_bsp());
863 cont_restore_0(cont, vp);
874 #define STACK_PAD_SIZE 1 876 #define STACK_PAD_SIZE 1024 880 #if !STACK_GROW_DIRECTION 881 if (addr_in_prev_frame > &space[0]) {
884 #if STACK_GROW_DIRECTION <= 0 886 if (&space[0] > end) {
891 cont_restore_0(cont, &space[0]);
895 #if !STACK_GROW_DIRECTION 900 #if STACK_GROW_DIRECTION >= 0 907 cont_restore_0(cont, &space[STACK_PAD_SIZE-1]);
911 #if !STACK_GROW_DIRECTION 915 cont_restore_1(cont);
918 #define cont_restore_0(cont, vp) register_stack_extend((cont), (vp), (VALUE*)rb_ia64_bsp()) 1005 rb_callcc(
VALUE self)
1007 volatile int called;
1008 volatile VALUE val = cont_capture(&called);
1066 for (p=current; p; p=p->
next)
1069 for (entry=target; entry->
marker; entry++)
1074 base_point = cur_size;
1075 while (base_point) {
1076 if (target_size >= base_point &&
1084 for (i=0; i < target_size - base_point; i++) {
1085 if (!lookup_rollback_func(target[i].e_proc)) {
1090 while (cur_size > base_point) {
1093 current = current->
next;
1098 func = (
VALUE (*)(
ANYARGS)) lookup_rollback_func(target[i].e_proc);
1100 (*func)(target[i].
data2);
1122 rb_cont_call(
int argc,
VALUE *argv,
VALUE contval)
1128 if (cont_thread_value(cont) != th->
self) {
1142 cont->
value = make_passing_arg(argc, argv);
1144 cont_restore_0(cont, &contval);
1217 {fiber_mark, fiber_free, fiber_memsize,},
1218 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
1222 fiber_alloc(
VALUE klass)
1228 fiber_t_alloc(
VALUE fibval)
1241 cont_init(&fib->
cont, th);
1302 #if !FIBER_USE_NATIVE 1311 rb_fiber_init(
VALUE fibval)
1319 return fiber_init(fiber_alloc(rb_cFiber),
rb_proc_new(func, obj));
1322 static void rb_fiber_terminate(
rb_fiber_t *fib);
1365 rb_fiber_terminate(fib);
1374 fib = fiber_t_alloc(fiber_alloc(rb_cFiber));
1376 #if FIBER_USE_NATIVE 1378 fib->fib_handle = ConvertThreadToFiber(0);
1407 if (root_fiber == fib) {
1408 rb_raise(rb_eFiberError,
"can't yield from root fiber");
1431 cont_save_thread(&fib->
cont, th);
1435 fib = root_fiber_alloc(th);
1441 #if FIBER_USE_NATIVE 1449 #if FIBER_USE_NATIVE == 0 1451 cont_save_machine_stack(th, &fib->
cont);
1456 #if FIBER_USE_NATIVE 1457 fiber_setcontext(next_fib, fib);
1460 if (terminated_machine_stack.ptr) {
1461 if (machine_stack_cache_index < MAX_MACHINE_STACK_CACHE) {
1462 machine_stack_cache[machine_stack_cache_index].ptr = terminated_machine_stack.ptr;
1463 machine_stack_cache[machine_stack_cache_index].size = terminated_machine_stack.size;
1464 machine_stack_cache_index++;
1468 munmap((
void*)terminated_machine_stack.ptr, terminated_machine_stack.size *
sizeof(
VALUE));
1471 rb_bug(
"terminated fiber resumed");
1474 terminated_machine_stack.ptr =
NULL;
1475 terminated_machine_stack.size = 0;
1495 cont_restore_0(&next_fib->
cont, &undef);
1502 fiber_switch(
rb_fiber_t *fib,
int argc,
const VALUE *argv,
int is_resume)
1512 return make_passing_arg(argc, argv);
1515 if (cont_thread_value(cont) != th->
self) {
1516 rb_raise(rb_eFiberError,
"fiber called across threads");
1519 rb_raise(rb_eFiberError,
"fiber called across stack rewinding barrier");
1522 value =
rb_exc_new2(rb_eFiberError,
"dead fiber called");
1536 cont->
value = value;
1537 #if FIBER_USE_NATIVE 1540 cont_restore_0(cont, &value);
1547 fib->
prev = fiber_current();
1553 cont->
value = make_passing_arg(argc, argv);
1554 value = fiber_store(fib, th);
1567 return fiber_switch(fib, argc, argv, 0);
1577 #if FIBER_USE_NATIVE && !defined(_WIN32) 1579 terminated_machine_stack.ptr = fib->ss_sp;
1580 terminated_machine_stack.size = fib->ss_size /
sizeof(
VALUE);
1582 fib->context.uc_stack.ss_sp =
NULL;
1586 fiber_switch(return_fiber(), 1, &value, 0);
1596 rb_raise(rb_eFiberError,
"double resume");
1599 rb_raise(rb_eFiberError,
"cannot resume transferred Fiber");
1602 return fiber_switch(fib, argc, argv, 1);
1608 return fiber_switch(return_fiber(), argc, argv, 0);
1654 rb_fiber_m_resume(
int argc,
VALUE *argv,
VALUE fib)
1705 rb_fiber_m_transfer(
int argc,
VALUE *argv,
VALUE fibval)
1710 return fiber_switch(fib, argc, argv, 0);
1724 rb_fiber_s_yield(
int argc,
VALUE *argv,
VALUE klass)
1738 rb_fiber_s_current(
VALUE klass)
1752 fiber_to_s(
VALUE fibval)
1756 char status_info[0x10];
1759 snprintf(status_info, 0x10,
" (%s)", fiber_status_name(fib->
status));
1762 strlcat(status_info,
">",
sizeof(status_info));
1787 #if FIBER_USE_NATIVE 1792 GetSystemInfo(&info);
1793 pagesize = info.dwPageSize;
1795 pagesize = sysconf(_SC_PAGESIZE);
#define RUBY_VM_CHECK_INTS(th)
struct rb_ensure_entry entry
void rb_bug(const char *fmt,...)
#define THREAD_MUST_BE_RUNNING(th)
#define GetContPtr(obj, ptr)
#define ruby_longjmp(env, val)
VALUE rb_block_to_s(VALUE self, const struct rb_block *block, const char *additional_info)
#define RUBY_TYPED_FREE_IMMEDIATELY
#define FIBER_RUNNABLE_P(fib)
#define RUBY_VM_SET_INTERRUPT(th)
struct rb_trace_arg_struct * trace_arg
void rb_undef_alloc_func(VALUE)
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
#define GetProcPtr(obj, ptr)
VALUE local_storage_recursive_hash_for_trace
#define FLUSH_REGISTER_WINDOWS
void rb_raise(VALUE exc, const char *fmt,...)
VALUE rb_fiber_resume(VALUE fibval, int argc, const VALUE *argv)
#define TypedData_Wrap_Struct(klass, data_type, sval)
void rb_fiber_reset_root_local_storage(VALUE thval)
#define GetFiberPtr(obj, ptr)
VALUE rb_vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, int argc, const VALUE *argv, VALUE passed_block_handler)
#define VM_BLOCK_HANDLER_NONE
size_t fiber_machine_stack_size
VALUE rb_ary_tmp_new(long capa)
rb_ensure_list_t * ensure_list
#define STACK_UPPER(x, a, b)
void rb_str_set_len(VALUE, long)
VALUE rb_fiber_alive_p(VALUE fibval)
void rb_threadptr_pending_interrupt_enque(rb_thread_t *th, VALUE v)
#define RUBY_MARK_LEAVE(msg)
VALUE rb_fiber_current(void)
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
void rb_gc_mark(VALUE ptr)
void rb_define_global_function(const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a global function.
struct cont_saved_vm_stack saved_vm_stack
void rb_undef_method(VALUE klass, const char *name)
void rb_gc_mark_locations(const VALUE *start, const VALUE *end)
struct rb_context_struct rb_context_t
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type)
RUBY_SYMBOL_EXPORT_BEGIN typedef unsigned long st_data_t
RUBY_EXTERN VALUE rb_cObject
rb_ensure_entry_t * ensure_array
size_t st_memsize(const st_table *tab)
#define FIBER_SUSPENDED_P(fib)
size_t fiber_vm_stack_size
VALUE rb_any_to_s(VALUE)
call-seq: obj.to_s -> string
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
#define RUBY_MARK_ENTER(msg)
VALUE rb_fiber_new(VALUE(*func)(ANYARGS), VALUE obj)
#define FIBER_RESUMED_P(fib)
void ruby_Init_Fiber_as_Coroutine(void)
void rb_fiber_start(void)
#define ALLOCA_N(type, n)
#define MEMCPY(p1, p2, type, n)
VALUE local_storage_recursive_hash
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
#define RARRAY_CONST_PTR(a)
#define REALLOC_N(var, type, n)
#define STACK_DIR_UPPER(a, b)
VALUE rb_obj_is_proc(VALUE)
void rb_vm_stack_to_heap(rb_thread_t *th)
RUBY_SYMBOL_EXPORT_BEGIN void ruby_Init_Continuation_body(void)
VALUE rb_fiber_yield(int argc, const VALUE *argv)
#define RUBY_SYMBOL_EXPORT_END
unsigned char buf[MIME_BUF_SIZE]
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
#define FIBER_TERMINATED_P(fib)
struct rb_vm_protect_tag * protect_tag
#define STACK_GROW_DIR_DETECTION
const VALUE * rb_vm_proc_local_ep(VALUE proc)
#define EXEC_EVENT_HOOK(th_, flag_, self_, id_, called_id_, klass_, data_)
#define FIBER_CREATED_P(fib)
#define RUBY_SYMBOL_EXPORT_BEGIN
rb_control_frame_t * rb_vm_push_frame(rb_execution_context_t *sec, const rb_iseq_t *iseq, VALUE type, VALUE self, VALUE specval, VALUE cref_or_me, const VALUE *pc, VALUE *sp, int local_size, int stack_max)
#define SET_MACHINE_STACK_END(p)
struct rb_ensure_list * next
struct rb_execution_context_struct::@143 machine
rb_execution_context_t saved_ec
enum rb_thread_status status
#define RUBY_FREE_UNLESS_NULL(ptr)
NOINLINE(static VALUE cont_capture(volatile int *volatile stat))
#define VAR_FROM_MEMORY(var)
VALUE rb_block_proc(void)
#define RUBY_FREE_LEAVE(msg)
#define RUBY_FREE_ENTER(msg)
#define VAR_INITIALIZED(var)
const struct rb_block block
RUBY_EXTERN char * strerror(int)
VALUE rb_obj_is_fiber(VALUE obj)
void rb_execution_context_mark(const rb_execution_context_t *ec)
VALUE rb_proc_new(VALUE(*)(ANYARGS), VALUE)
VALUE rb_str_cat_cstr(VALUE, const char *)
#define VM_UNREACHABLE(func)
struct rb_context_struct::@3 machine
#define TypedData_Make_Struct(klass, type, data_type, sval)
rb_execution_context_t ec
RUBY_EXTERN size_t strlcat(char *, const char *, size_t)
#define RUBY_EVENT_FIBER_SWITCH
void rb_fiber_mark_self(const rb_fiber_t *fib)
void ruby_register_rollback_func_for_ensure(VALUE(*ensure_func)(ANYARGS), VALUE(*rollback_func)(ANYARGS))
VALUE rb_vm_make_jump_tag_but_local_jump(int state, VALUE val)
NORETURN(NOINLINE(static void cont_restore_0(rb_context_t *, VALUE *)))
struct rb_fiber_struct * prev
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
struct rb_vm_struct::@140 default_params
rb_ensure_list_t * ensure_list
VALUE rb_fiber_transfer(VALUE fibval, int argc, const VALUE *argv)