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 89 #ifdef CAPTURE_JUST_VALID_VM_STACK 98 VALUE *register_stack;
99 VALUE *register_stack_src;
100 int register_stack_size;
115 #if FIBER_USE_NATIVE && !defined(_WIN32) 116 #define MAX_MACHINE_STACK_CACHE 10 117 static int machine_stack_cache_index = 0;
118 typedef struct machine_stack_cache_struct {
121 } machine_stack_cache_t;
122 static machine_stack_cache_t machine_stack_cache[MAX_MACHINE_STACK_CACHE];
123 static machine_stack_cache_t terminated_machine_stack;
156 #define GetContPtr(obj, ptr) \ 157 TypedData_Get_Struct((obj), rb_context_t, &cont_data_type, (ptr)) 159 #define GetFiberPtr(obj, ptr) do {\ 160 TypedData_Get_Struct((obj), rb_fiber_t, &fiber_data_type, (ptr)); \ 161 if (!(ptr)) rb_raise(rb_eFiberError, "uninitialized fiber"); \ 166 #define THREAD_MUST_BE_RUNNING(th) do { \ 167 if (!(th)->tag) rb_raise(rb_eThreadError, "not running thread"); \ 182 #ifdef CAPTURE_JUST_VALID_VM_STACK 209 if (cont->
machine.register_stack) {
211 cont->
machine.register_stack + cont->
machine.register_stack_size);
238 if (fib->fib_handle) {
239 DeleteFiber(fib->fib_handle);
243 if (th && th->
fiber != fib) {
246 rb_bug(
"Illegal root fiber parameter");
248 munmap((
void*)fib->ss_sp, fib->ss_size);
279 size =
sizeof(*cont);
281 #ifdef CAPTURE_JUST_VALID_VM_STACK 286 size += n *
sizeof(*cont->
vm_stack);
293 if (cont->
machine.register_stack) {
294 size += cont->
machine.register_stack_size *
sizeof(*cont->
machine.register_stack);
368 th->
machine.register_stack_end = rb_ia64_bsp();
392 size = cont->
machine.register_stack_size = th->
machine.register_stack_end - th->
machine.register_stack_start;
393 cont->
machine.register_stack_src = th->
machine.register_stack_start;
394 if (cont->
machine.register_stack) {
440 sth->
machine.register_stack_start = 0;
441 sth->
machine.register_stack_end = 0;
462 volatile VALUE contval;
467 cont->
self = contval;
477 volatile VALUE contval;
482 contval = cont->
self;
484 #ifdef CAPTURE_JUST_VALID_VM_STACK 540 th->
fiber = sth->fiber;
547 #ifdef CAPTURE_JUST_VALID_VM_STACK 557 th->
stack = sth->stack;
569 th->
state = sth->state;
585 fiber_set_stack_location(
void)
595 fiber_entry(
void *arg)
597 fiber_set_stack_location();
607 #if defined(MAP_STACK) && !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) 608 #define FIBER_STACK_FLAGS (MAP_PRIVATE | MAP_ANON | MAP_STACK) 610 #define FIBER_STACK_FLAGS (MAP_PRIVATE | MAP_ANON) 614 fiber_machine_stack_alloc(
size_t size)
618 if (machine_stack_cache_index > 0) {
619 if (machine_stack_cache[machine_stack_cache_index - 1].size == (size /
sizeof(
VALUE))) {
620 ptr = machine_stack_cache[machine_stack_cache_index - 1].ptr;
621 machine_stack_cache_index--;
622 machine_stack_cache[machine_stack_cache_index].ptr =
NULL;
623 machine_stack_cache[machine_stack_cache_index].size = 0;
627 rb_bug(
"machine_stack_cache size is not canonicalized");
635 ptr = mmap(
NULL, size, PROT_READ | PROT_WRITE, FIBER_STACK_FLAGS, -1, 0);
636 if (ptr == MAP_FAILED) {
642 if (mprotect(page, RB_PAGE_SIZE, PROT_NONE) < 0) {
652 fiber_initialize_machine_stack_context(
rb_fiber_t *fib,
size_t size)
657 # if defined(_MSC_VER) && _MSC_VER <= 1200 658 # define CreateFiberEx(cs, stacksize, flags, entry, param) \ 659 CreateFiber((stacksize), (entry), (param)) 661 fib->fib_handle = CreateFiberEx(size - 1, size, 0, fiber_entry,
NULL);
662 if (!fib->fib_handle) {
665 fib->fib_handle = CreateFiberEx(size - 1, size, 0, fiber_entry,
NULL);
666 if (!fib->fib_handle) {
672 ucontext_t *context = &fib->context;
677 ptr = fiber_machine_stack_alloc(size);
678 context->uc_link =
NULL;
679 context->uc_stack.ss_sp = ptr;
680 context->uc_stack.ss_size =
size;
706 if (sth->machine.stack_end && (newfib != oldfib)) {
707 rb_bug(
"fiber_setcontext: sth->machine.stack_end has non zero value");
729 if (!newfib->context.uc_stack.ss_sp && th->
root_fiber != newfib) {
730 rb_bug(
"non_root_fiber->context.uc_stac.ss_sp should not be NULL");
735 SwitchToFiber(newfib->fib_handle);
737 swapcontext(&oldfib->context, &newfib->context);
755 ((_JUMP_BUFFER*)(&cont->
jmpbuf))->Frame =
756 ((_JUMP_BUFFER*)(&
buf))->Frame;
766 if (cont->
machine.register_stack_src) {
778 #define C(a) rse_##a##0, rse_##a##1, rse_##a##2, rse_##a##3, rse_##a##4 779 #define E(a) rse_##a##0= rse_##a##1= rse_##a##2= rse_##a##3= rse_##a##4 780 static volatile int C(a),
C(b),
C(c),
C(d),
C(e);
781 static volatile int C(
f),
C(g),
C(h),
C(i),
C(j);
782 static volatile int C(k),
C(l),
C(m),
C(n),
C(o);
783 static volatile int C(p),
C(q),
C(r),
C(s),
C(t);
787 int rb_dummy_false = 0;
792 if (rb_dummy_false) {
794 E(a) = E(b) = E(c) = E(d) = E(e) =
795 E(
f) = E(g) = E(h) = E(i) = E(j) =
796 E(k) = E(l) = E(m) = E(n) = E(o) =
797 E(p) = E(q) = E(r) = E(s) = E(t) = 0;
798 E(a) = E(b) = E(c) = E(d) = E(e) =
799 E(
f) = E(g) = E(h) = E(i) = E(j) =
800 E(k) = E(l) = E(m) = E(n) = E(o) =
801 E(p) = E(q) = E(r) = E(s) = E(t) = 0;
803 if (curr_bsp < cont->
machine.register_stack_src+cont->
machine.register_stack_size) {
804 register_stack_extend(cont, vp, (
VALUE*)rb_ia64_bsp());
817 #define STACK_PAD_SIZE 1 819 #define STACK_PAD_SIZE 1024 823 #if !STACK_GROW_DIRECTION 824 if (addr_in_prev_frame > &space[0]) {
827 #if STACK_GROW_DIRECTION <= 0 829 if (&space[0] > end) {
838 #if !STACK_GROW_DIRECTION 843 #if STACK_GROW_DIRECTION >= 0 854 #if !STACK_GROW_DIRECTION 861 #define cont_restore_0(cont, vp) register_stack_extend((cont), (vp), (VALUE*)rb_ia64_bsp()) 1009 for (p=current; p; p=p->
next)
1012 for (entry=target; entry->
marker; entry++)
1017 base_point = cur_size;
1018 while (base_point) {
1019 if (target_size >= base_point &&
1027 for (i=0; i < target_size - base_point; i++) {
1033 while (cur_size > base_point) {
1036 current = current->
next;
1043 (*func)(target[i].
data2);
1163 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
1243 #if !FIBER_USE_NATIVE 1304 rb_bug(
"rb_fiber_start: unreachable");
1314 #if FIBER_USE_NATIVE 1316 fib->fib_handle = ConvertThreadToFiber(0);
1329 if (th->
fiber == 0) {
1346 if (root_fiber == fib) {
1377 #if FIBER_USE_NATIVE 1378 fiber_setcontext(next_fib, fib);
1381 if (terminated_machine_stack.ptr) {
1382 if (machine_stack_cache_index < MAX_MACHINE_STACK_CACHE) {
1383 machine_stack_cache[machine_stack_cache_index].ptr = terminated_machine_stack.ptr;
1384 machine_stack_cache[machine_stack_cache_index].size = terminated_machine_stack.size;
1385 machine_stack_cache_index++;
1389 munmap((
void*)terminated_machine_stack.ptr, terminated_machine_stack.size *
sizeof(
VALUE));
1392 rb_bug(
"terminated fiber resumed");
1395 terminated_machine_stack.ptr =
NULL;
1396 terminated_machine_stack.size = 0;
1411 rb_bug(
"rb_fiber_resume: unreachable");
1418 rb_bug(
"rb_fiber_resume: unreachable");
1430 if (th->
fiber == fib) {
1454 #if FIBER_USE_NATIVE 1494 #if FIBER_USE_NATIVE && !defined(_WIN32) 1496 terminated_machine_stack.ptr = fib->ss_sp;
1497 terminated_machine_stack.size = fib->ss_size /
sizeof(
VALUE);
1499 fib->context.uc_stack.ss_sp =
NULL;
1679 #if FIBER_USE_NATIVE 1684 GetSystemInfo(&info);
1685 pagesize = info.dwPageSize;
1687 pagesize = sysconf(_SC_PAGESIZE);
#define RUBY_VM_CHECK_INTS(th)
struct rb_ensure_entry entry
#define THREAD_MUST_BE_RUNNING(th)
#define GetContPtr(obj, ptr)
void rb_bug(const char *fmt,...)
#define ruby_longjmp(env, val)
#define RUBY_TYPED_FREE_IMMEDIATELY
struct rb_vm_protect_tag * protect_tag
static VALUE rb_cContinuation
#define RUBY_VM_SET_INTERRUPT(th)
struct rb_thread_struct::@204 machine
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)
#define FLUSH_REGISTER_WINDOWS
static VALUE lookup_rollback_func(VALUE(*ensure_func)(ANYARGS))
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)
static VALUE rb_fiber_m_resume(int argc, VALUE *argv, VALUE fib)
static const rb_data_type_t cont_data_type
#define GetFiberPtr(obj, ptr)
static rb_fiber_t * root_fiber_alloc(rb_thread_t *th)
VALUE rb_vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, int argc, const VALUE *argv, VALUE passed_block_handler)
static void rb_fiber_terminate(rb_fiber_t *fib)
#define VM_BLOCK_HANDLER_NONE
SSL_METHOD *(* func)(void)
size_t fiber_machine_stack_size
VALUE rb_ary_tmp_new(long capa)
#define STACK_UPPER(x, a, b)
static VALUE fiber_switch(rb_fiber_t *fib, int argc, const VALUE *argv, int is_resume)
VALUE rb_fiber_alive_p(VALUE fibval)
void rb_threadptr_pending_interrupt_enque(rb_thread_t *th, VALUE v)
void rb_raise(VALUE exc, const char *fmt,...)
static void cont_save_thread(rb_context_t *cont, rb_thread_t *th)
#define RUBY_MARK_LEAVE(msg)
VALUE rb_fiber_current(void)
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
static rb_fiber_t * fiber_current(void)
static VALUE fiber_init(VALUE fibval, VALUE proc)
void rb_gc_mark(VALUE ptr)
VALUE local_storage_recursive_hash_for_trace
void rb_define_global_function(const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a global function.
static const rb_data_type_t fiber_data_type
static VALUE cont_capture(volatile int *volatile stat)
void rb_undef_method(VALUE klass, const char *name)
void rb_gc_mark_locations(const VALUE *start, const VALUE *end)
static void cont_free(void *ptr)
struct rb_context_struct::@2 machine
struct rb_context_struct rb_context_t
static VALUE rb_eFiberError
RUBY_SYMBOL_EXPORT_BEGIN typedef unsigned long st_data_t
void rb_exc_raise(VALUE mesg)
static size_t fiber_memsize(const void *ptr)
RUBY_EXTERN VALUE rb_cObject
rb_ensure_entry_t * ensure_array
size_t st_memsize(const st_table *tab)
size_t fiber_vm_stack_size
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type)
static VALUE rb_fiber_init(VALUE fibval)
static void cont_restore_1(rb_context_t *cont)
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
static VALUE fiber_alloc(VALUE klass)
#define RUBY_MARK_ENTER(msg)
VALUE rb_fiber_new(VALUE(*func)(ANYARGS), VALUE obj)
void ruby_Init_Fiber_as_Coroutine(void)
void rb_fiber_start(void)
#define ALLOCA_N(type, n)
static void cont_mark(void *ptr)
static VALUE rb_callcc(VALUE self)
#define MEMCPY(p1, p2, type, n)
static VALUE rb_fiber_m_transfer(int argc, VALUE *argv, VALUE fibval)
static VALUE rb_fiber_s_current(VALUE klass)
#define RARRAY_CONST_PTR(a)
#define REALLOC_N(var, type, n)
#define STACK_DIR_UPPER(a, b)
void rb_vm_stack_to_heap(rb_thread_t *th)
RUBY_SYMBOL_EXPORT_BEGIN void ruby_Init_Continuation_body(void)
static rb_context_t * cont_new(VALUE klass)
VALUE rb_fiber_yield(int argc, const VALUE *argv)
#define RUBY_SYMBOL_EXPORT_END
static VALUE rb_cont_call(int argc, VALUE *argv, VALUE contval)
unsigned char buf[MIME_BUF_SIZE]
static VALUE fiber_store(rb_fiber_t *next_fib, rb_thread_t *th)
#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 RUBY_SYMBOL_EXPORT_BEGIN
static void fiber_mark(void *ptr)
void rb_thread_mark(void *th)
#define SET_MACHINE_STACK_END(p)
struct rb_ensure_list * next
static void cont_init(rb_context_t *cont, rb_thread_t *th)
static VALUE rb_fiber_s_yield(int argc, VALUE *argv, VALUE klass)
enum rb_thread_status status
#define RUBY_FREE_UNLESS_NULL(ptr)
NOINLINE(static VALUE cont_capture(volatile int *volatile stat))
static VALUE make_passing_arg(int argc, const VALUE *argv)
static void cont_restore_thread(rb_context_t *cont)
#define VAR_FROM_MEMORY(var)
VALUE rb_block_proc(void)
#define RUBY_FREE_LEAVE(msg)
#define RUBY_FREE_ENTER(msg)
#define VAR_INITIALIZED(var)
RUBY_EXTERN char * strerror(int)
VALUE rb_obj_is_fiber(VALUE obj)
VALUE rb_proc_new(VALUE(*)(ANYARGS), VALUE)
static rb_fiber_t * fiber_t_alloc(VALUE fibval)
void rb_fiber_mark_self(rb_fiber_t *fib)
#define TypedData_Make_Struct(klass, type, data_type, sval)
struct rb_vm_struct::@201 default_params
#define GetThreadPtr(obj, ptr)
rb_ensure_list_t * ensure_list
static void cont_restore_0(rb_context_t *cont, VALUE *addr_in_prev_frame)
VALUE local_storage_recursive_hash
#define RUBY_EVENT_FIBER_SWITCH
rb_control_frame_t * rb_vm_push_frame(rb_thread_t *th, 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)
void ruby_register_rollback_func_for_ensure(VALUE(*ensure_func)(ANYARGS), VALUE(*rollback_func)(ANYARGS))
static void fiber_free(void *ptr)
VALUE rb_vm_make_jump_tag_but_local_jump(int state, VALUE val)
static size_t cont_memsize(const void *ptr)
static void cont_save_machine_stack(rb_thread_t *th, rb_context_t *cont)
NORETURN(NOINLINE(static void cont_restore_0(rb_context_t *, VALUE *)))
static void rollback_ensure_stack(VALUE self, rb_ensure_list_t *current, rb_ensure_entry_t *target)
struct rb_fiber_struct * prev
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
static rb_fiber_t * return_fiber(void)
struct rb_trace_arg_struct * trace_arg
rb_ensure_list_t * ensure_list
VALUE rb_fiber_transfer(VALUE fibval, int argc, const VALUE *argv)