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
103 VALUE *machine_register_stack;
104 VALUE *machine_register_stack_src;
105 int machine_register_stack_size;
118 #if FIBER_USE_NATIVE && !defined(_WIN32)
119 #define MAX_MAHINE_STACK_CACHE 10
120 static int machine_stack_cache_index = 0;
121 typedef struct machine_stack_cache_struct {
124 } machine_stack_cache_t;
125 static machine_stack_cache_t machine_stack_cache[MAX_MAHINE_STACK_CACHE];
126 static machine_stack_cache_t terminated_machine_stack;
155 #define GetContPtr(obj, ptr) \
156 TypedData_Get_Struct((obj), rb_context_t, &cont_data_type, (ptr))
158 #define GetFiberPtr(obj, ptr) do {\
159 TypedData_Get_Struct((obj), rb_fiber_t, &fiber_data_type, (ptr)); \
160 if (!(ptr)) rb_raise(rb_eFiberError, "uninitialized fiber"); \
165 #define THREAD_MUST_BE_RUNNING(th) do { \
166 if (!(th)->tag) rb_raise(rb_eThreadError, "not running thread"); \
180 #ifdef CAPTURE_JUST_VALID_VM_STACK
184 rb_gc_mark_localtion(cont->
vm_stack,
207 if (cont->machine_register_stack) {
209 cont->machine_register_stack + cont->machine_register_stack_size);
234 if (fib->fib_handle) {
235 DeleteFiber(fib->fib_handle);
241 if (fib->context.uc_stack.ss_sp) {
243 rb_bug(
"Illegal root fiber parameter");
245 munmap((
void*)fib->context.uc_stack.ss_sp, fib->context.uc_stack.ss_size);
275 size =
sizeof(*cont);
277 #ifdef CAPTURE_JUST_VALID_VM_STACK
282 size += n *
sizeof(*cont->
vm_stack);
289 if (cont->machine_register_stack) {
290 size += cont->machine_register_stack_size *
sizeof(*cont->machine_register_stack);
380 th->machine_register_stack_end = rb_ia64_bsp();
404 size = cont->machine_register_stack_size = th->machine_register_stack_end - th->machine_register_stack_start;
405 cont->machine_register_stack_src = th->machine_register_stack_start;
406 if (cont->machine_register_stack) {
413 MEMCPY(cont->machine_register_stack, cont->machine_register_stack_src,
VALUE, size);
449 volatile VALUE contval;
454 cont->
self = contval;
464 volatile VALUE contval;
469 contval = cont->
self;
472 #ifdef CAPTURE_JUST_VALID_VM_STACK
487 volatile VALUE value;
511 th->
fiber = sth->fiber;
520 #ifdef CAPTURE_JUST_VALID_VM_STACK
530 th->
stack = sth->stack;
539 th->
state = sth->state;
552 fiber_set_stack_location(
void)
562 fiber_entry(
void *arg)
564 fiber_set_stack_location();
574 #if defined(MAP_STACK) && !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__)
575 #define FIBER_STACK_FLAGS (MAP_PRIVATE | MAP_ANON | MAP_STACK)
577 #define FIBER_STACK_FLAGS (MAP_PRIVATE | MAP_ANON)
581 fiber_machine_stack_alloc(
size_t size)
585 if (machine_stack_cache_index > 0) {
586 if (machine_stack_cache[machine_stack_cache_index - 1].size == (size /
sizeof(
VALUE))) {
587 ptr = machine_stack_cache[machine_stack_cache_index - 1].ptr;
588 machine_stack_cache_index--;
589 machine_stack_cache[machine_stack_cache_index].ptr =
NULL;
590 machine_stack_cache[machine_stack_cache_index].size = 0;
594 rb_bug(
"machine_stack_cache size is not canonicalized");
601 ptr = mmap(
NULL, size, PROT_READ | PROT_WRITE, FIBER_STACK_FLAGS, -1, 0);
602 if (ptr == MAP_FAILED) {
608 if (mprotect(page, RB_PAGE_SIZE, PROT_NONE) < 0) {
618 fiber_initialize_machine_stack_context(
rb_fiber_t *fib,
size_t size)
623 fib->fib_handle = CreateFiberEx(size - 1, size, 0, fiber_entry,
NULL);
624 if (!fib->fib_handle) {
627 fib->fib_handle = CreateFiberEx(size - 1, size, 0, fiber_entry,
NULL);
628 if (!fib->fib_handle) {
634 ucontext_t *context = &fib->context;
639 ptr = fiber_machine_stack_alloc(size);
640 context->uc_link =
NULL;
641 context->uc_stack.ss_sp = ptr;
642 context->uc_stack.ss_size =
size;
667 rb_bug(
"fiber_setcontext: sth->machine_stack_end has non zero value");
690 rb_bug(
"non_root_fiber->context.uc_stac.ss_sp should not be NULL");
696 SwitchToFiber(newfib->fib_handle);
698 swapcontext(&oldfib->context, &newfib->context);
716 ((_JUMP_BUFFER*)(&cont->
jmpbuf))->Frame =
717 ((_JUMP_BUFFER*)(&
buf))->Frame;
727 if (cont->machine_register_stack_src) {
728 MEMCPY(cont->machine_register_stack_src, cont->machine_register_stack,
729 VALUE, cont->machine_register_stack_size);
739 #define C(a) rse_##a##0, rse_##a##1, rse_##a##2, rse_##a##3, rse_##a##4
740 #define E(a) rse_##a##0= rse_##a##1= rse_##a##2= rse_##a##3= rse_##a##4
741 static volatile int C(a),
C(b),
C(c),
C(d),
C(e);
742 static volatile int C(
f),
C(g),
C(h),
C(
i),
C(j);
743 static volatile int C(k),
C(l),
C(m),
C(n),
C(o);
744 static volatile int C(
p),
C(q),
C(r),
C(s),
C(t);
748 int rb_dummy_false = 0;
753 if (rb_dummy_false) {
755 E(a) = E(b) = E(c) = E(d) = E(e) =
756 E(
f) = E(g) = E(h) = E(
i) = E(j) =
757 E(k) = E(l) = E(m) = E(n) = E(o) =
758 E(
p) = E(q) = E(r) = E(s) = E(t) = 0;
759 E(a) = E(b) = E(c) = E(d) = E(e) =
760 E(
f) = E(g) = E(h) = E(
i) = E(j) =
761 E(k) = E(l) = E(m) = E(n) = E(o) =
762 E(
p) = E(q) = E(r) = E(s) = E(t) = 0;
764 if (curr_bsp < cont->machine_register_stack_src+cont->machine_register_stack_size) {
765 register_stack_extend(cont, vp, (
VALUE*)rb_ia64_bsp());
778 #define STACK_PAD_SIZE 1
780 #define STACK_PAD_SIZE 1024
784 #if !STACK_GROW_DIRECTION
785 if (addr_in_prev_frame > &space[0]) {
788 #if STACK_GROW_DIRECTION <= 0
790 if (&space[0] > end) {
799 #if !STACK_GROW_DIRECTION
804 #if STACK_GROW_DIRECTION >= 0
815 #if !STACK_GROW_DIRECTION
822 #define cont_restore_0(cont, vp) register_stack_extend((cont), (vp), (VALUE*)rb_ia64_bsp())
1088 #if VM_DEBUG_BP_CHECK
1089 th->
cfp->bp_check = 0;
1105 #if !FIBER_USE_NATIVE
1137 if (root_fiber == curr) {
1155 #if FIBER_USE_NATIVE && !defined(_WIN32)
1157 terminated_machine_stack.ptr = fib->context.uc_stack.ss_sp;
1158 terminated_machine_stack.size = fib->context.uc_stack.ss_size /
sizeof(
VALUE);
1159 fib->context.uc_stack.ss_sp =
NULL;
1208 rb_bug(
"rb_fiber_start: unreachable");
1218 #if FIBER_USE_NATIVE
1220 fib->fib_handle = ConvertThreadToFiber(0);
1233 if (th->
fiber == 0) {
1257 #if !FIBER_USE_NATIVE
1262 #if FIBER_USE_NATIVE
1263 fiber_setcontext(next_fib, fib);
1265 if (terminated_machine_stack.ptr) {
1266 if (machine_stack_cache_index < MAX_MAHINE_STACK_CACHE) {
1267 machine_stack_cache[machine_stack_cache_index].ptr = terminated_machine_stack.ptr;
1268 machine_stack_cache[machine_stack_cache_index].size = terminated_machine_stack.size;
1269 machine_stack_cache_index++;
1273 munmap((
void*)terminated_machine_stack.ptr, terminated_machine_stack.size *
sizeof(
VALUE));
1276 rb_bug(
"terminated fiber resumed");
1279 terminated_machine_stack.ptr =
NULL;
1280 terminated_machine_stack.size = 0;
1289 #if !FIBER_USE_NATIVE
1307 if (th->
fiber == fibval) {
1322 if (th->
fiber != fibval) {
1334 cont->
value = value;
1335 #if FIBER_USE_NATIVE
1341 fiber_setcontext(fib, oldfib);
1360 #if !FIBER_USE_NATIVE
1363 rb_bug(
"rb_fiber_resume: unreachable");
1552 #if FIBER_USE_NATIVE
1557 GetSystemInfo(&info);
1558 pagesize = info.dwPageSize;
1560 pagesize = sysconf(_SC_PAGESIZE);
1573 #if defined __GNUC__ && __GNUC__ >= 4
1574 #pragma GCC visibility push(default)
1596 #if defined __GNUC__ && __GNUC__ >= 4
1597 #pragma GCC visibility pop
size_t machine_stack_size
#define RUBY_VM_CHECK_INTS(th)
VALUE rb_ary_new4(long n, const VALUE *elts)
#define THREAD_MUST_BE_RUNNING(th)
#define GetContPtr(obj, ptr)
void rb_bug(const char *fmt,...)
#define ruby_longjmp(env, val)
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)
struct rb_vm_struct::@131 default_params
#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)
void st_free_table(st_table *)
VALUE rb_fiber_yield(int argc, VALUE *argv)
size_t fiber_machine_stack_size
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)
static void cont_free(void *ptr)
struct rb_context_struct rb_context_t
static VALUE rb_eFiberError
void rb_exc_raise(VALUE mesg)
static size_t fiber_memsize(const void *ptr)
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
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)
VALUE * machine_stack_start
static VALUE rb_fiber_s_current(VALUE klass)
#define REALLOC_N(var, type, n)
SSL_METHOD *(* func)(void)
#define STACK_DIR_UPPER(a, b)
void rb_vm_stack_to_heap(rb_thread_t *th)
static rb_context_t * cont_new(VALUE klass)
static VALUE rb_cont_call(int argc, VALUE *argv, VALUE contval)
unsigned char buf[MIME_BUF_SIZE]
VALUE rb_exc_new2(VALUE etype, const char *s)
#define STACK_GROW_DIR_DETECTION
static VALUE fiber_store(rb_fiber_t *next_fib)
struct rb_fiber_struct rb_fiber_t
static void fiber_mark(void *ptr)
void rb_thread_mark(void *th)
#define SET_MACHINE_STACK_END(p)
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
VALUE * machine_stack_end
static void cont_restore_thread(rb_context_t *cont)
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)
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)
static void cont_restore_0(rb_context_t *cont, VALUE *addr_in_prev_frame)
void ruby_Init_Continuation_body(void)
static void fiber_link_remove(rb_fiber_t *fib)
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)
size_t machine_stack_maxsize
NORETURN(NOINLINE(static void cont_restore_0(rb_context_t *, VALUE *)))
static rb_thread_t * GET_THREAD(void)
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
VALUE * machine_stack_src
struct rb_trace_arg_struct * trace_arg
NOINLINE(static VALUE cont_capture(volatile int *stat))