Ruby
2.7.2p137(2020-10-01revision5445e0435260b449decf2ac16f9d09bae3cafe72)
|
Go to the documentation of this file.
25 static const int DEBUG = 0;
27 #define RB_PAGE_SIZE (pagesize)
28 #define RB_PAGE_MASK (~(RB_PAGE_SIZE - 1))
32 static VALUE rb_cContinuation;
33 static VALUE rb_cFiber;
34 static VALUE rb_eFiberError;
35 #ifdef RB_EXPERIMENTAL_FIBER_POOL
36 static VALUE rb_cFiberPool;
39 #define CAPTURE_JUST_VALID_VM_STACK 1
42 #ifdef COROUTINE_LIMITED_ADDRESS_SPACE
43 #define FIBER_POOL_ALLOCATION_FREE
44 #define FIBER_POOL_INITIAL_SIZE 8
45 #define FIBER_POOL_ALLOCATION_MAXIMUM_SIZE 32
47 #define FIBER_POOL_INITIAL_SIZE 32
48 #define FIBER_POOL_ALLOCATION_MAXIMUM_SIZE 1024
58 #ifdef CAPTURE_JUST_VALID_VM_STACK
95 #ifdef FIBER_POOL_ALLOCATION_FREE
138 #ifdef FIBER_POOL_ALLOCATION_FREE
146 #ifdef FIBER_POOL_ALLOCATION_FREE
220 #define FIBER_CREATED_P(fiber) ((fiber)->status == FIBER_CREATED)
221 #define FIBER_RESUMED_P(fiber) ((fiber)->status == FIBER_RESUMED)
222 #define FIBER_SUSPENDED_P(fiber) ((fiber)->status == FIBER_SUSPENDED)
223 #define FIBER_TERMINATED_P(fiber) ((fiber)->status == FIBER_TERMINATED)
224 #define FIBER_RUNNABLE_P(fiber) (FIBER_CREATED_P(fiber) || FIBER_SUSPENDED_P(fiber))
248 #if defined(MAP_STACK) && !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__)
249 #define FIBER_STACK_FLAGS (MAP_PRIVATE | MAP_ANON | MAP_STACK)
251 #define FIBER_STACK_FLAGS (MAP_PRIVATE | MAP_ANON)
254 #define ERRNOMSG strerror(errno)
259 fiber_pool_vacancy_pointer(
void * base,
size_t size)
313 fiber_pool_stack_reset(&vacancy->
stack);
322 vacancy->
next = head;
324 #ifdef FIBER_POOL_ALLOCATION_FREE
326 head->previous = vacancy;
333 #ifdef FIBER_POOL_ALLOCATION_FREE
338 vacancy->
next->previous = vacancy->previous;
341 if (vacancy->previous) {
342 vacancy->previous->
next = vacancy->
next;
351 fiber_pool_vacancy_pop(
struct fiber_pool * pool)
356 fiber_pool_vacancy_remove(vacancy);
363 fiber_pool_vacancy_pop(
struct fiber_pool * pool)
386 fiber_pool_vacancy_reset(vacancy);
390 return fiber_pool_vacancy_push(vacancy, vacancies);
398 fiber_pool_allocate_memory(
size_t *
count,
size_t stride)
408 void * base = VirtualAlloc(0, (*
count)*stride, MEM_COMMIT, PAGE_READWRITE);
411 *
count = (*count) >> 1;
420 if (base == MAP_FAILED) {
422 *
count = (*count) >> 1;
460 #ifdef FIBER_POOL_ALLOCATION_FREE
461 allocation->used = 0;
471 for (
size_t i = 0;
i <
count;
i += 1) {
478 if (!VirtualProtect(page,
RB_PAGE_SIZE, PAGE_READWRITE | PAGE_GUARD, &old_protect)) {
479 VirtualFree(allocation->
base, 0, MEM_RELEASE);
489 vacancies = fiber_pool_vacancy_initialize(
495 #ifdef FIBER_POOL_ALLOCATION_FREE
503 #ifdef FIBER_POOL_ALLOCATION_FREE
504 if (allocation->
next) {
505 allocation->
next->previous = allocation;
508 allocation->previous =
NULL;
538 #ifdef FIBER_POOL_ALLOCATION_FREE
550 for (
i = 0;
i < allocation->
count;
i += 1) {
556 fiber_pool_vacancy_remove(vacancy);
560 VirtualFree(allocation->
base, 0, MEM_RELEASE);
565 if (allocation->previous) {
566 allocation->previous->
next = allocation->
next;
573 if (allocation->
next) {
574 allocation->
next->previous = allocation->previous;
612 #ifdef FIBER_POOL_ALLOCATION_FREE
616 fiber_pool_stack_reset(&vacancy->
stack);
618 return vacancy->
stack;
626 void * base = fiber_pool_stack_base(
stack);
634 #if VM_CHECK_MODE > 0 && defined(MADV_DONTNEED)
636 madvise(base,
size, MADV_DONTNEED);
637 #elif defined(MADV_FREE_REUSABLE)
638 madvise(base,
size, MADV_FREE_REUSABLE);
639 #elif defined(MADV_FREE)
640 madvise(base,
size, MADV_FREE);
641 #elif defined(MADV_DONTNEED)
642 madvise(base,
size, MADV_DONTNEED);
643 #elif defined(_WIN32)
644 VirtualAlloc(base,
size, MEM_RESET, PAGE_READWRITE);
664 fiber_pool_vacancy_reset(vacancy);
670 #ifdef FIBER_POOL_ALLOCATION_FREE
673 allocation->used -= 1;
676 if (allocation->used == 0) {
677 fiber_pool_allocation_free(allocation);
680 fiber_pool_stack_free(&vacancy->
stack);
685 fiber_pool_stack_free(&vacancy->
stack);
698 fiber_initialize_coroutine(
rb_fiber_t *fiber,
size_t * vm_stack_size)
702 void * vm_stack =
NULL;
710 #ifdef COROUTINE_PRIVATE_STACK
736 if (DEBUG)
fprintf(
stderr,
"fiber_stack_release: %p, stack.base=%p\n", (
void*)fiber, fiber->stack.base);
740 fiber_pool_stack_release(&fiber->
stack);
764 #if VM_CHECK_MODE > 0
767 switch (fiber->status) {
828 if (!fiber)
rb_raise(rb_eFiberError,
"uninitialized fiber");
835 #define THREAD_MUST_BE_RUNNING(th) do { \
836 if (!(th)->ec->tag) rb_raise(rb_eThreadError, "not running thread"); \
846 cont_compact(
void *
ptr)
872 #ifdef CAPTURE_JUST_VALID_VM_STACK
921 coroutine_destroy(&fiber->
context);
922 if (!fiber_is_root_p(fiber)) {
923 fiber_stack_release(fiber);
938 cont_memsize(
const void *
ptr)
943 size =
sizeof(*cont);
945 #ifdef CAPTURE_JUST_VALID_VM_STACK
983 fiber_compact(
void *
ptr)
990 cont_compact(&fiber->
cont);
995 fiber_mark(
void *
ptr)
1002 cont_mark(&fiber->
cont);
1007 fiber_free(
void *
ptr)
1018 cont_free(&fiber->
cont);
1023 fiber_memsize(
const void *
ptr)
1026 size_t size =
sizeof(*fiber);
1028 const rb_thread_t *th = rb_ec_thread_ptr(saved_ec);
1036 size += cont_memsize(&fiber->
cont);
1080 {cont_mark, cont_free, cont_memsize, cont_compact},
1112 cont_save_thread(cont, th);
1117 cont_init_mjit_cont(cont);
1124 volatile VALUE contval;
1129 cont->
self = contval;
1130 cont_init(cont, th);
1139 cont_init_mjit_cont(&fiber->
cont);
1147 while (p < ec->
cfp->
sp) {
1159 while (
cfp != end_of_cfp) {
1174 cont_capture(
volatile int *
volatile stat)
1178 volatile VALUE contval;
1183 cont = cont_new(rb_cContinuation);
1184 contval = cont->
self;
1186 #ifdef CAPTURE_JUST_VALID_VM_STACK
1204 cont_save_machine_stack(th, cont);
1217 *entry++ = p->
entry;
1226 value = cont->
value;
1242 ec_switch(th, fiber);
1265 ec_switch(th, fiber);
1273 #ifdef CAPTURE_JUST_VALID_VM_STACK
1330 fiber_restore_thread(th, new_fiber);
1346 cont_restore_thread(cont);
1354 _JUMP_BUFFER *
bp = (
void*)&cont->
jmpbuf;
1355 bp->Frame = ((_JUMP_BUFFER*)((
void*)&
buf))->Frame;
1374 #define STACK_PAD_SIZE 1
1376 #define STACK_PAD_SIZE 1024
1380 #if !STACK_GROW_DIRECTION
1381 if (addr_in_prev_frame > &space[0]) {
1384 #if STACK_GROW_DIRECTION <= 0
1386 if (&space[0] > end) {
1391 cont_restore_0(cont, &space[0]);
1395 #if !STACK_GROW_DIRECTION
1400 #if STACK_GROW_DIRECTION >= 0
1411 #if !STACK_GROW_DIRECTION
1415 cont_restore_1(cont);
1502 rb_callcc(
VALUE self)
1504 volatile int called;
1505 volatile VALUE val = cont_capture(&called);
1545 lookup_rollback_func(
e_proc *ensure_func)
1567 for (p=current; p; p=p->
next)
1570 for (entry=target; entry->
marker; entry++)
1575 base_point = cur_size;
1576 while (base_point) {
1577 if (target_size >= base_point &&
1578 p->
entry.
marker == target[target_size - base_point].marker)
1585 for (
i=0;
i < target_size - base_point;
i++) {
1586 if (!lookup_rollback_func(target[
i].
e_proc)) {
1591 while (cur_size > base_point) {
1594 current = current->
next;
1598 for (j = 0; j <
i; j++) {
1599 func = lookup_rollback_func(target[
i - j - 1].
e_proc);
1601 (*func)(target[
i - j - 1].
data2);
1627 if (cont_thread_value(cont) != th->
self) {
1643 cont_restore_0(cont, &contval);
1716 {fiber_mark, fiber_free, fiber_memsize, fiber_compact,},
1727 fiber_t_alloc(
VALUE fiber_value)
1740 cont_init(&fiber->
cont, th);
1791 return fiber_initialize(
self,
rb_block_proc(), &shared_fiber_pool);
1797 return fiber_initialize(fiber_alloc(rb_cFiber),
rb_proc_new(func,
obj), &shared_fiber_pool);
1800 static void rb_fiber_terminate(
rb_fiber_t *fiber,
int need_interrupt);
1802 #define PASS_KW_SPLAT (rb_empty_keyword_given_p() ? RB_PASS_EMPTY_KEYWORDS : rb_keyword_given_p())
1811 int need_interrupt =
TRUE;
1848 need_interrupt =
TRUE;
1851 rb_fiber_terminate(fiber, need_interrupt);
1858 VALUE fiber_value = fiber_alloc(rb_cFiber);
1869 #ifdef COROUTINE_PRIVATE_STACK
1870 fiber->
stack = fiber_pool_stack_acquire(&shared_fiber_pool);
1873 coroutine_initialize_main(&fiber->
context);
1928 root_fiber_alloc(rb_ec_thread_ptr(ec));
1945 if (root_fiber == fiber) {
1946 rb_raise(rb_eFiberError,
"can't yield from root fiber");
1973 fiber = root_fiber_alloc(th);
1977 fiber_prepare_stack(next_fiber);
1986 fiber_setcontext(next_fiber, fiber);
2010 return make_passing_arg(
argc,
argv);
2013 if (cont_thread_value(cont) != th->
self) {
2014 rb_raise(rb_eFiberError,
"fiber called across threads");
2017 rb_raise(rb_eFiberError,
"fiber called across stack rewinding barrier");
2020 value =
rb_exc_new2(rb_eFiberError,
"dead fiber called");
2034 cont->
value = value;
2043 fiber->
prev = fiber_current();
2052 value = fiber_store(fiber, th);
2055 fiber_stack_release(fiber);
2078 rb_fiber_terminate(
rb_fiber_t *fiber,
int need_interrupt)
2086 coroutine_destroy(&fiber->
context);
2091 next_fiber = return_fiber();
2102 rb_raise(rb_eFiberError,
"cannot raise exception on unborn fiber");
2105 if (fiber->
prev != 0 || fiber_is_root_p(fiber)) {
2106 rb_raise(rb_eFiberError,
"double resume");
2110 rb_raise(rb_eFiberError,
"cannot resume transferred Fiber");
2113 return fiber_switch(fiber,
argc,
argv, 1, kw_splat);
2125 return fiber_switch(return_fiber(),
argc,
argv, 0, kw_splat);
2303 fiber_to_s(
VALUE fiber_value)
2305 const rb_fiber_t *fiber = fiber_ptr(fiber_value);
2307 char status_info[0x20];
2310 snprintf(status_info, 0x20,
" (%s, transferred)", fiber_status_name(fiber->status));
2313 snprintf(status_info, 0x20,
" (%s)", fiber_status_name(fiber->status));
2318 strlcat(status_info,
">",
sizeof(status_info));
2327 #ifdef HAVE_WORKING_FORK
2340 #ifdef RB_EXPERIMENTAL_FIBER_POOL
2342 fiber_pool_free(
void *
ptr)
2354 fiber_pool_memsize(
const void *
ptr)
2357 size_t size =
sizeof(*fiber_pool);
2366 {
NULL, fiber_pool_free, fiber_pool_memsize,},
2431 GetSystemInfo(&info);
2432 pagesize = info.dwPageSize;
2440 char * fiber_shared_fiber_pool_free_stacks =
getenv(
"RUBY_SHARED_FIBER_POOL_FREE_STACKS");
2441 if (fiber_shared_fiber_pool_free_stacks) {
2442 shared_fiber_pool.
free_stacks =
atoi(fiber_shared_fiber_pool_free_stacks);
2455 #ifdef RB_EXPERIMENTAL_FIBER_POOL
2458 rb_define_method(rb_cFiberPool,
"initialize", rb_fiber_pool_initialize, -1);
#define FIBER_TERMINATED_P(fiber)
NOINLINE(static VALUE cont_capture(volatile int *volatile stat))
struct rb_vm_protect_tag * protect_tag
void rb_ec_set_vm_stack(rb_execution_context_t *ec, VALUE *stack, size_t size)
struct cont_saved_vm_stack saved_vm_stack
#define RUBY_SYMBOL_EXPORT_END
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
VALUE rb_proc_new(type *q, VALUE w)
Creates a rb_cProc instance.
#define TypedData_Make_Struct(klass, type, data_type, sval)
#define FIBER_RUNNABLE_P(fiber)
rb_execution_context_t * ruby_current_execution_context_ptr
RUBY_EXTERN size_t strlcat(char *, const char *, size_t)
void * ruby_mimmalloc(size_t size)
#define RUBY_MARK_LEAVE(msg)
struct rb_context_struct rb_context_t
struct fiber_pool_allocation * next
MJIT_FUNC_EXPORTED VALUE rb_vm_invoke_proc(rb_execution_context_t *ec, rb_proc_t *proc, int argc, const VALUE *argv, int kw_splat, VALUE passed_block_handler)
NORETURN(NOINLINE(static void cont_restore_0(rb_context_t *, VALUE *)))
struct coroutine_context context
#define VAR_INITIALIZED(var)
void rb_gc_mark_locations(const VALUE *start, const VALUE *end)
#define EXEC_EVENT_HOOK(ec_, flag_, self_, id_, called_id_, klass_, data_)
const struct rb_block block
#define FIBER_SUSPENDED_P(fiber)
#define FLUSH_REGISTER_WINDOWS
VALUE rb_block_to_s(VALUE self, const struct rb_block *block, const char *additional_info)
st_table * st_init_numtable(void)
struct mjit_cont * mjit_cont
struct fiber_pool_vacancy * vacancies
VALUE rb_gc_location(VALUE value)
#define FIBER_STACK_FLAGS
void ruby_Init_Fiber_as_Coroutine(void)
void rb_fiber_mark_self(const rb_fiber_t *fiber)
struct rb_ensure_entry entry
void rb_define_global_function(const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a global function.
rb_ensure_list_t * ensure_list
#define FIBER_POOL_ALLOCATION_MAXIMUM_SIZE
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
int rb_signal_buff_size(void)
VALUE rb_make_exception(int argc, const VALUE *argv)
Make an Exception object from the list of arguments in a manner similar to Kernel#raise.
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
#define RUBY_VM_CHECK_INTS(ec)
struct fiber_pool_stack stack
struct fiber_pool_allocation * allocations
struct rb_execution_context_struct::@13 machine
#define ruby_longjmp(env, val)
int st_insert(st_table *tab, st_data_t key, st_data_t value)
rb_execution_context_t * ec
void rb_fiber_start(void)
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
VALUE rb_fiber_alive_p(VALUE fiber_value)
void rb_undef_method(VALUE klass, const char *name)
#define VM_BLOCK_HANDLER_NONE
void rb_raise(VALUE exc, const char *fmt,...)
VALUE rb_obj_is_proc(VALUE)
const VALUE * rb_vm_proc_local_ep(VALUE proc)
RUBY_EXTERN char * strerror(int)
VALUE rb_fiber_resume_kw(VALUE fiber_value, int argc, const VALUE *argv, int kw_splat)
void rb_ec_clear_vm_stack(rb_execution_context_t *ec)
#define VM_UNREACHABLE(func)
#define THREAD_MUST_BE_RUNNING(th)
struct rb_thread_struct * main_thread
struct fiber_pool_stack stack
enum rb_thread_status status
VALUE rb_ary_tmp_new(long capa)
struct fiber_pool_allocation * allocation
struct rb_thread_struct * thread_ptr
VALUE rb_fiber_transfer(VALUE fiber_value, int argc, const VALUE *argv)
#define VAR_FROM_MEMORY(var)
void rb_fiber_reset_root_local_storage(rb_thread_t *th)
struct fiber_pool_vacancy * next
#define COMPILER_WARNING_POP
void rb_threadptr_root_fiber_terminate(rb_thread_t *th)
#define TypedData_Wrap_Struct(klass, data_type, sval)
struct rb_trace_arg_struct * trace_arg
size_t fiber_vm_stack_size
#define RUBY_FREE_UNLESS_NULL(ptr)
#define RUBY_FREE_LEAVE(msg)
#define ALLOCA_N(type, n)
#define RUBY_FREE_ENTER(msg)
void rb_str_set_len(VALUE, long)
void rb_gc_mark_movable(VALUE ptr)
VALUE rb_obj_is_fiber(VALUE obj)
rb_ensure_entry_t * ensure_array
#define MEMZERO(p, type, n)
struct rb_context_struct::@0 machine
void rb_fiber_update_self(rb_fiber_t *fiber)
#define GetProcPtr(obj, ptr)
#define COMPILER_WARNING_PUSH
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type)
void rb_ec_initialize_vm_stack(rb_execution_context_t *ec, VALUE *stack, size_t size)
RUBY_SYMBOL_EXPORT_BEGIN void ruby_Init_Continuation_body(void)
VALUE rb_vm_make_jump_tag_but_local_jump(int state, VALUE val)
struct coroutine_context * coroutine_transfer(struct coroutine_context *current, struct coroutine_context *target)
RUBY_EXTERN VALUE rb_cObject
unsigned char buf[MIME_BUF_SIZE]
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
#define TypedData_Get_Struct(obj, type, data_type, sval)
void rb_threadptr_root_fiber_setup(rb_thread_t *th)
void rb_bug(const char *fmt,...)
#define RUBY_MARK_ENTER(msg)
rb_block_call_func * rb_block_call_func_t
#define RUBY_SYMBOL_EXPORT_BEGIN
VALUE rb_fiber_current(void)
VALUE rb_fiber_resume(VALUE fiber_value, int argc, const VALUE *argv)
void rb_fiber_close(rb_fiber_t *fiber)
char str[HTML_ESCAPE_MAX_LEN+1]
#define RARRAY_CONST_PTR(s)
void ruby_register_rollback_func_for_ensure(e_proc *ensure_func, e_proc *rollback_func)
#define RUBY_TYPED_FREE_IMMEDIATELY
size_t fiber_machine_stack_size
#define MEMCPY(p1, p2, type, n)
void rb_threadptr_root_fiber_release(rb_thread_t *th)
void rb_obj_info_dump(VALUE obj)
#define STACK_DIR_UPPER(a, b)
void rb_vm_stack_to_heap(rb_execution_context_t *ec)
void rb_fiber_init_mjit_cont(struct rb_fiber_struct *fiber)
VALUE rb_fiber_yield(int argc, const VALUE *argv)
#define REALLOC_N(var, type, n)
#define RUBY_EVENT_FIBER_SWITCH
VALUE rb_adjust_argv_kw_splat(int *, const VALUE **, int *)
struct rb_fiber_struct * prev
#define SET_MACHINE_STACK_END(p)
#define FIBER_CREATED_P(fiber)
#define COMPILER_WARNING_IGNORED(flag)
#define FIBER_RESUMED_P(fiber)
void rb_gc_mark(VALUE ptr)
size_t st_memsize(const st_table *tab)
#define STACK_GROW_DIR_DETECTION
struct rb_iseq_constant_body * body
VALUE rb_fiber_yield_kw(int argc, const VALUE *argv, int kw_splat)
BITFIELD(enum fiber_status, status, 2)
#define RUBY_VM_SET_INTERRUPT(ec)
struct rb_vm_struct::@10 default_params
VALUE rb_fiber_new(rb_block_call_func_t func, VALUE obj)
void rb_execution_context_mark(const rb_execution_context_t *ec)
#define FIBER_POOL_INITIAL_SIZE
VALUE local_storage_recursive_hash_for_trace
int st_lookup(st_table *tab, st_data_t key, st_data_t *value)
#define RUBY_VM_SET_TRAP_INTERRUPT(ec)
void rb_undef_alloc_func(VALUE)
VALUE local_storage_recursive_hash
void st_free_table(st_table *tab)
rb_execution_context_t saved_ec
struct rb_ensure_list * next
#define RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp)
VALUE rb_any_to_s(VALUE)
Default implementation of #to_s.
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
void rb_execution_context_update(const rb_execution_context_t *ec)
void rb_threadptr_pending_interrupt_enque(rb_thread_t *th, VALUE v)
VALUE rb_block_proc(void)