29 #if !defined(FIBER_USE_NATIVE) 30 # if defined(HAVE_GETCONTEXT) && defined(HAVE_SETCONTEXT) 32 # elif defined(__NetBSD__) 38 # define FIBER_USE_NATIVE 0 42 # define FIBER_USE_NATIVE 0 43 # elif defined(__ia64) 46 # define FIBER_USE_NATIVE 0 47 # elif defined(__GNU__) 53 # define FIBER_USE_NATIVE 0 55 # define FIBER_USE_NATIVE 1 57 # elif defined(_WIN32) 58 # if _WIN32_WINNT >= 0x0400 63 # define FIBER_USE_NATIVE 1 67 #if !defined(FIBER_USE_NATIVE) 68 #define FIBER_USE_NATIVE 0 77 #define RB_PAGE_SIZE (pagesize) 78 #define RB_PAGE_MASK (~(RB_PAGE_SIZE - 1)) 82 #define CAPTURE_JUST_VALID_VM_STACK 1 96 #ifdef CAPTURE_JUST_VALID_VM_STACK 105 VALUE *register_stack;
106 VALUE *register_stack_src;
107 int register_stack_size;
122 #if FIBER_USE_NATIVE && !defined(_WIN32) 123 #define MAX_MACHINE_STACK_CACHE 10 124 static int machine_stack_cache_index = 0;
125 typedef struct machine_stack_cache_struct {
128 } machine_stack_cache_t;
129 static machine_stack_cache_t machine_stack_cache[MAX_MACHINE_STACK_CACHE];
130 static machine_stack_cache_t terminated_machine_stack;
165 #define GetContPtr(obj, ptr) \ 166 TypedData_Get_Struct((obj), rb_context_t, &cont_data_type, (ptr)) 168 #define GetFiberPtr(obj, ptr) do {\ 169 TypedData_Get_Struct((obj), rb_fiber_t, &fiber_data_type, (ptr)); \ 170 if (!(ptr)) rb_raise(rb_eFiberError, "uninitialized fiber"); \ 175 #define THREAD_MUST_BE_RUNNING(th) do { \ 176 if (!(th)->tag) rb_raise(rb_eThreadError, "not running thread"); \ 190 #ifdef CAPTURE_JUST_VALID_VM_STACK 245 if (fib->fib_handle) {
246 DeleteFiber(fib->fib_handle);
254 rb_bug(
"Illegal root fiber parameter");
256 munmap((
void*)fib->ss_sp, fib->ss_size);
287 size =
sizeof(*cont);
289 #ifdef CAPTURE_JUST_VALID_VM_STACK 393 th->
machine.register_stack_end = rb_ia64_bsp();
463 volatile VALUE contval;
478 volatile VALUE contval;
486 #ifdef CAPTURE_JUST_VALID_VM_STACK 517 volatile VALUE value;
541 th->
fiber = sth->fiber;
550 #ifdef CAPTURE_JUST_VALID_VM_STACK 560 th->
stack = sth->stack;
569 th->
state = sth->state;
584 fiber_set_stack_location(
void)
594 fiber_entry(
void *arg)
596 fiber_set_stack_location();
606 #if defined(MAP_STACK) && !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) 607 #define FIBER_STACK_FLAGS (MAP_PRIVATE | MAP_ANON | MAP_STACK) 609 #define FIBER_STACK_FLAGS (MAP_PRIVATE | MAP_ANON) 613 fiber_machine_stack_alloc(
size_t size)
617 if (machine_stack_cache_index > 0) {
618 if (machine_stack_cache[machine_stack_cache_index - 1].
size == (
size /
sizeof(
VALUE))) {
619 ptr = machine_stack_cache[machine_stack_cache_index - 1].ptr;
620 machine_stack_cache_index--;
621 machine_stack_cache[machine_stack_cache_index].ptr =
NULL;
622 machine_stack_cache[machine_stack_cache_index].size = 0;
626 rb_bug(
"machine_stack_cache size is not canonicalized");
634 ptr = mmap(
NULL,
size, PROT_READ | PROT_WRITE, FIBER_STACK_FLAGS, -1, 0);
635 if (ptr == MAP_FAILED) {
641 if (mprotect(page, RB_PAGE_SIZE, PROT_NONE) < 0) {
651 fiber_initialize_machine_stack_context(
rb_fiber_t *fib,
size_t size)
656 fib->fib_handle = CreateFiberEx(
size - 1,
size, 0, fiber_entry,
NULL);
657 if (!fib->fib_handle) {
660 fib->fib_handle = CreateFiberEx(
size - 1,
size, 0, fiber_entry,
NULL);
661 if (!fib->fib_handle) {
667 ucontext_t *context = &fib->context;
672 ptr = fiber_machine_stack_alloc(
size);
673 context->uc_link =
NULL;
674 context->uc_stack.ss_sp = ptr;
675 context->uc_stack.ss_size =
size;
702 rb_bug(
"fiber_setcontext: sth->machine.stack_end has non zero value");
725 rb_bug(
"non_root_fiber->context.uc_stac.ss_sp should not be NULL");
731 SwitchToFiber(newfib->fib_handle);
733 swapcontext(&oldfib->context, &newfib->context);
752 ((_JUMP_BUFFER*)(&
buf))->Frame;
774 #define C(a) rse_##a##0, rse_##a##1, rse_##a##2, rse_##a##3, rse_##a##4 775 #define E(a) rse_##a##0= rse_##a##1= rse_##a##2= rse_##a##3= rse_##a##4 776 static volatile int C(a),
C(b),
C(c),
C(d),
C(e);
777 static volatile int C(
f),
C(g),
C(h),
C(i),
C(j);
778 static volatile int C(k),
C(l),
C(m),
C(n),
C(o);
779 static volatile int C(p),
C(q),
C(r),
C(s),
C(
t);
783 int rb_dummy_false = 0;
788 if (rb_dummy_false) {
790 E(a) = E(b) = E(c) = E(d) = E(e) =
791 E(
f) = E(g) = E(h) = E(i) = E(j) =
792 E(k) = E(l) = E(m) = E(n) = E(o) =
793 E(p) = E(q) = E(r) = E(s) = E(
t) = 0;
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;
799 if (curr_bsp < cont->machine.register_stack_src+
cont->
machine.register_stack_size) {
800 register_stack_extend(
cont, vp, (
VALUE*)rb_ia64_bsp());
813 #define STACK_PAD_SIZE 1 815 #define STACK_PAD_SIZE 1024 819 #if !STACK_GROW_DIRECTION 820 if (addr_in_prev_frame > &space[0]) {
823 #if STACK_GROW_DIRECTION <= 0 825 if (&space[0] > end) {
834 #if !STACK_GROW_DIRECTION 839 #if STACK_GROW_DIRECTION >= 0 850 #if !STACK_GROW_DIRECTION 857 #define cont_restore_0(cont, vp) register_stack_extend((cont), (vp), (VALUE*)rb_ia64_bsp()) 987 for (p=current; p; p=p->
next)
990 for (entry=target; entry->
marker; entry++)
995 base_point = cur_size;
997 if (target_size >= base_point &&
1005 for (i=0; i < target_size - base_point; i++) {
1011 while (cur_size > base_point) {
1014 current = current->
next;
1021 (*func)(target[i].
data2);
1199 #if VM_DEBUG_BP_CHECK 1200 th->
cfp->bp_check = 0;
1216 #if !FIBER_USE_NATIVE 1248 if (root_fiber == curr) {
1266 #if FIBER_USE_NATIVE && !defined(_WIN32) 1268 terminated_machine_stack.ptr = fib->ss_sp;
1269 terminated_machine_stack.size = fib->ss_size /
sizeof(
VALUE);
1271 fib->context.uc_stack.ss_sp =
NULL;
1319 rb_bug(
"rb_fiber_start: unreachable");
1329 #if FIBER_USE_NATIVE 1331 fib->fib_handle = ConvertThreadToFiber(0);
1344 if (th->
fiber == 0) {
1368 #if !FIBER_USE_NATIVE 1373 #if FIBER_USE_NATIVE 1374 fiber_setcontext(next_fib, fib);
1376 if (terminated_machine_stack.ptr) {
1377 if (machine_stack_cache_index < MAX_MACHINE_STACK_CACHE) {
1378 machine_stack_cache[machine_stack_cache_index].ptr = terminated_machine_stack.ptr;
1379 machine_stack_cache[machine_stack_cache_index].size = terminated_machine_stack.size;
1380 machine_stack_cache_index++;
1384 munmap((
void*)terminated_machine_stack.ptr, terminated_machine_stack.size *
sizeof(
VALUE));
1387 rb_bug(
"terminated fiber resumed");
1390 terminated_machine_stack.ptr =
NULL;
1391 terminated_machine_stack.size = 0;
1400 #if !FIBER_USE_NATIVE 1418 if (th->
fiber == fibval) {
1433 if (th->
fiber != fibval) {
1446 #if FIBER_USE_NATIVE 1452 fiber_setcontext(fib, oldfib);
1471 #if !FIBER_USE_NATIVE 1474 rb_bug(
"rb_fiber_resume: unreachable");
1663 #if FIBER_USE_NATIVE 1668 GetSystemInfo(&info);
1669 pagesize = info.dwPageSize;
1671 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
#define rb_gc_mark_locations(start, end)
static VALUE rb_cContinuation
#define RUBY_VM_SET_INTERRUPT(th)
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 cont_capture(volatile int *stat)
static VALUE lookup_rollback_func(VALUE(*ensure_func)(ANYARGS))
int st_insert(st_table *, st_data_t, st_data_t)
#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)
static void rb_fiber_terminate(rb_fiber_t *fib)
SSL_METHOD *(* func)(void)
void st_free_table(st_table *)
VALUE rb_fiber_yield(int argc, VALUE *argv)
size_t fiber_machine_stack_size
VALUE rb_ary_tmp_new(long capa)
static VALUE make_passing_arg(int argc, VALUE *argv)
#define VM_ENVVAL_BLOCK_PTR(v)
#define STACK_UPPER(x, a, b)
VALUE rb_fiber_alive_p(VALUE fibval)
static VALUE fiber_switch(VALUE fibval, int argc, VALUE *argv, int is_resume)
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 VALUE fiber_init(VALUE fibval, VALUE proc)
void rb_gc_mark(VALUE ptr)
static void fiber_link_join(rb_fiber_t *fib)
void rb_define_global_function(const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a global function.
VALUE rb_vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, int argc, const VALUE *argv, const rb_block_t *blockptr)
static const rb_data_type_t fiber_data_type
void rb_undef_method(VALUE klass, const char *name)
struct rb_thread_struct::@169 machine
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)
int st_lookup(st_table *, st_data_t, st_data_t *)
VALUE rb_fiber_resume(VALUE fibval, int argc, VALUE *argv)
static VALUE return_fiber(void)
VALUE * rb_vm_ep_local_ep(VALUE *ep)
RUBY_EXTERN VALUE rb_cObject
rb_ensure_entry_t * ensure_array
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)
#define RUBY_SYMBOL_EXPORT_END
static VALUE rb_cont_call(int argc, VALUE *argv, VALUE contval)
unsigned char buf[MIME_BUF_SIZE]
#define STACK_GROW_DIR_DETECTION
static VALUE fiber_store(rb_fiber_t *next_fib)
struct rb_fiber_struct rb_fiber_t
#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
st_table * st_init_numtable(void)
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)
struct rb_fiber_struct * next_fiber
static void cont_restore_thread(rb_context_t *cont)
struct rb_vm_struct::@168 default_params
VALUE rb_block_proc(void)
size_t st_memsize(const st_table *)
const rb_method_entry_t * me
#define RUBY_FREE_LEAVE(msg)
#define RUBY_FREE_ENTER(msg)
RUBY_EXTERN char * strerror(int)
VALUE rb_obj_is_fiber(VALUE obj)
VALUE rb_fiber_transfer(VALUE fib, int argc, VALUE *argv)
VALUE rb_proc_new(VALUE(*)(ANYARGS), VALUE)
static rb_fiber_t * fiber_t_alloc(VALUE fibval)
#define TypedData_Make_Struct(klass, type, data_type, sval)
struct rb_fiber_struct * prev_fiber
#define GetThreadPtr(obj, ptr)
rb_ensure_list_t * ensure_list
static void cont_restore_0(rb_context_t *cont, VALUE *addr_in_prev_frame)
static void fiber_link_remove(rb_fiber_t *fib)
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)
static rb_thread_t * GET_THREAD(void)
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
struct rb_trace_arg_struct * trace_arg
rb_ensure_list_t * ensure_list
NOINLINE(static VALUE cont_capture(volatile int *stat))