Ruby 2.1.5p273(2014-11-13revision48405)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

cont.c
Go to the documentation of this file.
1 /**********************************************************************
2
3 cont.c -
4
5 $Author: nagachika $
6 created at: Thu May 23 09:03:43 2007
7
8 Copyright (C) 2007 Koichi Sasada
9
10 **********************************************************************/
11
12 #include "ruby/ruby.h"
13 #include "internal.h"
14 #include "vm_core.h"
15 #include "gc.h"
16 #include "eval_intern.h"
17
18 /* FIBER_USE_NATIVE enables Fiber performance improvement using system
19 * dependent method such as make/setcontext on POSIX system or
20 * CreateFiber() API on Windows.
21 * This hack make Fiber context switch faster (x2 or more).
22 * However, it decrease maximum number of Fiber. For example, on the
23 * 32bit POSIX OS, ten or twenty thousands Fiber can be created.
24 *
25 * Details is reported in the paper "A Fast Fiber Implementation for Ruby 1.9"
26 * in Proc. of 51th Programming Symposium, pp.21--28 (2010) (in Japanese).
27 */
28
29 #if !defined(FIBER_USE_NATIVE)
30 # if defined(HAVE_GETCONTEXT) && defined(HAVE_SETCONTEXT)
31 # if 0
32 # elif defined(__NetBSD__)
33 /* On our experience, NetBSD doesn't support using setcontext() and pthread
34 * simultaneously. This is because pthread_self(), TLS and other information
35 * are represented by stack pointer (higher bits of stack pointer).
36 * TODO: check such constraint on configure.
37 */
38 # define FIBER_USE_NATIVE 0
39 # elif defined(__sun)
40 /* On Solaris because resuming any Fiber caused SEGV, for some reason.
41 */
42 # define FIBER_USE_NATIVE 0
43 # elif defined(__ia64)
44 /* At least, Linux/ia64's getcontext(3) doesn't save register window.
45 */
46 # define FIBER_USE_NATIVE 0
47 # elif defined(__GNU__)
48 /* GNU/Hurd doesn't fully support getcontext, setcontext, makecontext
49 * and swapcontext functions. Disabling their usage till support is
50 * implemented. More info at
51 * http://darnassus.sceen.net/~hurd-web/open_issues/glibc/#getcontext
52 */
53 # define FIBER_USE_NATIVE 0
54 # else
55 # define FIBER_USE_NATIVE 1
56 # endif
57 # elif defined(_WIN32)
58 # if _WIN32_WINNT >= 0x0400
59 /* only when _WIN32_WINNT >= 0x0400 on Windows because Fiber APIs are
60 * supported only such building (and running) environments.
61 * [ruby-dev:41192]
62 */
63 # define FIBER_USE_NATIVE 1
64 # endif
65 # endif
66 #endif
67 #if !defined(FIBER_USE_NATIVE)
68 #define FIBER_USE_NATIVE 0
69 #endif
70
71 #if FIBER_USE_NATIVE
72 #ifndef _WIN32
73 #include <unistd.h>
74 #include <sys/mman.h>
75 #include <ucontext.h>
76 #endif
77 #define RB_PAGE_SIZE (pagesize)
78 #define RB_PAGE_MASK (~(RB_PAGE_SIZE - 1))
79 static long pagesize;
80 #endif /*FIBER_USE_NATIVE*/
81
82 #define CAPTURE_JUST_VALID_VM_STACK 1
83
84 enum context_type {
85 CONTINUATION_CONTEXT = 0,
86 FIBER_CONTEXT = 1,
87 ROOT_FIBER_CONTEXT = 2
88 };
89
90 typedef struct rb_context_struct {
91 enum context_type type;
92 VALUE self;
93 int argc;
94 VALUE value;
95 VALUE *vm_stack;
96 #ifdef CAPTURE_JUST_VALID_VM_STACK
97 size_t vm_stack_slen; /* length of stack (head of th->stack) */
98 size_t vm_stack_clen; /* length of control frames (tail of th->stack) */
99 #endif
100 struct {
101 VALUE *stack;
102 VALUE *stack_src;
103 size_t stack_size;
104 #ifdef __ia64
105 VALUE *register_stack;
106 VALUE *register_stack_src;
107 int register_stack_size;
108 #endif
109 } machine;
110 rb_thread_t saved_thread;
111 rb_jmpbuf_t jmpbuf;
112 rb_ensure_entry_t *ensure_array;
113 rb_ensure_list_t *ensure_list;
114 } rb_context_t;
115
116 enum fiber_status {
117 CREATED,
118 RUNNING,
119 TERMINATED
120 };
121
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 {
126 void *ptr;
127 size_t size;
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;
131 #endif
132
133 typedef struct rb_fiber_struct {
134 rb_context_t cont;
135 VALUE prev;
136 enum fiber_status status;
137 struct rb_fiber_struct *prev_fiber;
138 struct rb_fiber_struct *next_fiber;
139 /* If a fiber invokes "transfer",
140 * then this fiber can't "resume" any more after that.
141 * You shouldn't mix "transfer" and "resume".
142 */
143 int transfered;
144
145 #if FIBER_USE_NATIVE
146 #ifdef _WIN32
147 void *fib_handle;
148 #else
149 ucontext_t context;
150 #endif
151 #endif
152 } rb_fiber_t;
153
154 static const rb_data_type_t cont_data_type, fiber_data_type;
155 static VALUE rb_cContinuation;
156 static VALUE rb_cFiber;
157 static VALUE rb_eFiberError;
158
159 #define GetContPtr(obj, ptr) \
160 TypedData_Get_Struct((obj), rb_context_t, &cont_data_type, (ptr))
161
162 #define GetFiberPtr(obj, ptr) do {\
163 TypedData_Get_Struct((obj), rb_fiber_t, &fiber_data_type, (ptr)); \
164 if (!(ptr)) rb_raise(rb_eFiberError, "uninitialized fiber"); \
165 } while (0)
166
167 NOINLINE(static VALUE cont_capture(volatile int *stat));
168
169 #define THREAD_MUST_BE_RUNNING(th) do { \
170 if (!(th)->tag) rb_raise(rb_eThreadError, "not running thread"); \
171 } while (0)
172
173 static void
174 cont_mark(void *ptr)
175 {
176 RUBY_MARK_ENTER("cont");
177 if (ptr) {
178 rb_context_t *cont = ptr;
179 rb_gc_mark(cont->value);
180 rb_thread_mark(&cont->saved_thread);
181 rb_gc_mark(cont->saved_thread.self);
182
183 if (cont->vm_stack) {
184 #ifdef CAPTURE_JUST_VALID_VM_STACK
185 rb_gc_mark_locations(cont->vm_stack,
186 cont->vm_stack + cont->vm_stack_slen + cont->vm_stack_clen);
187 #else
188 rb_gc_mark_localtion(cont->vm_stack,
189 cont->vm_stack, cont->saved_thread.stack_size);
190 #endif
191 }
192
193 if (cont->machine.stack) {
194 if (cont->type == CONTINUATION_CONTEXT) {
195 /* cont */
196 rb_gc_mark_locations(cont->machine.stack,
197 cont->machine.stack + cont->machine.stack_size);
198 }
199 else {
200 /* fiber */
201 rb_thread_t *th;
202 rb_fiber_t *fib = (rb_fiber_t*)cont;
203 GetThreadPtr(cont->saved_thread.self, th);
204 if ((th->fiber != cont->self) && fib->status == RUNNING) {
205 rb_gc_mark_locations(cont->machine.stack,
206 cont->machine.stack + cont->machine.stack_size);
207 }
208 }
209 }
210 #ifdef __ia64
211 if (cont->machine.register_stack) {
212 rb_gc_mark_locations(cont->machine.register_stack,
213 cont->machine.register_stack + cont->machine.register_stack_size);
214 }
215 #endif
216 }
217 RUBY_MARK_LEAVE("cont");
218 }
219
220 static void
221 cont_free(void *ptr)
222 {
223 RUBY_FREE_ENTER("cont");
224 if (ptr) {
225 rb_context_t *cont = ptr;
226 RUBY_FREE_UNLESS_NULL(cont->saved_thread.stack); fflush(stdout);
227 #if FIBER_USE_NATIVE
228 if (cont->type == CONTINUATION_CONTEXT) {
229 /* cont */
230 ruby_xfree(cont->ensure_array);
231 RUBY_FREE_UNLESS_NULL(cont->machine.stack);
232 }
233 else {
234 /* fiber */
235 #ifdef _WIN32
236 if (GET_THREAD()->fiber != cont->self && cont->type != ROOT_FIBER_CONTEXT) {
237 /* don't delete root fiber handle */
238 rb_fiber_t *fib = (rb_fiber_t*)cont;
239 if (fib->fib_handle) {
240 DeleteFiber(fib->fib_handle);
241 }
242 }
243 #else /* not WIN32 */
244 if (GET_THREAD()->fiber != cont->self) {
245 rb_fiber_t *fib = (rb_fiber_t*)cont;
246 if (fib->context.uc_stack.ss_sp) {
247 if (cont->type == ROOT_FIBER_CONTEXT) {
248 rb_bug("Illegal root fiber parameter");
249 }
250 munmap((void*)fib->context.uc_stack.ss_sp, fib->context.uc_stack.ss_size);
251 }
252 }
253 else {
254 /* It may reached here when finalize */
255 /* TODO examine whether it is a bug */
256 /* rb_bug("cont_free: release self"); */
257 }
258 #endif
259 }
260 #else /* not FIBER_USE_NATIVE */
261 ruby_xfree(cont->ensure_array);
262 RUBY_FREE_UNLESS_NULL(cont->machine.stack);
263 #endif
264 #ifdef __ia64
265 RUBY_FREE_UNLESS_NULL(cont->machine.register_stack);
266 #endif
267 RUBY_FREE_UNLESS_NULL(cont->vm_stack);
268
269 /* free rb_cont_t or rb_fiber_t */
270 ruby_xfree(ptr);
271 }
272 RUBY_FREE_LEAVE("cont");
273 }
274
275 static size_t
276 cont_memsize(const void *ptr)
277 {
278 const rb_context_t *cont = ptr;
279 size_t size = 0;
280 if (cont) {
281 size = sizeof(*cont);
282 if (cont->vm_stack) {
283 #ifdef CAPTURE_JUST_VALID_VM_STACK
284 size_t n = (cont->vm_stack_slen + cont->vm_stack_clen);
285 #else
286 size_t n = cont->saved_thread.stack_size;
287 #endif
288 size += n * sizeof(*cont->vm_stack);
289 }
290
291 if (cont->machine.stack) {
292 size += cont->machine.stack_size * sizeof(*cont->machine.stack);
293 }
294 #ifdef __ia64
295 if (cont->machine.register_stack) {
296 size += cont->machine.register_stack_size * sizeof(*cont->machine.register_stack);
297 }
298 #endif
299 }
300 return size;
301 }
302
303 static void
304 fiber_mark(void *ptr)
305 {
306 RUBY_MARK_ENTER("cont");
307 if (ptr) {
308 rb_fiber_t *fib = ptr;
309 rb_gc_mark(fib->prev);
310 cont_mark(&fib->cont);
311 }
312 RUBY_MARK_LEAVE("cont");
313 }
314
315 static void
316 fiber_link_join(rb_fiber_t *fib)
317 {
318 VALUE current_fibval = rb_fiber_current();
319 rb_fiber_t *current_fib;
320 GetFiberPtr(current_fibval, current_fib);
321
322 /* join fiber link */
323 fib->next_fiber = current_fib->next_fiber;
324 fib->prev_fiber = current_fib;
325 current_fib->next_fiber->prev_fiber = fib;
326 current_fib->next_fiber = fib;
327 }
328
329 static void
330 fiber_link_remove(rb_fiber_t *fib)
331 {
332 fib->prev_fiber->next_fiber = fib->next_fiber;
333 fib->next_fiber->prev_fiber = fib->prev_fiber;
334 }
335
336 static void
337 fiber_free(void *ptr)
338 {
339 RUBY_FREE_ENTER("fiber");
340 if (ptr) {
341 rb_fiber_t *fib = ptr;
342 if (fib->cont.type != ROOT_FIBER_CONTEXT &&
343 fib->cont.saved_thread.local_storage) {
344 st_free_table(fib->cont.saved_thread.local_storage);
345 }
346 fiber_link_remove(fib);
347
348 cont_free(&fib->cont);
349 }
350 RUBY_FREE_LEAVE("fiber");
351 }
352
353 static size_t
354 fiber_memsize(const void *ptr)
355 {
356 const rb_fiber_t *fib = ptr;
357 size_t size = 0;
358 if (ptr) {
359 size = sizeof(*fib);
360 if (fib->cont.type != ROOT_FIBER_CONTEXT &&
361 fib->cont.saved_thread.local_storage != NULL) {
362 size += st_memsize(fib->cont.saved_thread.local_storage);
363 }
364 size += cont_memsize(&fib->cont);
365 }
366 return size;
367 }
368
369 VALUE
370 rb_obj_is_fiber(VALUE obj)
371 {
372 if (rb_typeddata_is_kind_of(obj, &fiber_data_type)) {
373 return Qtrue;
374 }
375 else {
376 return Qfalse;
377 }
378 }
379
380 static void
381 cont_save_machine_stack(rb_thread_t *th, rb_context_t *cont)
382 {
383 size_t size;
384
385 SET_MACHINE_STACK_END(&th->machine.stack_end);
386 #ifdef __ia64
387 th->machine.register_stack_end = rb_ia64_bsp();
388 #endif
389
390 if (th->machine.stack_start > th->machine.stack_end) {
391 size = cont->machine.stack_size = th->machine.stack_start - th->machine.stack_end;
392 cont->machine.stack_src = th->machine.stack_end;
393 }
394 else {
395 size = cont->machine.stack_size = th->machine.stack_end - th->machine.stack_start;
396 cont->machine.stack_src = th->machine.stack_start;
397 }
398
399 if (cont->machine.stack) {
400 REALLOC_N(cont->machine.stack, VALUE, size);
401 }
402 else {
403 cont->machine.stack = ALLOC_N(VALUE, size);
404 }
405
406 FLUSH_REGISTER_WINDOWS;
407 MEMCPY(cont->machine.stack, cont->machine.stack_src, VALUE, size);
408
409 #ifdef __ia64
410 rb_ia64_flushrs();
411 size = cont->machine.register_stack_size = th->machine.register_stack_end - th->machine.register_stack_start;
412 cont->machine.register_stack_src = th->machine.register_stack_start;
413 if (cont->machine.register_stack) {
414 REALLOC_N(cont->machine.register_stack, VALUE, size);
415 }
416 else {
417 cont->machine.register_stack = ALLOC_N(VALUE, size);
418 }
419
420 MEMCPY(cont->machine.register_stack, cont->machine.register_stack_src, VALUE, size);
421 #endif
422 }
423
424 static const rb_data_type_t cont_data_type = {
425 "continuation",
426 {cont_mark, cont_free, cont_memsize,},
427 NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
428 };
429
430 static void
431 cont_save_thread(rb_context_t *cont, rb_thread_t *th)
432 {
433 /* save thread context */
434 cont->saved_thread = *th;
435 /* saved_thread->machine.stack_(start|end) should be NULL */
436 /* because it may happen GC afterward */
437 cont->saved_thread.machine.stack_start = 0;
438 cont->saved_thread.machine.stack_end = 0;
439 #ifdef __ia64
440 cont->saved_thread.machine.register_stack_start = 0;
441 cont->saved_thread.machine.register_stack_end = 0;
442 #endif
443 }
444
445 static void
446 cont_init(rb_context_t *cont, rb_thread_t *th)
447 {
448 /* save thread context */
449 cont_save_thread(cont, th);
450 cont->saved_thread.local_storage = 0;
451 }
452
453 static rb_context_t *
454 cont_new(VALUE klass)
455 {
456 rb_context_t *cont;
457 volatile VALUE contval;
458 rb_thread_t *th = GET_THREAD();
459
460 THREAD_MUST_BE_RUNNING(th);
461 contval = TypedData_Make_Struct(klass, rb_context_t, &cont_data_type, cont);
462 cont->self = contval;
463 cont_init(cont, th);
464 return cont;
465 }
466
467 static VALUE
468 cont_capture(volatile int *stat)
469 {
470 rb_context_t *cont;
471 rb_thread_t *th = GET_THREAD(), *sth;
472 volatile VALUE contval;
473
474 THREAD_MUST_BE_RUNNING(th);
475 rb_vm_stack_to_heap(th);
476 cont = cont_new(rb_cContinuation);
477 contval = cont->self;
478 sth = &cont->saved_thread;
479
480 #ifdef CAPTURE_JUST_VALID_VM_STACK
481 cont->vm_stack_slen = th->cfp->sp + th->mark_stack_len - th->stack;
482 cont->vm_stack_clen = th->stack + th->stack_size - (VALUE*)th->cfp;
483 cont->vm_stack = ALLOC_N(VALUE, cont->vm_stack_slen + cont->vm_stack_clen);
484 MEMCPY(cont->vm_stack, th->stack, VALUE, cont->vm_stack_slen);
485 MEMCPY(cont->vm_stack + cont->vm_stack_slen, (VALUE*)th->cfp, VALUE, cont->vm_stack_clen);
486 #else
487 cont->vm_stack = ALLOC_N(VALUE, th->stack_size);
488 MEMCPY(cont->vm_stack, th->stack, VALUE, th->stack_size);
489 #endif
490 sth->stack = 0;
491
492 cont_save_machine_stack(th, cont);
493
494 /* backup ensure_list to array for search in another context */
495 {
496 rb_ensure_list_t *p;
497 int size = 0;
498 rb_ensure_entry_t *entry;
499 for (p=th->ensure_list; p; p=p->next)
500 size++;
501 entry = cont->ensure_array = ALLOC_N(rb_ensure_entry_t,size+1);
502 for (p=th->ensure_list; p; p=p->next) {
503 if (!p->entry.marker)
504 p->entry.marker = rb_ary_tmp_new(0); /* dummy object */
505 *entry++ = p->entry;
506 }
507 entry->marker = 0;
508 }
509
510 if (ruby_setjmp(cont->jmpbuf)) {
511 volatile VALUE value;
512
513 value = cont->value;
514 if (cont->argc == -1) rb_exc_raise(value);
515 cont->value = Qnil;
516 *stat = 1;
517 return value;
518 }
519 else {
520 *stat = 0;
521 return contval;
522 }
523 }
524
525 static void
526 cont_restore_thread(rb_context_t *cont)
527 {
528 rb_thread_t *th = GET_THREAD(), *sth = &cont->saved_thread;
529
530 /* restore thread context */
531 if (cont->type == CONTINUATION_CONTEXT) {
532 /* continuation */
533 VALUE fib;
534
535 th->fiber = sth->fiber;
536 fib = th->fiber ? th->fiber : th->root_fiber;
537
538 if (fib) {
539 rb_fiber_t *fcont;
540 GetFiberPtr(fib, fcont);
541 th->stack_size = fcont->cont.saved_thread.stack_size;
542 th->stack = fcont->cont.saved_thread.stack;
543 }
544 #ifdef CAPTURE_JUST_VALID_VM_STACK
545 MEMCPY(th->stack, cont->vm_stack, VALUE, cont->vm_stack_slen);
546 MEMCPY(th->stack + sth->stack_size - cont->vm_stack_clen,
547 cont->vm_stack + cont->vm_stack_slen, VALUE, cont->vm_stack_clen);
548 #else
549 MEMCPY(th->stack, cont->vm_stack, VALUE, sth->stack_size);
550 #endif
551 }
552 else {
553 /* fiber */
554 th->stack = sth->stack;
555 th->stack_size = sth->stack_size;
556 th->local_storage = sth->local_storage;
557 th->fiber = cont->self;
558 }
559
560 th->cfp = sth->cfp;
561 th->safe_level = sth->safe_level;
562 th->raised_flag = sth->raised_flag;
563 th->state = sth->state;
564 th->status = sth->status;
565 th->tag = sth->tag;
566 th->protect_tag = sth->protect_tag;
567 th->errinfo = sth->errinfo;
568 th->first_proc = sth->first_proc;
569 th->root_lep = sth->root_lep;
570 th->root_svar = sth->root_svar;
571 th->ensure_list = sth->ensure_list;
572
573 }
574
575 #if FIBER_USE_NATIVE
576 #ifdef _WIN32
577 static void
578 fiber_set_stack_location(void)
579 {
580 rb_thread_t *th = GET_THREAD();
581 VALUE *ptr;
582
583 SET_MACHINE_STACK_END(&ptr);
584 th->machine.stack_start = (void*)(((VALUE)ptr & RB_PAGE_MASK) + STACK_UPPER((void *)&ptr, 0, RB_PAGE_SIZE));
585 }
586
587 static VOID CALLBACK
588 fiber_entry(void *arg)
589 {
590 fiber_set_stack_location();
591 rb_fiber_start();
592 }
593 #else /* _WIN32 */
594
595 /*
596 * FreeBSD require a first (i.e. addr) argument of mmap(2) is not NULL
597 * if MAP_STACK is passed.
598 * http://www.FreeBSD.org/cgi/query-pr.cgi?pr=158755
599 */
600 #if defined(MAP_STACK) && !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__)
601 #define FIBER_STACK_FLAGS (MAP_PRIVATE | MAP_ANON | MAP_STACK)
602 #else
603 #define FIBER_STACK_FLAGS (MAP_PRIVATE | MAP_ANON)
604 #endif
605
606 static char*
607 fiber_machine_stack_alloc(size_t size)
608 {
609 char *ptr;
610
611 if (machine_stack_cache_index > 0) {
612 if (machine_stack_cache[machine_stack_cache_index - 1].size == (size / sizeof(VALUE))) {
613 ptr = machine_stack_cache[machine_stack_cache_index - 1].ptr;
614 machine_stack_cache_index--;
615 machine_stack_cache[machine_stack_cache_index].ptr = NULL;
616 machine_stack_cache[machine_stack_cache_index].size = 0;
617 }
618 else{
619 /* TODO handle multiple machine stack size */
620 rb_bug("machine_stack_cache size is not canonicalized");
621 }
622 }
623 else {
624 void *page;
625 STACK_GROW_DIR_DETECTION;
626
627 errno = 0;
628 ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, FIBER_STACK_FLAGS, -1, 0);
629 if (ptr == MAP_FAILED) {
630 rb_raise(rb_eFiberError, "can't alloc machine stack to fiber: %s", strerror(errno));
631 }
632
633 /* guard page setup */
634 page = ptr + STACK_DIR_UPPER(size - RB_PAGE_SIZE, 0);
635 if (mprotect(page, RB_PAGE_SIZE, PROT_NONE) < 0) {
636 rb_raise(rb_eFiberError, "mprotect failed");
637 }
638 }
639
640 return ptr;
641 }
642 #endif
643
644 static void
645 fiber_initialize_machine_stack_context(rb_fiber_t *fib, size_t size)
646 {
647 rb_thread_t *sth = &fib->cont.saved_thread;
648
649 #ifdef _WIN32
650 fib->fib_handle = CreateFiberEx(size - 1, size, 0, fiber_entry, NULL);
651 if (!fib->fib_handle) {
652 /* try to release unnecessary fibers & retry to create */
653 rb_gc();
654 fib->fib_handle = CreateFiberEx(size - 1, size, 0, fiber_entry, NULL);
655 if (!fib->fib_handle) {
656 rb_raise(rb_eFiberError, "can't create fiber");
657 }
658 }
659 sth->machine.stack_maxsize = size;
660 #else /* not WIN32 */
661 ucontext_t *context = &fib->context;
662 char *ptr;
663 STACK_GROW_DIR_DETECTION;
664
665 getcontext(context);
666 ptr = fiber_machine_stack_alloc(size);
667 context->uc_link = NULL;
668 context->uc_stack.ss_sp = ptr;
669 context->uc_stack.ss_size = size;
670 makecontext(context, rb_fiber_start, 0);
671 sth->machine.stack_start = (VALUE*)(ptr + STACK_DIR_UPPER(0, size));
672 sth->machine.stack_maxsize = size - RB_PAGE_SIZE;
673 #endif
674 #ifdef __ia64
675 sth->machine.register_stack_maxsize = sth->machine.stack_maxsize;
676 #endif
677 }
678
679 NOINLINE(static void fiber_setcontext(rb_fiber_t *newfib, rb_fiber_t *oldfib));
680
681 static void
682 fiber_setcontext(rb_fiber_t *newfib, rb_fiber_t *oldfib)
683 {
684 rb_thread_t *th = GET_THREAD(), *sth = &newfib->cont.saved_thread;
685
686 if (newfib->status != RUNNING) {
687 fiber_initialize_machine_stack_context(newfib, th->vm->default_params.fiber_machine_stack_size);
688 }
689
690 /* restore thread context */
691 cont_restore_thread(&newfib->cont);
692 th->machine.stack_maxsize = sth->machine.stack_maxsize;
693 if (sth->machine.stack_end && (newfib != oldfib)) {
694 rb_bug("fiber_setcontext: sth->machine.stack_end has non zero value");
695 }
696
697 /* save oldfib's machine stack */
698 if (oldfib->status != TERMINATED) {
699 STACK_GROW_DIR_DETECTION;
700 SET_MACHINE_STACK_END(&th->machine.stack_end);
701 if (STACK_DIR_UPPER(0, 1)) {
702 oldfib->cont.machine.stack_size = th->machine.stack_start - th->machine.stack_end;
703 oldfib->cont.machine.stack = th->machine.stack_end;
704 }
705 else {
706 oldfib->cont.machine.stack_size = th->machine.stack_end - th->machine.stack_start;
707 oldfib->cont.machine.stack = th->machine.stack_start;
708 }
709 }
710 /* exchange machine_stack_start between oldfib and newfib */
711 oldfib->cont.saved_thread.machine.stack_start = th->machine.stack_start;
712 th->machine.stack_start = sth->machine.stack_start;
713 /* oldfib->machine.stack_end should be NULL */
714 oldfib->cont.saved_thread.machine.stack_end = 0;
715 #ifndef _WIN32
716 if (!newfib->context.uc_stack.ss_sp && th->root_fiber != newfib->cont.self) {
717 rb_bug("non_root_fiber->context.uc_stac.ss_sp should not be NULL");
718 }
719 #endif
720
721 /* swap machine context */
722 #ifdef _WIN32
723 SwitchToFiber(newfib->fib_handle);
724 #else
725 swapcontext(&oldfib->context, &newfib->context);
726 #endif
727 }
728 #endif
729
730 NOINLINE(NORETURN(static void cont_restore_1(rb_context_t *)));
731
732 static void
733 cont_restore_1(rb_context_t *cont)
734 {
735 cont_restore_thread(cont);
736
737 /* restore machine stack */
738 #ifdef _M_AMD64
739 {
740 /* workaround for x64 SEH */
741 jmp_buf buf;
742 setjmp(buf);
743 ((_JUMP_BUFFER*)(&cont->jmpbuf))->Frame =
744 ((_JUMP_BUFFER*)(&buf))->Frame;
745 }
746 #endif
747 if (cont->machine.stack_src) {
748 FLUSH_REGISTER_WINDOWS;
749 MEMCPY(cont->machine.stack_src, cont->machine.stack,
750 VALUE, cont->machine.stack_size);
751 }
752
753 #ifdef __ia64
754 if (cont->machine.register_stack_src) {
755 MEMCPY(cont->machine.register_stack_src, cont->machine.register_stack,
756 VALUE, cont->machine.register_stack_size);
757 }
758 #endif
759
760 ruby_longjmp(cont->jmpbuf, 1);
761 }
762
763 NORETURN(NOINLINE(static void cont_restore_0(rb_context_t *, VALUE *)));
764
765 #ifdef __ia64
766 #define C(a) rse_##a##0, rse_##a##1, rse_##a##2, rse_##a##3, rse_##a##4
767 #define E(a) rse_##a##0= rse_##a##1= rse_##a##2= rse_##a##3= rse_##a##4
768 static volatile int C(a), C(b), C(c), C(d), C(e);
769 static volatile int C(f), C(g), C(h), C(i), C(j);
770 static volatile int C(k), C(l), C(m), C(n), C(o);
771 static volatile int C(p), C(q), C(r), C(s), C(t);
772 #if 0
773 {/* the above lines make cc-mode.el confused so much */}
774 #endif
775 int rb_dummy_false = 0;
776 NORETURN(NOINLINE(static void register_stack_extend(rb_context_t *, VALUE *, VALUE *)));
777 static void
778 register_stack_extend(rb_context_t *cont, VALUE *vp, VALUE *curr_bsp)
779 {
780 if (rb_dummy_false) {
781 /* use registers as much as possible */
782 E(a) = E(b) = E(c) = E(d) = E(e) =
783 E(f) = E(g) = E(h) = E(i) = E(j) =
784 E(k) = E(l) = E(m) = E(n) = E(o) =
785 E(p) = E(q) = E(r) = E(s) = E(t) = 0;
786 E(a) = E(b) = E(c) = E(d) = E(e) =
787 E(f) = E(g) = E(h) = E(i) = E(j) =
788 E(k) = E(l) = E(m) = E(n) = E(o) =
789 E(p) = E(q) = E(r) = E(s) = E(t) = 0;
790 }
791 if (curr_bsp < cont->machine.register_stack_src+cont->machine.register_stack_size) {
792 register_stack_extend(cont, vp, (VALUE*)rb_ia64_bsp());
793 }
794 cont_restore_0(cont, vp);
795 }
796 #undef C
797 #undef E
798 #endif
799
800 static void
801 cont_restore_0(rb_context_t *cont, VALUE *addr_in_prev_frame)
802 {
803 if (cont->machine.stack_src) {
804 #ifdef HAVE_ALLOCA
805 #define STACK_PAD_SIZE 1
806 #else
807 #define STACK_PAD_SIZE 1024
808 #endif
809 VALUE space[STACK_PAD_SIZE];
810
811 #if !STACK_GROW_DIRECTION
812 if (addr_in_prev_frame > &space[0]) {
813 /* Stack grows downward */
814 #endif
815 #if STACK_GROW_DIRECTION <= 0
816 volatile VALUE *const end = cont->machine.stack_src;
817 if (&space[0] > end) {
818 # ifdef HAVE_ALLOCA
819 volatile VALUE *sp = ALLOCA_N(VALUE, &space[0] - end);
820 space[0] = *sp;
821 # else
822 cont_restore_0(cont, &space[0]);
823 # endif
824 }
825 #endif
826 #if !STACK_GROW_DIRECTION
827 }
828 else {
829 /* Stack grows upward */
830 #endif
831 #if STACK_GROW_DIRECTION >= 0
832 volatile VALUE *const end = cont->machine.stack_src + cont->machine.stack_size;
833 if (&space[STACK_PAD_SIZE] < end) {
834 # ifdef HAVE_ALLOCA
835 volatile VALUE *sp = ALLOCA_N(VALUE, end - &space[STACK_PAD_SIZE]);
836 space[0] = *sp;
837 # else
838 cont_restore_0(cont, &space[STACK_PAD_SIZE-1]);
839 # endif
840 }
841 #endif
842 #if !STACK_GROW_DIRECTION
843 }
844 #endif
845 }
846 cont_restore_1(cont);
847 }
848 #ifdef __ia64
849 #define cont_restore_0(cont, vp) register_stack_extend((cont), (vp), (VALUE*)rb_ia64_bsp())
850 #endif
851
852 /*
853 * Document-class: Continuation
854 *
855 * Continuation objects are generated by Kernel#callcc,
856 * after having +require+d <i>continuation</i>. They hold
857 * a return address and execution context, allowing a nonlocal return
858 * to the end of the <code>callcc</code> block from anywhere within a
859 * program. Continuations are somewhat analogous to a structured
860 * version of C's <code>setjmp/longjmp</code> (although they contain
861 * more state, so you might consider them closer to threads).
862 *
863 * For instance:
864 *
865 * require "continuation"
866 * arr = [ "Freddie", "Herbie", "Ron", "Max", "Ringo" ]
867 * callcc{|cc| $cc = cc}
868 * puts(message = arr.shift)
869 * $cc.call unless message =~ /Max/
870 *
871 * <em>produces:</em>
872 *
873 * Freddie
874 * Herbie
875 * Ron
876 * Max
877 *
878 * This (somewhat contrived) example allows the inner loop to abandon
879 * processing early:
880 *
881 * require "continuation"
882 * callcc {|cont|
883 * for i in 0..4
884 * print "\n#{i}: "
885 * for j in i*5...(i+1)*5
886 * cont.call() if j == 17
887 * printf "%3d", j
888 * end
889 * end
890 * }
891 * puts
892 *
893 * <em>produces:</em>
894 *
895 * 0: 0 1 2 3 4
896 * 1: 5 6 7 8 9
897 * 2: 10 11 12 13 14
898 * 3: 15 16
899 */
900
901 /*
902 * call-seq:
903 * callcc {|cont| block } -> obj
904 *
905 * Generates a Continuation object, which it passes to
906 * the associated block. You need to <code>require
907 * 'continuation'</code> before using this method. Performing a
908 * <em>cont</em><code>.call</code> will cause the #callcc
909 * to return (as will falling through the end of the block). The
910 * value returned by the #callcc is the value of the
911 * block, or the value passed to <em>cont</em><code>.call</code>. See
912 * class Continuation for more details. Also see
913 * Kernel#throw for an alternative mechanism for
914 * unwinding a call stack.
915 */
916
917 static VALUE
918 rb_callcc(VALUE self)
919 {
920 volatile int called;
921 volatile VALUE val = cont_capture(&called);
922
923 if (called) {
924 return val;
925 }
926 else {
927 return rb_yield(val);
928 }
929 }
930
931 static VALUE
932 make_passing_arg(int argc, VALUE *argv)
933 {
934 switch (argc) {
935 case 0:
936 return Qnil;
937 case 1:
938 return argv[0];
939 default:
940 return rb_ary_new4(argc, argv);
941 }
942 }
943
944 /* CAUTION!! : Currently, error in rollback_func is not supported */
945 /* same as rb_protect if set rollback_func to NULL */
946 void
947 ruby_register_rollback_func_for_ensure(VALUE (*ensure_func)(ANYARGS), VALUE (*rollback_func)(ANYARGS))
948 {
949 st_table **table_p = &GET_VM()->ensure_rollback_table;
950 if (UNLIKELY(*table_p == NULL)) {
951 *table_p = st_init_numtable();
952 }
953 st_insert(*table_p, (st_data_t)ensure_func, (st_data_t)rollback_func);
954 }
955
956 static inline VALUE
957 lookup_rollback_func(VALUE (*ensure_func)(ANYARGS))
958 {
959 st_table *table = GET_VM()->ensure_rollback_table;
960 st_data_t val;
961 if (table && st_lookup(table, (st_data_t)ensure_func, &val))
962 return (VALUE) val;
963 return Qundef;
964 }
965
966
967 static inline void
968 rollback_ensure_stack(VALUE self,rb_ensure_list_t *current,rb_ensure_entry_t *target)
969 {
970 rb_ensure_list_t *p;
971 rb_ensure_entry_t *entry;
972 size_t i;
973 size_t cur_size;
974 size_t target_size;
975 size_t base_point;
976 VALUE (*func)(ANYARGS);
977
978 cur_size = 0;
979 for (p=current; p; p=p->next)
980 cur_size++;
981 target_size = 0;
982 for (entry=target; entry->marker; entry++)
983 target_size++;
984
985 /* search common stack point */
986 p = current;
987 base_point = cur_size;
988 while (base_point) {
989 if (target_size >= base_point &&
990 p->entry.marker == target[target_size - base_point].marker)
991 break;
992 base_point --;
993 p = p->next;
994 }
995
996 /* rollback function check */
997 for (i=0; i < target_size - base_point; i++) {
998 if (!lookup_rollback_func(target[i].e_proc)) {
999 rb_raise(rb_eRuntimeError, "continuation called from out of critical rb_ensure scope");
1000 }
1001 }
1002 /* pop ensure stack */
1003 while (cur_size > base_point) {
1004 /* escape from ensure block */
1005 (*current->entry.e_proc)(current->entry.data2);
1006 current = current->next;
1007 cur_size--;
1008 }
1009 /* push ensure stack */
1010 while (i--) {
1011 func = (VALUE (*)(ANYARGS)) lookup_rollback_func(target[i].e_proc);
1012 if ((VALUE)func != Qundef) {
1013 (*func)(target[i].data2);
1014 }
1015 }
1016 }
1017
1018 /*
1019 * call-seq:
1020 * cont.call(args, ...)
1021 * cont[args, ...]
1022 *
1023 * Invokes the continuation. The program continues from the end of the
1024 * <code>callcc</code> block. If no arguments are given, the original
1025 * <code>callcc</code> returns <code>nil</code>. If one argument is
1026 * given, <code>callcc</code> returns it. Otherwise, an array
1027 * containing <i>args</i> is returned.
1028 *
1029 * callcc {|cont| cont.call } #=> nil
1030 * callcc {|cont| cont.call 1 } #=> 1
1031 * callcc {|cont| cont.call 1, 2, 3 } #=> [1, 2, 3]
1032 */
1033
1034 static VALUE
1035 rb_cont_call(int argc, VALUE *argv, VALUE contval)
1036 {
1037 rb_context_t *cont;
1038 rb_thread_t *th = GET_THREAD();
1039 GetContPtr(contval, cont);
1040
1041 if (cont->saved_thread.self != th->self) {
1042 rb_raise(rb_eRuntimeError, "continuation called across threads");
1043 }
1044 if (cont->saved_thread.protect_tag != th->protect_tag) {
1045 rb_raise(rb_eRuntimeError, "continuation called across stack rewinding barrier");
1046 }
1047 if (cont->saved_thread.fiber) {
1048 rb_fiber_t *fcont;
1049 GetFiberPtr(cont->saved_thread.fiber, fcont);
1050
1051 if (th->fiber != cont->saved_thread.fiber) {
1052 rb_raise(rb_eRuntimeError, "continuation called across fiber");
1053 }
1054 }
1055 rollback_ensure_stack(contval, th->ensure_list, cont->ensure_array);
1056
1057 cont->argc = argc;
1058 cont->value = make_passing_arg(argc, argv);
1059
1060 /* restore `tracing' context. see [Feature #4347] */
1061 th->trace_arg = cont->saved_thread.trace_arg;
1062
1063 cont_restore_0(cont, &contval);
1064 return Qnil; /* unreachable */
1065 }
1066
1067 /*********/
1068 /* fiber */
1069 /*********/
1070
1071 /*
1072 * Document-class: Fiber
1073 *
1074 * Fibers are primitives for implementing light weight cooperative
1075 * concurrency in Ruby. Basically they are a means of creating code blocks
1076 * that can be paused and resumed, much like threads. The main difference
1077 * is that they are never preempted and that the scheduling must be done by
1078 * the programmer and not the VM.
1079 *
1080 * As opposed to other stackless light weight concurrency models, each fiber
1081 * comes with a small 4KB stack. This enables the fiber to be paused from deeply
1082 * nested function calls within the fiber block.
1083 *
1084 * When a fiber is created it will not run automatically. Rather it must be
1085 * be explicitly asked to run using the <code>Fiber#resume</code> method.
1086 * The code running inside the fiber can give up control by calling
1087 * <code>Fiber.yield</code> in which case it yields control back to caller
1088 * (the caller of the <code>Fiber#resume</code>).
1089 *
1090 * Upon yielding or termination the Fiber returns the value of the last
1091 * executed expression
1092 *
1093 * For instance:
1094 *
1095 * fiber = Fiber.new do
1096 * Fiber.yield 1
1097 * 2
1098 * end
1099 *
1100 * puts fiber.resume
1101 * puts fiber.resume
1102 * puts fiber.resume
1103 *
1104 * <em>produces</em>
1105 *
1106 * 1
1107 * 2
1108 * FiberError: dead fiber called
1109 *
1110 * The <code>Fiber#resume</code> method accepts an arbitrary number of
1111 * parameters, if it is the first call to <code>resume</code> then they
1112 * will be passed as block arguments. Otherwise they will be the return
1113 * value of the call to <code>Fiber.yield</code>
1114 *
1115 * Example:
1116 *
1117 * fiber = Fiber.new do |first|
1118 * second = Fiber.yield first + 2
1119 * end
1120 *
1121 * puts fiber.resume 10
1122 * puts fiber.resume 14
1123 * puts fiber.resume 18
1124 *
1125 * <em>produces</em>
1126 *
1127 * 12
1128 * 14
1129 * FiberError: dead fiber called
1130 *
1131 */
1132
1133 static const rb_data_type_t fiber_data_type = {
1134 "fiber",
1135 {fiber_mark, fiber_free, fiber_memsize,},
1136 NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
1137 };
1138
1139 static VALUE
1140 fiber_alloc(VALUE klass)
1141 {
1142 return TypedData_Wrap_Struct(klass, &fiber_data_type, 0);
1143 }
1144
1145 static rb_fiber_t*
1146 fiber_t_alloc(VALUE fibval)
1147 {
1148 rb_fiber_t *fib;
1149 rb_thread_t *th = GET_THREAD();
1150
1151 if (DATA_PTR(fibval) != 0) {
1152 rb_raise(rb_eRuntimeError, "cannot initialize twice");
1153 }
1154
1155 THREAD_MUST_BE_RUNNING(th);
1156 fib = ALLOC(rb_fiber_t);
1157 memset(fib, 0, sizeof(rb_fiber_t));
1158 fib->cont.self = fibval;
1159 fib->cont.type = FIBER_CONTEXT;
1160 cont_init(&fib->cont, th);
1161 fib->prev = Qnil;
1162 fib->status = CREATED;
1163
1164 DATA_PTR(fibval) = fib;
1165
1166 return fib;
1167 }
1168
1169 static VALUE
1170 fiber_init(VALUE fibval, VALUE proc)
1171 {
1172 rb_fiber_t *fib = fiber_t_alloc(fibval);
1173 rb_context_t *cont = &fib->cont;
1174 rb_thread_t *th = &cont->saved_thread;
1175
1176 /* initialize cont */
1177 cont->vm_stack = 0;
1178
1179 th->stack = 0;
1180 th->stack_size = 0;
1181
1182 fiber_link_join(fib);
1183
1184 th->stack_size = th->vm->default_params.fiber_vm_stack_size / sizeof(VALUE);
1185 th->stack = ALLOC_N(VALUE, th->stack_size);
1186
1187 th->cfp = (void *)(th->stack + th->stack_size);
1188 th->cfp--;
1189 th->cfp->pc = 0;
1190 th->cfp->sp = th->stack + 1;
1191 #if VM_DEBUG_BP_CHECK
1192 th->cfp->bp_check = 0;
1193 #endif
1194 th->cfp->ep = th->stack;
1195 *th->cfp->ep = VM_ENVVAL_BLOCK_PTR(0);
1196 th->cfp->self = Qnil;
1197 th->cfp->klass = Qnil;
1198 th->cfp->flag = 0;
1199 th->cfp->iseq = 0;
1200 th->cfp->proc = 0;
1201 th->cfp->block_iseq = 0;
1202 th->cfp->me = 0;
1203 th->tag = 0;
1204 th->local_storage = st_init_numtable();
1205
1206 th->first_proc = proc;
1207
1208 #if !FIBER_USE_NATIVE
1209 MEMCPY(&cont->jmpbuf, &th->root_jmpbuf, rb_jmpbuf_t, 1);
1210 #endif
1211
1212 return fibval;
1213 }
1214
1215 /* :nodoc: */
1216 static VALUE
1217 rb_fiber_init(VALUE fibval)
1218 {
1219 return fiber_init(fibval, rb_block_proc());
1220 }
1221
1222 VALUE
1223 rb_fiber_new(VALUE (*func)(ANYARGS), VALUE obj)
1224 {
1225 return fiber_init(fiber_alloc(rb_cFiber), rb_proc_new(func, obj));
1226 }
1227
1228 static VALUE
1229 return_fiber(void)
1230 {
1231 rb_fiber_t *fib;
1232 VALUE curr = rb_fiber_current();
1233 VALUE prev;
1234 GetFiberPtr(curr, fib);
1235
1236 prev = fib->prev;
1237 if (NIL_P(prev)) {
1238 const VALUE root_fiber = GET_THREAD()->root_fiber;
1239
1240 if (root_fiber == curr) {
1241 rb_raise(rb_eFiberError, "can't yield from root fiber");
1242 }
1243 return root_fiber;
1244 }
1245 else {
1246 fib->prev = Qnil;
1247 return prev;
1248 }
1249 }
1250
1251 VALUE rb_fiber_transfer(VALUE fib, int argc, VALUE *argv);
1252
1253 static void
1254 rb_fiber_terminate(rb_fiber_t *fib)
1255 {
1256 VALUE value = fib->cont.value;
1257 fib->status = TERMINATED;
1258 #if FIBER_USE_NATIVE && !defined(_WIN32)
1259 /* Ruby must not switch to other thread until storing terminated_machine_stack */
1260 terminated_machine_stack.ptr = fib->context.uc_stack.ss_sp;
1261 terminated_machine_stack.size = fib->context.uc_stack.ss_size / sizeof(VALUE);
1262 fib->context.uc_stack.ss_sp = NULL;
1263 fib->cont.machine.stack = NULL;
1264 fib->cont.machine.stack_size = 0;
1265 #endif
1266 rb_fiber_transfer(return_fiber(), 1, &value);
1267 }
1268
1269 void
1270 rb_fiber_start(void)
1271 {
1272 rb_thread_t *th = GET_THREAD();
1273 rb_fiber_t *fib;
1274 rb_context_t *cont;
1275 rb_proc_t *proc;
1276 int state;
1277
1278 GetFiberPtr(th->fiber, fib);
1279 cont = &fib->cont;
1280
1281 TH_PUSH_TAG(th);
1282 if ((state = EXEC_TAG()) == 0) {
1283 int argc;
1284 const VALUE *argv, args = cont->value;
1285 GetProcPtr(cont->saved_thread.first_proc, proc);
1286 argv = (argc = cont->argc) > 1 ? RARRAY_CONST_PTR(args) : &args;
1287 cont->value = Qnil;
1288 th->errinfo = Qnil;
1289 th->root_lep = rb_vm_ep_local_ep(proc->block.ep);
1290 th->root_svar = Qnil;
1291
1292 fib->status = RUNNING;
1293 cont->value = rb_vm_invoke_proc(th, proc, argc, argv, 0);
1294 }
1295 TH_POP_TAG();
1296
1297 if (state) {
1298 if (state == TAG_RAISE || state == TAG_FATAL) {
1299 rb_threadptr_pending_interrupt_enque(th, th->errinfo);
1300 }
1301 else {
1302 VALUE err = rb_vm_make_jump_tag_but_local_jump(state, th->errinfo);
1303 if (!NIL_P(err))
1304 rb_threadptr_pending_interrupt_enque(th, err);
1305 }
1306 RUBY_VM_SET_INTERRUPT(th);
1307 }
1308
1309 rb_fiber_terminate(fib);
1310 rb_bug("rb_fiber_start: unreachable");
1311 }
1312
1313 static rb_fiber_t *
1314 root_fiber_alloc(rb_thread_t *th)
1315 {
1316 rb_fiber_t *fib;
1317 /* no need to allocate vm stack */
1318 fib = fiber_t_alloc(fiber_alloc(rb_cFiber));
1319 fib->cont.type = ROOT_FIBER_CONTEXT;
1320 #if FIBER_USE_NATIVE
1321 #ifdef _WIN32
1322 fib->fib_handle = ConvertThreadToFiber(0);
1323 #endif
1324 #endif
1325 fib->status = RUNNING;
1326 fib->prev_fiber = fib->next_fiber = fib;
1327
1328 return fib;
1329 }
1330
1331 VALUE
1332 rb_fiber_current(void)
1333 {
1334 rb_thread_t *th = GET_THREAD();
1335 if (th->fiber == 0) {
1336 /* save root */
1337 rb_fiber_t *fib = root_fiber_alloc(th);
1338 th->root_fiber = th->fiber = fib->cont.self;
1339 }
1340 return th->fiber;
1341 }
1342
1343 static VALUE
1344 fiber_store(rb_fiber_t *next_fib)
1345 {
1346 rb_thread_t *th = GET_THREAD();
1347 rb_fiber_t *fib;
1348
1349 if (th->fiber) {
1350 GetFiberPtr(th->fiber, fib);
1351 cont_save_thread(&fib->cont, th);
1352 }
1353 else {
1354 /* create current fiber */
1355 fib = root_fiber_alloc(th);
1356 th->root_fiber = th->fiber = fib->cont.self;
1357 }
1358
1359 #if !FIBER_USE_NATIVE
1360 cont_save_machine_stack(th, &fib->cont);
1361 #endif
1362
1363 if (FIBER_USE_NATIVE || ruby_setjmp(fib->cont.jmpbuf)) {
1364 #if FIBER_USE_NATIVE
1365 fiber_setcontext(next_fib, fib);
1366 #ifndef _WIN32
1367 if (terminated_machine_stack.ptr) {
1368 if (machine_stack_cache_index < MAX_MACHINE_STACK_CACHE) {
1369 machine_stack_cache[machine_stack_cache_index].ptr = terminated_machine_stack.ptr;
1370 machine_stack_cache[machine_stack_cache_index].size = terminated_machine_stack.size;
1371 machine_stack_cache_index++;
1372 }
1373 else {
1374 if (terminated_machine_stack.ptr != fib->cont.machine.stack) {
1375 munmap((void*)terminated_machine_stack.ptr, terminated_machine_stack.size * sizeof(VALUE));
1376 }
1377 else {
1378 rb_bug("terminated fiber resumed");
1379 }
1380 }
1381 terminated_machine_stack.ptr = NULL;
1382 terminated_machine_stack.size = 0;
1383 }
1384 #endif
1385 #endif
1386 /* restored */
1387 GetFiberPtr(th->fiber, fib);
1388 if (fib->cont.argc == -1) rb_exc_raise(fib->cont.value);
1389 return fib->cont.value;
1390 }
1391 #if !FIBER_USE_NATIVE
1392 else {
1393 return Qundef;
1394 }
1395 #endif
1396 }
1397
1398 static inline VALUE
1399 fiber_switch(VALUE fibval, int argc, VALUE *argv, int is_resume)
1400 {
1401 VALUE value;
1402 rb_fiber_t *fib;
1403 rb_context_t *cont;
1404 rb_thread_t *th = GET_THREAD();
1405
1406 GetFiberPtr(fibval, fib);
1407 cont = &fib->cont;
1408
1409 if (th->fiber == fibval) {
1410 /* ignore fiber context switch
1411 * because destination fiber is same as current fiber
1412 */
1413 return make_passing_arg(argc, argv);
1414 }
1415
1416 if (cont->saved_thread.self != th->self) {
1417 rb_raise(rb_eFiberError, "fiber called across threads");
1418 }
1419 else if (cont->saved_thread.protect_tag != th->protect_tag) {
1420 rb_raise(rb_eFiberError, "fiber called across stack rewinding barrier");
1421 }
1422 else if (fib->status == TERMINATED) {
1423 value = rb_exc_new2(rb_eFiberError, "dead fiber called");
1424 if (th->fiber != fibval) {
1425 GetFiberPtr(th->fiber, fib);
1426 if (fib->status != TERMINATED) rb_exc_raise(value);
1427 fibval = th->root_fiber;
1428 }
1429 else {
1430 fibval = fib->prev;
1431 if (NIL_P(fibval)) fibval = th->root_fiber;
1432 }
1433 GetFiberPtr(fibval, fib);
1434 cont = &fib->cont;
1435 cont->argc = -1;
1436 cont->value = value;
1437 #if FIBER_USE_NATIVE
1438 {
1439 VALUE oldfibval;
1440 rb_fiber_t *oldfib;
1441 oldfibval = rb_fiber_current();
1442 GetFiberPtr(oldfibval, oldfib);
1443 fiber_setcontext(fib, oldfib);
1444 }
1445 #else
1446 cont_restore_0(cont, &value);
1447 #endif
1448 }
1449
1450 if (is_resume) {
1451 fib->prev = rb_fiber_current();
1452 }
1453 else {
1454 /* restore `tracing' context. see [Feature #4347] */
1455 th->trace_arg = cont->saved_thread.trace_arg;
1456 }
1457
1458 cont->argc = argc;
1459 cont->value = make_passing_arg(argc, argv);
1460
1461 value = fiber_store(fib);
1462 #if !FIBER_USE_NATIVE
1463 if (value == Qundef) {
1464 cont_restore_0(cont, &value);
1465 rb_bug("rb_fiber_resume: unreachable");
1466 }
1467 #endif
1468 RUBY_VM_CHECK_INTS(th);
1469
1470 return value;
1471 }
1472
1473 VALUE
1474 rb_fiber_transfer(VALUE fib, int argc, VALUE *argv)
1475 {
1476 return fiber_switch(fib, argc, argv, 0);
1477 }
1478
1479 VALUE
1480 rb_fiber_resume(VALUE fibval, int argc, VALUE *argv)
1481 {
1482 rb_fiber_t *fib;
1483 GetFiberPtr(fibval, fib);
1484
1485 if (fib->prev != Qnil || fib->cont.type == ROOT_FIBER_CONTEXT) {
1486 rb_raise(rb_eFiberError, "double resume");
1487 }
1488 if (fib->transfered != 0) {
1489 rb_raise(rb_eFiberError, "cannot resume transferred Fiber");
1490 }
1491
1492 return fiber_switch(fibval, argc, argv, 1);
1493 }
1494
1495 VALUE
1496 rb_fiber_yield(int argc, VALUE *argv)
1497 {
1498 return rb_fiber_transfer(return_fiber(), argc, argv);
1499 }
1500
1501 void
1502 rb_fiber_reset_root_local_storage(VALUE thval)
1503 {
1504 rb_thread_t *th;
1505 rb_fiber_t *fib;
1506
1507 GetThreadPtr(thval, th);
1508 if (th->root_fiber && th->root_fiber != th->fiber) {
1509 GetFiberPtr(th->root_fiber, fib);
1510 th->local_storage = fib->cont.saved_thread.local_storage;
1511 }
1512 }
1513
1514 /*
1515 * call-seq:
1516 * fiber.alive? -> true or false
1517 *
1518 * Returns true if the fiber can still be resumed (or transferred
1519 * to). After finishing execution of the fiber block this method will
1520 * always return false. You need to <code>require 'fiber'</code>
1521 * before using this method.
1522 */
1523 VALUE
1524 rb_fiber_alive_p(VALUE fibval)
1525 {
1526 rb_fiber_t *fib;
1527 GetFiberPtr(fibval, fib);
1528 return fib->status != TERMINATED ? Qtrue : Qfalse;
1529 }
1530
1531 /*
1532 * call-seq:
1533 * fiber.resume(args, ...) -> obj
1534 *
1535 * Resumes the fiber from the point at which the last <code>Fiber.yield</code>
1536 * was called, or starts running it if it is the first call to
1537 * <code>resume</code>. Arguments passed to resume will be the value of
1538 * the <code>Fiber.yield</code> expression or will be passed as block
1539 * parameters to the fiber's block if this is the first <code>resume</code>.
1540 *
1541 * Alternatively, when resume is called it evaluates to the arguments passed
1542 * to the next <code>Fiber.yield</code> statement inside the fiber's block
1543 * or to the block value if it runs to completion without any
1544 * <code>Fiber.yield</code>
1545 */
1546 static VALUE
1547 rb_fiber_m_resume(int argc, VALUE *argv, VALUE fib)
1548 {
1549 return rb_fiber_resume(fib, argc, argv);
1550 }
1551
1552 /*
1553 * call-seq:
1554 * fiber.transfer(args, ...) -> obj
1555 *
1556 * Transfer control to another fiber, resuming it from where it last
1557 * stopped or starting it if it was not resumed before. The calling
1558 * fiber will be suspended much like in a call to
1559 * <code>Fiber.yield</code>. You need to <code>require 'fiber'</code>
1560 * before using this method.
1561 *
1562 * The fiber which receives the transfer call is treats it much like
1563 * a resume call. Arguments passed to transfer are treated like those
1564 * passed to resume.
1565 *
1566 * You cannot resume a fiber that transferred control to another one.
1567 * This will cause a double resume error. You need to transfer control
1568 * back to this fiber before it can yield and resume.
1569 *
1570 * Example:
1571 *
1572 * fiber1 = Fiber.new do
1573 * puts "In Fiber 1"
1574 * Fiber.yield
1575 * end
1576 *
1577 * fiber2 = Fiber.new do
1578 * puts "In Fiber 2"
1579 * fiber1.transfer
1580 * puts "Never see this message"
1581 * end
1582 *
1583 * fiber3 = Fiber.new do
1584 * puts "In Fiber 3"
1585 * end
1586 *
1587 * fiber2.resume
1588 * fiber3.resume
1589 *
1590 * <em>produces</em>
1591 *
1592 * In fiber 2
1593 * In fiber 1
1594 * In fiber 3
1595 *
1596 */
1597 static VALUE
1598 rb_fiber_m_transfer(int argc, VALUE *argv, VALUE fibval)
1599 {
1600 rb_fiber_t *fib;
1601 GetFiberPtr(fibval, fib);
1602 fib->transfered = 1;
1603 return rb_fiber_transfer(fibval, argc, argv);
1604 }
1605
1606 /*
1607 * call-seq:
1608 * Fiber.yield(args, ...) -> obj
1609 *
1610 * Yields control back to the context that resumed the fiber, passing
1611 * along any arguments that were passed to it. The fiber will resume
1612 * processing at this point when <code>resume</code> is called next.
1613 * Any arguments passed to the next <code>resume</code> will be the
1614 * value that this <code>Fiber.yield</code> expression evaluates to.
1615 */
1616 static VALUE
1617 rb_fiber_s_yield(int argc, VALUE *argv, VALUE klass)
1618 {
1619 return rb_fiber_yield(argc, argv);
1620 }
1621
1622 /*
1623 * call-seq:
1624 * Fiber.current() -> fiber
1625 *
1626 * Returns the current fiber. You need to <code>require 'fiber'</code>
1627 * before using this method. If you are not running in the context of
1628 * a fiber this method will return the root fiber.
1629 */
1630 static VALUE
1631 rb_fiber_s_current(VALUE klass)
1632 {
1633 return rb_fiber_current();
1634 }
1635
1636
1637
1638 /*
1639 * Document-class: FiberError
1640 *
1641 * Raised when an invalid operation is attempted on a Fiber, in
1642 * particular when attempting to call/resume a dead fiber,
1643 * attempting to yield from the root fiber, or calling a fiber across
1644 * threads.
1645 *
1646 * fiber = Fiber.new{}
1647 * fiber.resume #=> nil
1648 * fiber.resume #=> FiberError: dead fiber called
1649 */
1650
1651 void
1652 Init_Cont(void)
1653 {
1654 #if FIBER_USE_NATIVE
1655 rb_thread_t *th = GET_THREAD();
1656
1657 #ifdef _WIN32
1658 SYSTEM_INFO info;
1659 GetSystemInfo(&info);
1660 pagesize = info.dwPageSize;
1661 #else /* not WIN32 */
1662 pagesize = sysconf(_SC_PAGESIZE);
1663 #endif
1664 SET_MACHINE_STACK_END(&th->machine.stack_end);
1665 #endif
1666
1667 rb_cFiber = rb_define_class("Fiber", rb_cObject);
1668 rb_define_alloc_func(rb_cFiber, fiber_alloc);
1669 rb_eFiberError = rb_define_class("FiberError", rb_eStandardError);
1670 rb_define_singleton_method(rb_cFiber, "yield", rb_fiber_s_yield, -1);
1671 rb_define_method(rb_cFiber, "initialize", rb_fiber_init, 0);
1672 rb_define_method(rb_cFiber, "resume", rb_fiber_m_resume, -1);
1673 }
1674
1675 RUBY_SYMBOL_EXPORT_BEGIN
1676
1677 void
1678 ruby_Init_Continuation_body(void)
1679 {
1680 rb_cContinuation = rb_define_class("Continuation", rb_cObject);
1681 rb_undef_alloc_func(rb_cContinuation);
1682 rb_undef_method(CLASS_OF(rb_cContinuation), "new");
1683 rb_define_method(rb_cContinuation, "call", rb_cont_call, -1);
1684 rb_define_method(rb_cContinuation, "[]", rb_cont_call, -1);
1685 rb_define_global_function("callcc", rb_callcc, 0);
1686 }
1687
1688 void
1689 ruby_Init_Fiber_as_Coroutine(void)
1690 {
1691 rb_define_method(rb_cFiber, "transfer", rb_fiber_m_transfer, -1);
1692 rb_define_method(rb_cFiber, "alive?", rb_fiber_alive_p, 0);
1693 rb_define_singleton_method(rb_cFiber, "current", rb_fiber_s_current, 0);
1694 }
1695
1696 RUBY_SYMBOL_EXPORT_END
rb_gc
void rb_gc(void)
Definition: gc.c:5190
rb_thread_struct::cfp
rb_control_frame_t * cfp
Definition: vm_core.h:531
rb_context_struct::vm_stack
VALUE * vm_stack
Definition: cont.c:95
rb_eStandardError
VALUE rb_eStandardError
Definition: error.c:546
rb_thread_struct::stack_end
VALUE * stack_end
Definition: vm_core.h:622
RUBY_VM_CHECK_INTS
#define RUBY_VM_CHECK_INTS(th)
Definition: vm_core.h:989
rb_thread_struct::vm
rb_vm_t * vm
Definition: vm_core.h:526
rb_ensure_list::entry
struct rb_ensure_entry entry
Definition: vm_core.h:521
rb_exc_new2
#define rb_exc_new2
Definition: intern.h:247
THREAD_MUST_BE_RUNNING
#define THREAD_MUST_BE_RUNNING(th)
Definition: cont.c:169
GetContPtr
#define GetContPtr(obj, ptr)
Definition: cont.c:159
rb_bug
void rb_bug(const char *fmt,...)
Definition: error.c:327
rb_thread_struct::root_lep
VALUE * root_lep
Definition: vm_core.h:557
FIBER_CONTEXT
Definition: cont.c:86
ruby_longjmp
#define ruby_longjmp(env, val)
Definition: eval_intern.h:51
RUBY_TYPED_FREE_IMMEDIATELY
#define RUBY_TYPED_FREE_IMMEDIATELY
Definition: ruby.h:1015
rb_thread_struct::protect_tag
struct rb_vm_protect_tag * protect_tag
Definition: vm_core.h:594
rb_gc_mark_locations
#define rb_gc_mark_locations(start, end)
Definition: gc.c:3316
CONTINUATION_CONTEXT
Definition: cont.c:85
rb_cContinuation
static VALUE rb_cContinuation
Definition: cont.c:155
st_table
Definition: st.h:69
RUBY_VM_SET_INTERRUPT
#define RUBY_VM_SET_INTERRUPT(th)
Definition: vm_core.h:960
rb_thread_struct::local_storage
st_table * local_storage
Definition: vm_core.h:611
rb_control_frame_struct::klass
VALUE klass
Definition: vm_core.h:451
ROOT_FIBER_CONTEXT
Definition: cont.c:87
rb_undef_alloc_func
void rb_undef_alloc_func(VALUE)
Definition: vm_method.c:519
rb_define_singleton_method
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1655
GetProcPtr
#define GetProcPtr(obj, ptr)
Definition: vm_core.h:697
ruby.h
rb_context_struct::self
VALUE self
Definition: cont.c:92
FLUSH_REGISTER_WINDOWS
#define FLUSH_REGISTER_WINDOWS
Definition: defines.h:270
CLASS_OF
#define CLASS_OF(v)
Definition: ruby.h:440
cont_capture
static VALUE cont_capture(volatile int *stat)
Definition: cont.c:468
lookup_rollback_func
static VALUE lookup_rollback_func(VALUE(*ensure_func)(ANYARGS))
Definition: cont.c:957
Qtrue
#define Qtrue
Definition: ruby.h:426
st_insert
int st_insert(st_table *, st_data_t, st_data_t)
TypedData_Wrap_Struct
#define TypedData_Wrap_Struct(klass, data_type, sval)
Definition: ruby.h:1027
rb_fiber_reset_root_local_storage
void rb_fiber_reset_root_local_storage(VALUE thval)
Definition: cont.c:1502
rb_fiber_struct::prev
VALUE prev
Definition: cont.c:135
rb_fiber_m_resume
static VALUE rb_fiber_m_resume(int argc, VALUE *argv, VALUE fib)
Definition: cont.c:1547
eval_intern.h
cont_data_type
static const rb_data_type_t cont_data_type
Definition: cont.c:154
GetFiberPtr
#define GetFiberPtr(obj, ptr)
Definition: cont.c:162
rb_ensure_entry::data2
VALUE data2
Definition: vm_core.h:516
root_fiber_alloc
static rb_fiber_t * root_fiber_alloc(rb_thread_t *th)
Definition: cont.c:1314
rb_control_frame_struct::sp
VALUE * sp
Definition: vm_core.h:447
rb_context_struct::type
enum context_type type
Definition: cont.c:91
rb_fiber_terminate
static void rb_fiber_terminate(rb_fiber_t *fib)
Definition: cont.c:1254
TERMINATED
Definition: cont.c:119
st_free_table
void st_free_table(st_table *)
Definition: st.c:334
rb_fiber_yield
VALUE rb_fiber_yield(int argc, VALUE *argv)
Definition: cont.c:1496
rb_vm_struct::fiber_machine_stack_size
size_t fiber_machine_stack_size
Definition: vm_core.h:423
rb_ary_tmp_new
VALUE rb_ary_tmp_new(long capa)
Definition: array.c:534
make_passing_arg
static VALUE make_passing_arg(int argc, VALUE *argv)
Definition: cont.c:932
rb_fiber_struct::transfered
int transfered
Definition: cont.c:143
VM_ENVVAL_BLOCK_PTR
#define VM_ENVVAL_BLOCK_PTR(v)
Definition: vm_core.h:813
STACK_UPPER
#define STACK_UPPER(x, a, b)
Definition: gc.h:74
rb_fiber_alive_p
VALUE rb_fiber_alive_p(VALUE fibval)
Definition: cont.c:1524
fiber_switch
static VALUE fiber_switch(VALUE fibval, int argc, VALUE *argv, int is_resume)
Definition: cont.c:1399
rb_threadptr_pending_interrupt_enque
void rb_threadptr_pending_interrupt_enque(rb_thread_t *th, VALUE v)
Definition: thread.c:1544
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1857
cont_save_thread
static void cont_save_thread(rb_context_t *cont, rb_thread_t *th)
Definition: cont.c:431
RUBY_MARK_LEAVE
#define RUBY_MARK_LEAVE(msg)
Definition: gc.h:54
rb_fiber_current
VALUE rb_fiber_current(void)
Definition: cont.c:1332
gc.h
rb_context_struct::argc
int argc
Definition: cont.c:93
C
#define C
Definition: util.c:195
rb_define_alloc_func
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
fiber_init
static VALUE fiber_init(VALUE fibval, VALUE proc)
Definition: cont.c:1170
DATA_PTR
#define DATA_PTR(dta)
Definition: ruby.h:992
rb_gc_mark
void rb_gc_mark(VALUE ptr)
Definition: gc.c:3604
fiber_link_join
static void fiber_link_join(rb_fiber_t *fib)
Definition: cont.c:316
TAG_RAISE
#define TAG_RAISE
Definition: eval_intern.h:193
rb_context_struct::jmpbuf
rb_jmpbuf_t jmpbuf
Definition: cont.c:111
rb_define_global_function
void rb_define_global_function(const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a global function.
Definition: class.c:1684
rb_vm_invoke_proc
VALUE rb_vm_invoke_proc(rb_thread_t *th, rb_proc_t *proc, int argc, const VALUE *argv, const rb_block_t *blockptr)
Definition: vm.c:897
rb_ensure_entry
Definition: vm_core.h:513
fiber_data_type
static const rb_data_type_t fiber_data_type
Definition: cont.c:154
rb_thread_struct
Definition: vm_core.h:524
rb_context_struct::value
VALUE value
Definition: cont.c:94
rb_undef_method
void rb_undef_method(VALUE klass, const char *name)
Definition: class.c:1506
rb_thread_struct::machine
struct rb_thread_struct::@169 machine
cont_free
static void cont_free(void *ptr)
Definition: cont.c:221
rb_context_struct::machine
struct rb_context_struct::@2 machine
rb_context_struct::saved_thread
rb_thread_t saved_thread
Definition: cont.c:110
rb_context_t
struct rb_context_struct rb_context_t
rb_eFiberError
static VALUE rb_eFiberError
Definition: cont.c:157
rb_context_struct::stack
VALUE * stack
Definition: cont.c:101
st_data_t
RUBY_SYMBOL_EXPORT_BEGIN typedef unsigned long st_data_t
Definition: st.h:20
TAG_FATAL
#define TAG_FATAL
Definition: eval_intern.h:195
rb_exc_raise
void rb_exc_raise(VALUE mesg)
Definition: eval.c:567
rb_context_struct::vm_stack_clen
size_t vm_stack_clen
Definition: cont.c:98
rb_thread_struct::stack
VALUE * stack
Definition: vm_core.h:529
fiber_memsize
static size_t fiber_memsize(const void *ptr)
Definition: cont.c:354
rb_control_frame_struct::proc
VALUE proc
Definition: vm_core.h:454
rb_control_frame_struct::self
VALUE self
Definition: vm_core.h:450
TH_POP_TAG
#define TH_POP_TAG()
Definition: eval_intern.h:128
st_lookup
int st_lookup(st_table *, st_data_t, st_data_t *)
rb_fiber_struct::status
enum fiber_status status
Definition: cont.c:136
rb_fiber_resume
VALUE rb_fiber_resume(VALUE fibval, int argc, VALUE *argv)
Definition: cont.c:1480
return_fiber
static VALUE return_fiber(void)
Definition: cont.c:1229
ALLOC_N
#define ALLOC_N(type, n)
Definition: ruby.h:1333
EXEC_TAG
#define EXEC_TAG()
Definition: eval_intern.h:168
val
#define val
rb_vm_ep_local_ep
VALUE * rb_vm_ep_local_ep(VALUE *ep)
Definition: vm.c:34
rb_control_frame_struct::block_iseq
rb_iseq_t * block_iseq
Definition: vm_core.h:453
rb_cObject
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:1553
rb_eRuntimeError
VALUE rb_eRuntimeError
Definition: error.c:547
rb_context_struct::ensure_array
rb_ensure_entry_t * ensure_array
Definition: cont.c:112
rb_vm_struct::fiber_vm_stack_size
size_t fiber_vm_stack_size
Definition: vm_core.h:422
rb_typeddata_is_kind_of
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type)
Definition: error.c:510
CREATED
Definition: cont.c:117
rb_fiber_init
static VALUE rb_fiber_init(VALUE fibval)
Definition: cont.c:1217
cont_restore_1
static void cont_restore_1(rb_context_t *cont)
Definition: cont.c:733
rb_control_frame_struct::iseq
rb_iseq_t * iseq
Definition: vm_core.h:448
NIL_P
#define NIL_P(v)
Definition: ruby.h:438
UNLIKELY
#define UNLIKELY(x)
Definition: vm_core.h:109
rb_define_class
VALUE rb_define_class(const char *name, VALUE super)
Defines a top-level class.
Definition: class.c:630
unistd.h
fiber_alloc
static VALUE fiber_alloc(VALUE klass)
Definition: cont.c:1140
rb_vm_tag::tag
VALUE tag
Definition: vm_core.h:489
RUBY_MARK_ENTER
#define RUBY_MARK_ENTER(msg)
Definition: gc.h:53
rb_fiber_new
VALUE rb_fiber_new(VALUE(*func)(ANYARGS), VALUE obj)
Definition: cont.c:1223
argc
int argc
Definition: ruby.c:131
Qfalse
#define Qfalse
Definition: ruby.h:425
ruby_Init_Fiber_as_Coroutine
void ruby_Init_Fiber_as_Coroutine(void)
Definition: cont.c:1689
rb_fiber_start
void rb_fiber_start(void)
Definition: cont.c:1270
ALLOCA_N
#define ALLOCA_N(type, n)
Definition: ruby.h:1337
cont_mark
static void cont_mark(void *ptr)
Definition: cont.c:174
rb_callcc
static VALUE rb_callcc(VALUE self)
Definition: cont.c:918
MEMCPY
#define MEMCPY(p1, p2, type, n)
Definition: ruby.h:1352
rb_ary_new4
#define rb_ary_new4
Definition: intern.h:92
rb_fiber_m_transfer
static VALUE rb_fiber_m_transfer(int argc, VALUE *argv, VALUE fibval)
Definition: cont.c:1598
err
int err
Definition: win32.c:114
rb_fiber_s_current
static VALUE rb_fiber_s_current(VALUE klass)
Definition: cont.c:1631
ALLOC
#define ALLOC(type)
Definition: ruby.h:1334
RUNNING
Definition: cont.c:118
rb_context_struct::vm_stack_slen
size_t vm_stack_slen
Definition: cont.c:97
rb_yield
VALUE rb_yield(VALUE)
Definition: vm_eval.c:942
RARRAY_CONST_PTR
#define RARRAY_CONST_PTR(a)
Definition: ruby.h:886
REALLOC_N
#define REALLOC_N(var, type, n)
Definition: ruby.h:1335
func
SSL_METHOD *(* func)(void)
Definition: ossl_ssl.c:113
errno
int errno
STACK_DIR_UPPER
#define STACK_DIR_UPPER(a, b)
Definition: gc.h:82
rb_vm_stack_to_heap
void rb_vm_stack_to_heap(rb_thread_t *th)
Definition: vm.c:635
rb_proc_t
Definition: vm_core.h:700
ruby_Init_Continuation_body
RUBY_SYMBOL_EXPORT_BEGIN void ruby_Init_Continuation_body(void)
Definition: cont.c:1678
cont_new
static rb_context_t * cont_new(VALUE klass)
Definition: cont.c:454
RUBY_SYMBOL_EXPORT_END
#define RUBY_SYMBOL_EXPORT_END
Definition: missing.h:39
ruby_xfree
void ruby_xfree(void *x)
Definition: gc.c:6242
rb_cont_call
static VALUE rb_cont_call(int argc, VALUE *argv, VALUE contval)
Definition: cont.c:1035
Init_Cont
void Init_Cont(void)
Definition: cont.c:1652
buf
unsigned char buf[MIME_BUF_SIZE]
Definition: nkf.c:4308
internal.h
rb_cFiber
static VALUE rb_cFiber
Definition: cont.c:156
Qnil
#define Qnil
Definition: ruby.h:427
vm_core.h
VALUE
unsigned long VALUE
Definition: ruby.h:88
STACK_GROW_DIR_DETECTION
#define STACK_GROW_DIR_DETECTION
Definition: gc.h:81
rb_fiber_struct::cont
rb_context_t cont
Definition: cont.c:134
rb_jmpbuf_t
RUBY_JMP_BUF rb_jmpbuf_t
Definition: vm_core.h:482
fiber_store
static VALUE fiber_store(rb_fiber_t *next_fib)
Definition: cont.c:1344
rb_fiber_t
struct rb_fiber_struct rb_fiber_t
rb_thread_struct::first_proc
VALUE first_proc
Definition: vm_core.h:615
RUBY_SYMBOL_EXPORT_BEGIN
#define RUBY_SYMBOL_EXPORT_BEGIN
Definition: missing.h:38
fiber_mark
static void fiber_mark(void *ptr)
Definition: cont.c:304
rb_thread_mark
void rb_thread_mark(void *th)
Definition: vm.c:2014
TH_PUSH_TAG
#define TH_PUSH_TAG(th)
Definition: eval_intern.h:122
SET_MACHINE_STACK_END
#define SET_MACHINE_STACK_END(p)
Definition: gc.h:11
rb_ensure_list::next
struct rb_ensure_list * next
Definition: vm_core.h:520
st_init_numtable
st_table * st_init_numtable(void)
Definition: st.c:272
rb_thread_struct::raised_flag
int raised_flag
Definition: vm_core.h:533
cont_init
static void cont_init(rb_context_t *cont, rb_thread_t *th)
Definition: cont.c:446
rb_control_frame_struct::flag
VALUE flag
Definition: vm_core.h:449
rb_fiber_s_yield
static VALUE rb_fiber_s_yield(int argc, VALUE *argv, VALUE klass)
Definition: cont.c:1617
FIBER_USE_NATIVE
#define FIBER_USE_NATIVE
Definition: cont.c:68
ruby_setjmp
#define ruby_setjmp(env)
Definition: eval_intern.h:50
rb_thread_struct::status
enum rb_thread_status status
Definition: vm_core.h:562
RUBY_FREE_UNLESS_NULL
#define RUBY_FREE_UNLESS_NULL(ptr)
Definition: gc.h:61
rb_fiber_struct::next_fiber
struct rb_fiber_struct * next_fiber
Definition: cont.c:138
rb_context_struct::stack_src
VALUE * stack_src
Definition: cont.c:102
cont_restore_thread
static void cont_restore_thread(rb_context_t *cont)
Definition: cont.c:526
size
int size
Definition: encoding.c:49
f
#define f
rb_thread_struct::mark_stack_len
int mark_stack_len
Definition: vm_core.h:631
rb_vm_struct::default_params
struct rb_vm_struct::@168 default_params
rb_context_struct
Definition: cont.c:90
rb_thread_struct::root_svar
VALUE root_svar
Definition: vm_core.h:558
rb_proc_t::block
rb_block_t block
Definition: vm_core.h:701
rb_thread_struct::stack_start
VALUE * stack_start
Definition: vm_core.h:621
rb_control_frame_struct::pc
VALUE * pc
Definition: vm_core.h:446
rb_ensure_list
Definition: vm_core.h:519
rb_block_proc
VALUE rb_block_proc(void)
Definition: proc.c:620
st_memsize
size_t st_memsize(const st_table *)
Definition: st.c:342
ANYARGS
#define ANYARGS
Definition: defines.h:98
rb_control_frame_struct::me
const rb_method_entry_t * me
Definition: vm_core.h:455
RUBY_FREE_LEAVE
#define RUBY_FREE_LEAVE(msg)
Definition: gc.h:56
rb_ensure_entry::marker
VALUE marker
Definition: vm_core.h:514
rb_data_type_struct
Definition: ruby.h:966
RUBY_FREE_ENTER
#define RUBY_FREE_ENTER(msg)
Definition: gc.h:55
strerror
RUBY_EXTERN char * strerror(int)
Definition: strerror.c:11
rb_obj_is_fiber
VALUE rb_obj_is_fiber(VALUE obj)
Definition: cont.c:370
STACK_PAD_SIZE
#define STACK_PAD_SIZE
rb_fiber_transfer
VALUE rb_fiber_transfer(VALUE fib, int argc, VALUE *argv)
Definition: cont.c:1474
rb_control_frame_struct::ep
VALUE * ep
Definition: vm_core.h:452
rb_fiber_struct
Definition: cont.c:133
rb_proc_new
VALUE rb_proc_new(VALUE(*)(ANYARGS), VALUE)
Definition: proc.c:2301
rb_thread_struct::root_fiber
VALUE root_fiber
Definition: vm_core.h:642
rb_thread_struct::fiber
VALUE fiber
Definition: vm_core.h:641
fiber_t_alloc
static rb_fiber_t * fiber_t_alloc(VALUE fibval)
Definition: cont.c:1146
TypedData_Make_Struct
#define TypedData_Make_Struct(klass, type, data_type, sval)
Definition: ruby.h:1030
rb_fiber_struct::prev_fiber
struct rb_fiber_struct * prev_fiber
Definition: cont.c:137
rb_thread_struct::state
int state
Definition: vm_core.h:537
GetThreadPtr
#define GetThreadPtr(obj, ptr)
Definition: vm_core.h:472
rb_thread_struct::ensure_list
rb_ensure_list_t * ensure_list
Definition: vm_core.h:646
rb_thread_struct::root_jmpbuf
rb_jmpbuf_t root_jmpbuf
Definition: vm_core.h:643
cont_restore_0
static void cont_restore_0(rb_context_t *cont, VALUE *addr_in_prev_frame)
Definition: cont.c:801
rb_thread_struct::safe_level
int safe_level
Definition: vm_core.h:532
rb_ensure_entry::e_proc
VALUE(* e_proc)(ANYARGS)
Definition: vm_core.h:515
rb_thread_struct::stack_size
size_t stack_size
Definition: vm_core.h:530
rb_thread_struct::self
VALUE self
Definition: vm_core.h:525
fiber_link_remove
static void fiber_link_remove(rb_fiber_t *fib)
Definition: cont.c:330
rb_thread_struct::tag
struct rb_vm_tag * tag
Definition: vm_core.h:593
ruby_register_rollback_func_for_ensure
void ruby_register_rollback_func_for_ensure(VALUE(*ensure_func)(ANYARGS), VALUE(*rollback_func)(ANYARGS))
Definition: cont.c:947
context_type
context_type
Definition: cont.c:84
rb_context_struct::stack_size
size_t stack_size
Definition: cont.c:103
fiber_free
static void fiber_free(void *ptr)
Definition: cont.c:337
rb_vm_make_jump_tag_but_local_jump
VALUE rb_vm_make_jump_tag_but_local_jump(int state, VALUE val)
Definition: vm.c:1101
cont_memsize
static size_t cont_memsize(const void *ptr)
Definition: cont.c:276
rb_thread_struct::stack_maxsize
size_t stack_maxsize
Definition: vm_core.h:623
stat
#define stat(path, st)
Definition: win32.h:213
cont_save_machine_stack
static void cont_save_machine_stack(rb_thread_t *th, rb_context_t *cont)
Definition: cont.c:381
fiber_status
fiber_status
Definition: cont.c:116
NORETURN
NORETURN(NOINLINE(static void cont_restore_0(rb_context_t *, VALUE *)))
rollback_ensure_stack
static void rollback_ensure_stack(VALUE self, rb_ensure_list_t *current, rb_ensure_entry_t *target)
Definition: cont.c:968
NULL
#define NULL
Definition: _sdbm.c:103
Qundef
#define Qundef
Definition: ruby.h:428
rb_thread_struct::errinfo
VALUE errinfo
Definition: vm_core.h:573
GET_THREAD
static rb_thread_t * GET_THREAD(void)
Definition: vm_core.h:927
rb_define_method
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1488
rb_thread_struct::trace_arg
struct rb_trace_arg_struct * trace_arg
Definition: vm_core.h:638
argv
char ** argv
Definition: ruby.c:132
rb_block_struct::ep
VALUE * ep
Definition: vm_core.h:465
rb_context_struct::ensure_list
rb_ensure_list_t * ensure_list
Definition: cont.c:113
NOINLINE
NOINLINE(static VALUE cont_capture(volatile int *stat))
GET_VM
#define GET_VM()
Definition: vm_core.h:920