00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "ruby/ruby.h"
00013 #include "internal.h"
00014 #include "vm_core.h"
00015 #include "gc.h"
00016 #include "eval_intern.h"
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #if !defined(FIBER_USE_NATIVE)
00030 # if defined(HAVE_GETCONTEXT) && defined(HAVE_SETCONTEXT)
00031 # if 0
00032 # elif defined(__NetBSD__)
00033
00034
00035
00036
00037
00038 # define FIBER_USE_NATIVE 0
00039 # elif defined(__sun)
00040
00041
00042 # define FIBER_USE_NATIVE 0
00043 # elif defined(__ia64)
00044
00045
00046 # define FIBER_USE_NATIVE 0
00047 # elif defined(__GNU__)
00048
00049
00050
00051
00052
00053 # define FIBER_USE_NATIVE 0
00054 # else
00055 # define FIBER_USE_NATIVE 1
00056 # endif
00057 # elif defined(_WIN32)
00058 # if _WIN32_WINNT >= 0x0400
00059
00060
00061
00062
00063 # define FIBER_USE_NATIVE 1
00064 # endif
00065 # endif
00066 #endif
00067 #if !defined(FIBER_USE_NATIVE)
00068 #define FIBER_USE_NATIVE 0
00069 #endif
00070
00071 #if FIBER_USE_NATIVE
00072 #ifndef _WIN32
00073 #include <unistd.h>
00074 #include <sys/mman.h>
00075 #include <ucontext.h>
00076 #endif
00077 #define RB_PAGE_SIZE (pagesize)
00078 #define RB_PAGE_MASK (~(RB_PAGE_SIZE - 1))
00079 static long pagesize;
00080 #endif
00081
00082 #define CAPTURE_JUST_VALID_VM_STACK 1
00083
00084 enum context_type {
00085 CONTINUATION_CONTEXT = 0,
00086 FIBER_CONTEXT = 1,
00087 ROOT_FIBER_CONTEXT = 2
00088 };
00089
00090 typedef struct rb_context_struct {
00091 enum context_type type;
00092 VALUE self;
00093 int argc;
00094 VALUE value;
00095 VALUE *vm_stack;
00096 #ifdef CAPTURE_JUST_VALID_VM_STACK
00097 size_t vm_stack_slen;
00098 size_t vm_stack_clen;
00099 #endif
00100 struct {
00101 VALUE *stack;
00102 VALUE *stack_src;
00103 size_t stack_size;
00104 #ifdef __ia64
00105 VALUE *register_stack;
00106 VALUE *register_stack_src;
00107 int register_stack_size;
00108 #endif
00109 } machine;
00110 rb_thread_t saved_thread;
00111 rb_jmpbuf_t jmpbuf;
00112 rb_ensure_entry_t *ensure_array;
00113 rb_ensure_list_t *ensure_list;
00114 } rb_context_t;
00115
00116 enum fiber_status {
00117 CREATED,
00118 RUNNING,
00119 TERMINATED
00120 };
00121
00122 #if FIBER_USE_NATIVE && !defined(_WIN32)
00123 #define MAX_MACHINE_STACK_CACHE 10
00124 static int machine_stack_cache_index = 0;
00125 typedef struct machine_stack_cache_struct {
00126 void *ptr;
00127 size_t size;
00128 } machine_stack_cache_t;
00129 static machine_stack_cache_t machine_stack_cache[MAX_MACHINE_STACK_CACHE];
00130 static machine_stack_cache_t terminated_machine_stack;
00131 #endif
00132
00133 typedef struct rb_fiber_struct {
00134 rb_context_t cont;
00135 VALUE prev;
00136 enum fiber_status status;
00137 struct rb_fiber_struct *prev_fiber;
00138 struct rb_fiber_struct *next_fiber;
00139
00140
00141
00142
00143 int transfered;
00144
00145 #if FIBER_USE_NATIVE
00146 #ifdef _WIN32
00147 void *fib_handle;
00148 #else
00149 ucontext_t context;
00150 #endif
00151 #endif
00152 } rb_fiber_t;
00153
00154 static const rb_data_type_t cont_data_type, fiber_data_type;
00155 static VALUE rb_cContinuation;
00156 static VALUE rb_cFiber;
00157 static VALUE rb_eFiberError;
00158
00159 #define GetContPtr(obj, ptr) \
00160 TypedData_Get_Struct((obj), rb_context_t, &cont_data_type, (ptr))
00161
00162 #define GetFiberPtr(obj, ptr) do {\
00163 TypedData_Get_Struct((obj), rb_fiber_t, &fiber_data_type, (ptr)); \
00164 if (!(ptr)) rb_raise(rb_eFiberError, "uninitialized fiber"); \
00165 } while (0)
00166
00167 NOINLINE(static VALUE cont_capture(volatile int *stat));
00168
00169 #define THREAD_MUST_BE_RUNNING(th) do { \
00170 if (!(th)->tag) rb_raise(rb_eThreadError, "not running thread"); \
00171 } while (0)
00172
00173 static void
00174 cont_mark(void *ptr)
00175 {
00176 RUBY_MARK_ENTER("cont");
00177 if (ptr) {
00178 rb_context_t *cont = ptr;
00179 rb_gc_mark(cont->value);
00180 rb_thread_mark(&cont->saved_thread);
00181 rb_gc_mark(cont->saved_thread.self);
00182
00183 if (cont->vm_stack) {
00184 #ifdef CAPTURE_JUST_VALID_VM_STACK
00185 rb_gc_mark_locations(cont->vm_stack,
00186 cont->vm_stack + cont->vm_stack_slen + cont->vm_stack_clen);
00187 #else
00188 rb_gc_mark_localtion(cont->vm_stack,
00189 cont->vm_stack, cont->saved_thread.stack_size);
00190 #endif
00191 }
00192
00193 if (cont->machine.stack) {
00194 if (cont->type == CONTINUATION_CONTEXT) {
00195
00196 rb_gc_mark_locations(cont->machine.stack,
00197 cont->machine.stack + cont->machine.stack_size);
00198 }
00199 else {
00200
00201 rb_thread_t *th;
00202 rb_fiber_t *fib = (rb_fiber_t*)cont;
00203 GetThreadPtr(cont->saved_thread.self, th);
00204 if ((th->fiber != cont->self) && fib->status == RUNNING) {
00205 rb_gc_mark_locations(cont->machine.stack,
00206 cont->machine.stack + cont->machine.stack_size);
00207 }
00208 }
00209 }
00210 #ifdef __ia64
00211 if (cont->machine.register_stack) {
00212 rb_gc_mark_locations(cont->machine.register_stack,
00213 cont->machine.register_stack + cont->machine.register_stack_size);
00214 }
00215 #endif
00216 }
00217 RUBY_MARK_LEAVE("cont");
00218 }
00219
00220 static void
00221 cont_free(void *ptr)
00222 {
00223 RUBY_FREE_ENTER("cont");
00224 if (ptr) {
00225 rb_context_t *cont = ptr;
00226 RUBY_FREE_UNLESS_NULL(cont->saved_thread.stack); fflush(stdout);
00227 #if FIBER_USE_NATIVE
00228 if (cont->type == CONTINUATION_CONTEXT) {
00229
00230 ruby_xfree(cont->ensure_array);
00231 RUBY_FREE_UNLESS_NULL(cont->machine.stack);
00232 }
00233 else {
00234
00235 #ifdef _WIN32
00236 if (GET_THREAD()->fiber != cont->self && cont->type != ROOT_FIBER_CONTEXT) {
00237
00238 rb_fiber_t *fib = (rb_fiber_t*)cont;
00239 if (fib->fib_handle) {
00240 DeleteFiber(fib->fib_handle);
00241 }
00242 }
00243 #else
00244 if (GET_THREAD()->fiber != cont->self) {
00245 rb_fiber_t *fib = (rb_fiber_t*)cont;
00246 if (fib->context.uc_stack.ss_sp) {
00247 if (cont->type == ROOT_FIBER_CONTEXT) {
00248 rb_bug("Illegal root fiber parameter");
00249 }
00250 munmap((void*)fib->context.uc_stack.ss_sp, fib->context.uc_stack.ss_size);
00251 }
00252 }
00253 else {
00254
00255
00256
00257 }
00258 #endif
00259 }
00260 #else
00261 ruby_xfree(cont->ensure_array);
00262 RUBY_FREE_UNLESS_NULL(cont->machine.stack);
00263 #endif
00264 #ifdef __ia64
00265 RUBY_FREE_UNLESS_NULL(cont->machine.register_stack);
00266 #endif
00267 RUBY_FREE_UNLESS_NULL(cont->vm_stack);
00268
00269
00270 ruby_xfree(ptr);
00271 }
00272 RUBY_FREE_LEAVE("cont");
00273 }
00274
00275 static size_t
00276 cont_memsize(const void *ptr)
00277 {
00278 const rb_context_t *cont = ptr;
00279 size_t size = 0;
00280 if (cont) {
00281 size = sizeof(*cont);
00282 if (cont->vm_stack) {
00283 #ifdef CAPTURE_JUST_VALID_VM_STACK
00284 size_t n = (cont->vm_stack_slen + cont->vm_stack_clen);
00285 #else
00286 size_t n = cont->saved_thread.stack_size;
00287 #endif
00288 size += n * sizeof(*cont->vm_stack);
00289 }
00290
00291 if (cont->machine.stack) {
00292 size += cont->machine.stack_size * sizeof(*cont->machine.stack);
00293 }
00294 #ifdef __ia64
00295 if (cont->machine.register_stack) {
00296 size += cont->machine.register_stack_size * sizeof(*cont->machine.register_stack);
00297 }
00298 #endif
00299 }
00300 return size;
00301 }
00302
00303 static void
00304 fiber_mark(void *ptr)
00305 {
00306 RUBY_MARK_ENTER("cont");
00307 if (ptr) {
00308 rb_fiber_t *fib = ptr;
00309 rb_gc_mark(fib->prev);
00310 cont_mark(&fib->cont);
00311 }
00312 RUBY_MARK_LEAVE("cont");
00313 }
00314
00315 static void
00316 fiber_link_join(rb_fiber_t *fib)
00317 {
00318 VALUE current_fibval = rb_fiber_current();
00319 rb_fiber_t *current_fib;
00320 GetFiberPtr(current_fibval, current_fib);
00321
00322
00323 fib->next_fiber = current_fib->next_fiber;
00324 fib->prev_fiber = current_fib;
00325 current_fib->next_fiber->prev_fiber = fib;
00326 current_fib->next_fiber = fib;
00327 }
00328
00329 static void
00330 fiber_link_remove(rb_fiber_t *fib)
00331 {
00332 fib->prev_fiber->next_fiber = fib->next_fiber;
00333 fib->next_fiber->prev_fiber = fib->prev_fiber;
00334 }
00335
00336 static void
00337 fiber_free(void *ptr)
00338 {
00339 RUBY_FREE_ENTER("fiber");
00340 if (ptr) {
00341 rb_fiber_t *fib = ptr;
00342 if (fib->cont.type != ROOT_FIBER_CONTEXT &&
00343 fib->cont.saved_thread.local_storage) {
00344 st_free_table(fib->cont.saved_thread.local_storage);
00345 }
00346 fiber_link_remove(fib);
00347
00348 cont_free(&fib->cont);
00349 }
00350 RUBY_FREE_LEAVE("fiber");
00351 }
00352
00353 static size_t
00354 fiber_memsize(const void *ptr)
00355 {
00356 const rb_fiber_t *fib = ptr;
00357 size_t size = 0;
00358 if (ptr) {
00359 size = sizeof(*fib);
00360 if (fib->cont.type != ROOT_FIBER_CONTEXT &&
00361 fib->cont.saved_thread.local_storage != NULL) {
00362 size += st_memsize(fib->cont.saved_thread.local_storage);
00363 }
00364 size += cont_memsize(&fib->cont);
00365 }
00366 return size;
00367 }
00368
00369 VALUE
00370 rb_obj_is_fiber(VALUE obj)
00371 {
00372 if (rb_typeddata_is_kind_of(obj, &fiber_data_type)) {
00373 return Qtrue;
00374 }
00375 else {
00376 return Qfalse;
00377 }
00378 }
00379
00380 static void
00381 cont_save_machine_stack(rb_thread_t *th, rb_context_t *cont)
00382 {
00383 size_t size;
00384
00385 SET_MACHINE_STACK_END(&th->machine.stack_end);
00386 #ifdef __ia64
00387 th->machine.register_stack_end = rb_ia64_bsp();
00388 #endif
00389
00390 if (th->machine.stack_start > th->machine.stack_end) {
00391 size = cont->machine.stack_size = th->machine.stack_start - th->machine.stack_end;
00392 cont->machine.stack_src = th->machine.stack_end;
00393 }
00394 else {
00395 size = cont->machine.stack_size = th->machine.stack_end - th->machine.stack_start;
00396 cont->machine.stack_src = th->machine.stack_start;
00397 }
00398
00399 if (cont->machine.stack) {
00400 REALLOC_N(cont->machine.stack, VALUE, size);
00401 }
00402 else {
00403 cont->machine.stack = ALLOC_N(VALUE, size);
00404 }
00405
00406 FLUSH_REGISTER_WINDOWS;
00407 MEMCPY(cont->machine.stack, cont->machine.stack_src, VALUE, size);
00408
00409 #ifdef __ia64
00410 rb_ia64_flushrs();
00411 size = cont->machine.register_stack_size = th->machine.register_stack_end - th->machine.register_stack_start;
00412 cont->machine.register_stack_src = th->machine.register_stack_start;
00413 if (cont->machine.register_stack) {
00414 REALLOC_N(cont->machine.register_stack, VALUE, size);
00415 }
00416 else {
00417 cont->machine.register_stack = ALLOC_N(VALUE, size);
00418 }
00419
00420 MEMCPY(cont->machine.register_stack, cont->machine.register_stack_src, VALUE, size);
00421 #endif
00422 }
00423
00424 static const rb_data_type_t cont_data_type = {
00425 "continuation",
00426 {cont_mark, cont_free, cont_memsize,},
00427 NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
00428 };
00429
00430 static void
00431 cont_save_thread(rb_context_t *cont, rb_thread_t *th)
00432 {
00433
00434 cont->saved_thread = *th;
00435
00436
00437 cont->saved_thread.machine.stack_start = 0;
00438 cont->saved_thread.machine.stack_end = 0;
00439 #ifdef __ia64
00440 cont->saved_thread.machine.register_stack_start = 0;
00441 cont->saved_thread.machine.register_stack_end = 0;
00442 #endif
00443 }
00444
00445 static void
00446 cont_init(rb_context_t *cont, rb_thread_t *th)
00447 {
00448
00449 cont_save_thread(cont, th);
00450 cont->saved_thread.local_storage = 0;
00451 }
00452
00453 static rb_context_t *
00454 cont_new(VALUE klass)
00455 {
00456 rb_context_t *cont;
00457 volatile VALUE contval;
00458 rb_thread_t *th = GET_THREAD();
00459
00460 THREAD_MUST_BE_RUNNING(th);
00461 contval = TypedData_Make_Struct(klass, rb_context_t, &cont_data_type, cont);
00462 cont->self = contval;
00463 cont_init(cont, th);
00464 return cont;
00465 }
00466
00467 static VALUE
00468 cont_capture(volatile int *stat)
00469 {
00470 rb_context_t *cont;
00471 rb_thread_t *th = GET_THREAD(), *sth;
00472 volatile VALUE contval;
00473
00474 THREAD_MUST_BE_RUNNING(th);
00475 rb_vm_stack_to_heap(th);
00476 cont = cont_new(rb_cContinuation);
00477 contval = cont->self;
00478 sth = &cont->saved_thread;
00479
00480 #ifdef CAPTURE_JUST_VALID_VM_STACK
00481 cont->vm_stack_slen = th->cfp->sp + th->mark_stack_len - th->stack;
00482 cont->vm_stack_clen = th->stack + th->stack_size - (VALUE*)th->cfp;
00483 cont->vm_stack = ALLOC_N(VALUE, cont->vm_stack_slen + cont->vm_stack_clen);
00484 MEMCPY(cont->vm_stack, th->stack, VALUE, cont->vm_stack_slen);
00485 MEMCPY(cont->vm_stack + cont->vm_stack_slen, (VALUE*)th->cfp, VALUE, cont->vm_stack_clen);
00486 #else
00487 cont->vm_stack = ALLOC_N(VALUE, th->stack_size);
00488 MEMCPY(cont->vm_stack, th->stack, VALUE, th->stack_size);
00489 #endif
00490 sth->stack = 0;
00491
00492 cont_save_machine_stack(th, cont);
00493
00494
00495 {
00496 rb_ensure_list_t *p;
00497 int size = 0;
00498 rb_ensure_entry_t *entry;
00499 for (p=th->ensure_list; p; p=p->next)
00500 size++;
00501 entry = cont->ensure_array = ALLOC_N(rb_ensure_entry_t,size+1);
00502 for (p=th->ensure_list; p; p=p->next) {
00503 if (!p->entry.marker)
00504 p->entry.marker = rb_ary_tmp_new(0);
00505 *entry++ = p->entry;
00506 }
00507 entry->marker = 0;
00508 }
00509
00510 if (ruby_setjmp(cont->jmpbuf)) {
00511 volatile VALUE value;
00512
00513 value = cont->value;
00514 if (cont->argc == -1) rb_exc_raise(value);
00515 cont->value = Qnil;
00516 *stat = 1;
00517 return value;
00518 }
00519 else {
00520 *stat = 0;
00521 return contval;
00522 }
00523 }
00524
00525 static void
00526 cont_restore_thread(rb_context_t *cont)
00527 {
00528 rb_thread_t *th = GET_THREAD(), *sth = &cont->saved_thread;
00529
00530
00531 if (cont->type == CONTINUATION_CONTEXT) {
00532
00533 VALUE fib;
00534
00535 th->fiber = sth->fiber;
00536 fib = th->fiber ? th->fiber : th->root_fiber;
00537
00538 if (fib) {
00539 rb_fiber_t *fcont;
00540 GetFiberPtr(fib, fcont);
00541 th->stack_size = fcont->cont.saved_thread.stack_size;
00542 th->stack = fcont->cont.saved_thread.stack;
00543 }
00544 #ifdef CAPTURE_JUST_VALID_VM_STACK
00545 MEMCPY(th->stack, cont->vm_stack, VALUE, cont->vm_stack_slen);
00546 MEMCPY(th->stack + sth->stack_size - cont->vm_stack_clen,
00547 cont->vm_stack + cont->vm_stack_slen, VALUE, cont->vm_stack_clen);
00548 #else
00549 MEMCPY(th->stack, cont->vm_stack, VALUE, sth->stack_size);
00550 #endif
00551 }
00552 else {
00553
00554 th->stack = sth->stack;
00555 th->stack_size = sth->stack_size;
00556 th->local_storage = sth->local_storage;
00557 th->fiber = cont->self;
00558 }
00559
00560 th->cfp = sth->cfp;
00561 th->safe_level = sth->safe_level;
00562 th->raised_flag = sth->raised_flag;
00563 th->state = sth->state;
00564 th->status = sth->status;
00565 th->tag = sth->tag;
00566 th->protect_tag = sth->protect_tag;
00567 th->errinfo = sth->errinfo;
00568 th->first_proc = sth->first_proc;
00569 th->root_lep = sth->root_lep;
00570 th->root_svar = sth->root_svar;
00571 th->ensure_list = sth->ensure_list;
00572
00573 }
00574
00575 #if FIBER_USE_NATIVE
00576 #ifdef _WIN32
00577 static void
00578 fiber_set_stack_location(void)
00579 {
00580 rb_thread_t *th = GET_THREAD();
00581 VALUE *ptr;
00582
00583 SET_MACHINE_STACK_END(&ptr);
00584 th->machine.stack_start = (void*)(((VALUE)ptr & RB_PAGE_MASK) + STACK_UPPER((void *)&ptr, 0, RB_PAGE_SIZE));
00585 }
00586
00587 static VOID CALLBACK
00588 fiber_entry(void *arg)
00589 {
00590 fiber_set_stack_location();
00591 rb_fiber_start();
00592 }
00593 #else
00594
00595
00596
00597
00598
00599
00600 #if defined(MAP_STACK) && !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__)
00601 #define FIBER_STACK_FLAGS (MAP_PRIVATE | MAP_ANON | MAP_STACK)
00602 #else
00603 #define FIBER_STACK_FLAGS (MAP_PRIVATE | MAP_ANON)
00604 #endif
00605
00606 static char*
00607 fiber_machine_stack_alloc(size_t size)
00608 {
00609 char *ptr;
00610
00611 if (machine_stack_cache_index > 0) {
00612 if (machine_stack_cache[machine_stack_cache_index - 1].size == (size / sizeof(VALUE))) {
00613 ptr = machine_stack_cache[machine_stack_cache_index - 1].ptr;
00614 machine_stack_cache_index--;
00615 machine_stack_cache[machine_stack_cache_index].ptr = NULL;
00616 machine_stack_cache[machine_stack_cache_index].size = 0;
00617 }
00618 else{
00619
00620 rb_bug("machine_stack_cache size is not canonicalized");
00621 }
00622 }
00623 else {
00624 void *page;
00625 STACK_GROW_DIR_DETECTION;
00626
00627 errno = 0;
00628 ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, FIBER_STACK_FLAGS, -1, 0);
00629 if (ptr == MAP_FAILED) {
00630 rb_raise(rb_eFiberError, "can't alloc machine stack to fiber: %s", strerror(errno));
00631 }
00632
00633
00634 page = ptr + STACK_DIR_UPPER(size - RB_PAGE_SIZE, 0);
00635 if (mprotect(page, RB_PAGE_SIZE, PROT_NONE) < 0) {
00636 rb_raise(rb_eFiberError, "mprotect failed");
00637 }
00638 }
00639
00640 return ptr;
00641 }
00642 #endif
00643
00644 static void
00645 fiber_initialize_machine_stack_context(rb_fiber_t *fib, size_t size)
00646 {
00647 rb_thread_t *sth = &fib->cont.saved_thread;
00648
00649 #ifdef _WIN32
00650 fib->fib_handle = CreateFiberEx(size - 1, size, 0, fiber_entry, NULL);
00651 if (!fib->fib_handle) {
00652
00653 rb_gc();
00654 fib->fib_handle = CreateFiberEx(size - 1, size, 0, fiber_entry, NULL);
00655 if (!fib->fib_handle) {
00656 rb_raise(rb_eFiberError, "can't create fiber");
00657 }
00658 }
00659 sth->machine.stack_maxsize = size;
00660 #else
00661 ucontext_t *context = &fib->context;
00662 char *ptr;
00663 STACK_GROW_DIR_DETECTION;
00664
00665 getcontext(context);
00666 ptr = fiber_machine_stack_alloc(size);
00667 context->uc_link = NULL;
00668 context->uc_stack.ss_sp = ptr;
00669 context->uc_stack.ss_size = size;
00670 makecontext(context, rb_fiber_start, 0);
00671 sth->machine.stack_start = (VALUE*)(ptr + STACK_DIR_UPPER(0, size));
00672 sth->machine.stack_maxsize = size - RB_PAGE_SIZE;
00673 #endif
00674 #ifdef __ia64
00675 sth->machine.register_stack_maxsize = sth->machine.stack_maxsize;
00676 #endif
00677 }
00678
00679 NOINLINE(static void fiber_setcontext(rb_fiber_t *newfib, rb_fiber_t *oldfib));
00680
00681 static void
00682 fiber_setcontext(rb_fiber_t *newfib, rb_fiber_t *oldfib)
00683 {
00684 rb_thread_t *th = GET_THREAD(), *sth = &newfib->cont.saved_thread;
00685
00686 if (newfib->status != RUNNING) {
00687 fiber_initialize_machine_stack_context(newfib, th->vm->default_params.fiber_machine_stack_size);
00688 }
00689
00690
00691 cont_restore_thread(&newfib->cont);
00692 th->machine.stack_maxsize = sth->machine.stack_maxsize;
00693 if (sth->machine.stack_end && (newfib != oldfib)) {
00694 rb_bug("fiber_setcontext: sth->machine.stack_end has non zero value");
00695 }
00696
00697
00698 if (oldfib->status != TERMINATED) {
00699 STACK_GROW_DIR_DETECTION;
00700 SET_MACHINE_STACK_END(&th->machine.stack_end);
00701 if (STACK_DIR_UPPER(0, 1)) {
00702 oldfib->cont.machine.stack_size = th->machine.stack_start - th->machine.stack_end;
00703 oldfib->cont.machine.stack = th->machine.stack_end;
00704 }
00705 else {
00706 oldfib->cont.machine.stack_size = th->machine.stack_end - th->machine.stack_start;
00707 oldfib->cont.machine.stack = th->machine.stack_start;
00708 }
00709 }
00710
00711 oldfib->cont.saved_thread.machine.stack_start = th->machine.stack_start;
00712 th->machine.stack_start = sth->machine.stack_start;
00713
00714 oldfib->cont.saved_thread.machine.stack_end = 0;
00715 #ifndef _WIN32
00716 if (!newfib->context.uc_stack.ss_sp && th->root_fiber != newfib->cont.self) {
00717 rb_bug("non_root_fiber->context.uc_stac.ss_sp should not be NULL");
00718 }
00719 #endif
00720
00721
00722 #ifdef _WIN32
00723 SwitchToFiber(newfib->fib_handle);
00724 #else
00725 swapcontext(&oldfib->context, &newfib->context);
00726 #endif
00727 }
00728 #endif
00729
00730 NOINLINE(NORETURN(static void cont_restore_1(rb_context_t *)));
00731
00732 static void
00733 cont_restore_1(rb_context_t *cont)
00734 {
00735 cont_restore_thread(cont);
00736
00737
00738 #ifdef _M_AMD64
00739 {
00740
00741 jmp_buf buf;
00742 setjmp(buf);
00743 ((_JUMP_BUFFER*)(&cont->jmpbuf))->Frame =
00744 ((_JUMP_BUFFER*)(&buf))->Frame;
00745 }
00746 #endif
00747 if (cont->machine.stack_src) {
00748 FLUSH_REGISTER_WINDOWS;
00749 MEMCPY(cont->machine.stack_src, cont->machine.stack,
00750 VALUE, cont->machine.stack_size);
00751 }
00752
00753 #ifdef __ia64
00754 if (cont->machine.register_stack_src) {
00755 MEMCPY(cont->machine.register_stack_src, cont->machine.register_stack,
00756 VALUE, cont->machine.register_stack_size);
00757 }
00758 #endif
00759
00760 ruby_longjmp(cont->jmpbuf, 1);
00761 }
00762
00763 NORETURN(NOINLINE(static void cont_restore_0(rb_context_t *, VALUE *)));
00764
00765 #ifdef __ia64
00766 #define C(a) rse_##a##0, rse_##a##1, rse_##a##2, rse_##a##3, rse_##a##4
00767 #define E(a) rse_##a##0= rse_##a##1= rse_##a##2= rse_##a##3= rse_##a##4
00768 static volatile int C(a), C(b), C(c), C(d), C(e);
00769 static volatile int C(f), C(g), C(h), C(i), C(j);
00770 static volatile int C(k), C(l), C(m), C(n), C(o);
00771 static volatile int C(p), C(q), C(r), C(s), C(t);
00772 #if 0
00773 {}
00774 #endif
00775 int rb_dummy_false = 0;
00776 NORETURN(NOINLINE(static void register_stack_extend(rb_context_t *, VALUE *, VALUE *)));
00777 static void
00778 register_stack_extend(rb_context_t *cont, VALUE *vp, VALUE *curr_bsp)
00779 {
00780 if (rb_dummy_false) {
00781
00782 E(a) = E(b) = E(c) = E(d) = E(e) =
00783 E(f) = E(g) = E(h) = E(i) = E(j) =
00784 E(k) = E(l) = E(m) = E(n) = E(o) =
00785 E(p) = E(q) = E(r) = E(s) = E(t) = 0;
00786 E(a) = E(b) = E(c) = E(d) = E(e) =
00787 E(f) = E(g) = E(h) = E(i) = E(j) =
00788 E(k) = E(l) = E(m) = E(n) = E(o) =
00789 E(p) = E(q) = E(r) = E(s) = E(t) = 0;
00790 }
00791 if (curr_bsp < cont->machine.register_stack_src+cont->machine.register_stack_size) {
00792 register_stack_extend(cont, vp, (VALUE*)rb_ia64_bsp());
00793 }
00794 cont_restore_0(cont, vp);
00795 }
00796 #undef C
00797 #undef E
00798 #endif
00799
00800 static void
00801 cont_restore_0(rb_context_t *cont, VALUE *addr_in_prev_frame)
00802 {
00803 if (cont->machine.stack_src) {
00804 #ifdef HAVE_ALLOCA
00805 #define STACK_PAD_SIZE 1
00806 #else
00807 #define STACK_PAD_SIZE 1024
00808 #endif
00809 VALUE space[STACK_PAD_SIZE];
00810
00811 #if !STACK_GROW_DIRECTION
00812 if (addr_in_prev_frame > &space[0]) {
00813
00814 #endif
00815 #if STACK_GROW_DIRECTION <= 0
00816 volatile VALUE *const end = cont->machine.stack_src;
00817 if (&space[0] > end) {
00818 # ifdef HAVE_ALLOCA
00819 volatile VALUE *sp = ALLOCA_N(VALUE, &space[0] - end);
00820 space[0] = *sp;
00821 # else
00822 cont_restore_0(cont, &space[0]);
00823 # endif
00824 }
00825 #endif
00826 #if !STACK_GROW_DIRECTION
00827 }
00828 else {
00829
00830 #endif
00831 #if STACK_GROW_DIRECTION >= 0
00832 volatile VALUE *const end = cont->machine.stack_src + cont->machine.stack_size;
00833 if (&space[STACK_PAD_SIZE] < end) {
00834 # ifdef HAVE_ALLOCA
00835 volatile VALUE *sp = ALLOCA_N(VALUE, end - &space[STACK_PAD_SIZE]);
00836 space[0] = *sp;
00837 # else
00838 cont_restore_0(cont, &space[STACK_PAD_SIZE-1]);
00839 # endif
00840 }
00841 #endif
00842 #if !STACK_GROW_DIRECTION
00843 }
00844 #endif
00845 }
00846 cont_restore_1(cont);
00847 }
00848 #ifdef __ia64
00849 #define cont_restore_0(cont, vp) register_stack_extend((cont), (vp), (VALUE*)rb_ia64_bsp())
00850 #endif
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917 static VALUE
00918 rb_callcc(VALUE self)
00919 {
00920 volatile int called;
00921 volatile VALUE val = cont_capture(&called);
00922
00923 if (called) {
00924 return val;
00925 }
00926 else {
00927 return rb_yield(val);
00928 }
00929 }
00930
00931 static VALUE
00932 make_passing_arg(int argc, VALUE *argv)
00933 {
00934 switch (argc) {
00935 case 0:
00936 return Qnil;
00937 case 1:
00938 return argv[0];
00939 default:
00940 return rb_ary_new4(argc, argv);
00941 }
00942 }
00943
00944
00945
00946 void
00947 ruby_register_rollback_func_for_ensure(VALUE (*ensure_func)(ANYARGS), VALUE (*rollback_func)(ANYARGS))
00948 {
00949 st_table **table_p = &GET_VM()->ensure_rollback_table;
00950 if (UNLIKELY(*table_p == NULL)) {
00951 *table_p = st_init_numtable();
00952 }
00953 st_insert(*table_p, (st_data_t)ensure_func, (st_data_t)rollback_func);
00954 }
00955
00956 static inline VALUE
00957 lookup_rollback_func(VALUE (*ensure_func)(ANYARGS))
00958 {
00959 st_table *table = GET_VM()->ensure_rollback_table;
00960 st_data_t val;
00961 if (table && st_lookup(table, (st_data_t)ensure_func, &val))
00962 return (VALUE) val;
00963 return Qundef;
00964 }
00965
00966
00967 static inline void
00968 rollback_ensure_stack(VALUE self,rb_ensure_list_t *current,rb_ensure_entry_t *target)
00969 {
00970 rb_ensure_list_t *p;
00971 rb_ensure_entry_t *entry;
00972 size_t i;
00973 size_t cur_size;
00974 size_t target_size;
00975 size_t base_point;
00976 VALUE (*func)(ANYARGS);
00977
00978 cur_size = 0;
00979 for (p=current; p; p=p->next)
00980 cur_size++;
00981 target_size = 0;
00982 for (entry=target; entry->marker; entry++)
00983 target_size++;
00984
00985
00986 p = current;
00987 base_point = cur_size;
00988 while (base_point) {
00989 if (target_size >= base_point &&
00990 p->entry.marker == target[target_size - base_point].marker)
00991 break;
00992 base_point --;
00993 p = p->next;
00994 }
00995
00996
00997 for (i=0; i < target_size - base_point; i++) {
00998 if (!lookup_rollback_func(target[i].e_proc)) {
00999 rb_raise(rb_eRuntimeError, "continuation called from out of critical rb_ensure scope");
01000 }
01001 }
01002
01003 while (cur_size > base_point) {
01004
01005 (*current->entry.e_proc)(current->entry.data2);
01006 current = current->next;
01007 cur_size--;
01008 }
01009
01010 while (i--) {
01011 func = (VALUE (*)(ANYARGS)) lookup_rollback_func(target[i].e_proc);
01012 if ((VALUE)func != Qundef) {
01013 (*func)(target[i].data2);
01014 }
01015 }
01016 }
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034 static VALUE
01035 rb_cont_call(int argc, VALUE *argv, VALUE contval)
01036 {
01037 rb_context_t *cont;
01038 rb_thread_t *th = GET_THREAD();
01039 GetContPtr(contval, cont);
01040
01041 if (cont->saved_thread.self != th->self) {
01042 rb_raise(rb_eRuntimeError, "continuation called across threads");
01043 }
01044 if (cont->saved_thread.protect_tag != th->protect_tag) {
01045 rb_raise(rb_eRuntimeError, "continuation called across stack rewinding barrier");
01046 }
01047 if (cont->saved_thread.fiber) {
01048 rb_fiber_t *fcont;
01049 GetFiberPtr(cont->saved_thread.fiber, fcont);
01050
01051 if (th->fiber != cont->saved_thread.fiber) {
01052 rb_raise(rb_eRuntimeError, "continuation called across fiber");
01053 }
01054 }
01055 rollback_ensure_stack(contval, th->ensure_list, cont->ensure_array);
01056
01057 cont->argc = argc;
01058 cont->value = make_passing_arg(argc, argv);
01059
01060
01061 th->trace_arg = cont->saved_thread.trace_arg;
01062
01063 cont_restore_0(cont, &contval);
01064 return Qnil;
01065 }
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133 static const rb_data_type_t fiber_data_type = {
01134 "fiber",
01135 {fiber_mark, fiber_free, fiber_memsize,},
01136 NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
01137 };
01138
01139 static VALUE
01140 fiber_alloc(VALUE klass)
01141 {
01142 return TypedData_Wrap_Struct(klass, &fiber_data_type, 0);
01143 }
01144
01145 static rb_fiber_t*
01146 fiber_t_alloc(VALUE fibval)
01147 {
01148 rb_fiber_t *fib;
01149 rb_thread_t *th = GET_THREAD();
01150
01151 if (DATA_PTR(fibval) != 0) {
01152 rb_raise(rb_eRuntimeError, "cannot initialize twice");
01153 }
01154
01155 THREAD_MUST_BE_RUNNING(th);
01156 fib = ALLOC(rb_fiber_t);
01157 memset(fib, 0, sizeof(rb_fiber_t));
01158 fib->cont.self = fibval;
01159 fib->cont.type = FIBER_CONTEXT;
01160 cont_init(&fib->cont, th);
01161 fib->prev = Qnil;
01162 fib->status = CREATED;
01163
01164 DATA_PTR(fibval) = fib;
01165
01166 return fib;
01167 }
01168
01169 static VALUE
01170 fiber_init(VALUE fibval, VALUE proc)
01171 {
01172 rb_fiber_t *fib = fiber_t_alloc(fibval);
01173 rb_context_t *cont = &fib->cont;
01174 rb_thread_t *th = &cont->saved_thread;
01175
01176
01177 cont->vm_stack = 0;
01178
01179 th->stack = 0;
01180 th->stack_size = 0;
01181
01182 fiber_link_join(fib);
01183
01184 th->stack_size = th->vm->default_params.fiber_vm_stack_size / sizeof(VALUE);
01185 th->stack = ALLOC_N(VALUE, th->stack_size);
01186
01187 th->cfp = (void *)(th->stack + th->stack_size);
01188 th->cfp--;
01189 th->cfp->pc = 0;
01190 th->cfp->sp = th->stack + 1;
01191 #if VM_DEBUG_BP_CHECK
01192 th->cfp->bp_check = 0;
01193 #endif
01194 th->cfp->ep = th->stack;
01195 *th->cfp->ep = VM_ENVVAL_BLOCK_PTR(0);
01196 th->cfp->self = Qnil;
01197 th->cfp->klass = Qnil;
01198 th->cfp->flag = 0;
01199 th->cfp->iseq = 0;
01200 th->cfp->proc = 0;
01201 th->cfp->block_iseq = 0;
01202 th->cfp->me = 0;
01203 th->tag = 0;
01204 th->local_storage = st_init_numtable();
01205
01206 th->first_proc = proc;
01207
01208 #if !FIBER_USE_NATIVE
01209 MEMCPY(&cont->jmpbuf, &th->root_jmpbuf, rb_jmpbuf_t, 1);
01210 #endif
01211
01212 return fibval;
01213 }
01214
01215
01216 static VALUE
01217 rb_fiber_init(VALUE fibval)
01218 {
01219 return fiber_init(fibval, rb_block_proc());
01220 }
01221
01222 VALUE
01223 rb_fiber_new(VALUE (*func)(ANYARGS), VALUE obj)
01224 {
01225 return fiber_init(fiber_alloc(rb_cFiber), rb_proc_new(func, obj));
01226 }
01227
01228 static VALUE
01229 return_fiber(void)
01230 {
01231 rb_fiber_t *fib;
01232 VALUE curr = rb_fiber_current();
01233 VALUE prev;
01234 GetFiberPtr(curr, fib);
01235
01236 prev = fib->prev;
01237 if (NIL_P(prev)) {
01238 const VALUE root_fiber = GET_THREAD()->root_fiber;
01239
01240 if (root_fiber == curr) {
01241 rb_raise(rb_eFiberError, "can't yield from root fiber");
01242 }
01243 return root_fiber;
01244 }
01245 else {
01246 fib->prev = Qnil;
01247 return prev;
01248 }
01249 }
01250
01251 VALUE rb_fiber_transfer(VALUE fib, int argc, VALUE *argv);
01252
01253 static void
01254 rb_fiber_terminate(rb_fiber_t *fib)
01255 {
01256 VALUE value = fib->cont.value;
01257 fib->status = TERMINATED;
01258 #if FIBER_USE_NATIVE && !defined(_WIN32)
01259
01260 terminated_machine_stack.ptr = fib->context.uc_stack.ss_sp;
01261 terminated_machine_stack.size = fib->context.uc_stack.ss_size / sizeof(VALUE);
01262 fib->context.uc_stack.ss_sp = NULL;
01263 fib->cont.machine.stack = NULL;
01264 fib->cont.machine.stack_size = 0;
01265 #endif
01266 rb_fiber_transfer(return_fiber(), 1, &value);
01267 }
01268
01269 void
01270 rb_fiber_start(void)
01271 {
01272 rb_thread_t *th = GET_THREAD();
01273 rb_fiber_t *fib;
01274 rb_context_t *cont;
01275 rb_proc_t *proc;
01276 int state;
01277
01278 GetFiberPtr(th->fiber, fib);
01279 cont = &fib->cont;
01280
01281 TH_PUSH_TAG(th);
01282 if ((state = EXEC_TAG()) == 0) {
01283 int argc;
01284 const VALUE *argv, args = cont->value;
01285 GetProcPtr(cont->saved_thread.first_proc, proc);
01286 argv = (argc = cont->argc) > 1 ? RARRAY_CONST_PTR(args) : &args;
01287 cont->value = Qnil;
01288 th->errinfo = Qnil;
01289 th->root_lep = rb_vm_ep_local_ep(proc->block.ep);
01290 th->root_svar = Qnil;
01291
01292 fib->status = RUNNING;
01293 cont->value = rb_vm_invoke_proc(th, proc, argc, argv, 0);
01294 }
01295 TH_POP_TAG();
01296
01297 if (state) {
01298 if (state == TAG_RAISE || state == TAG_FATAL) {
01299 rb_threadptr_pending_interrupt_enque(th, th->errinfo);
01300 }
01301 else {
01302 VALUE err = rb_vm_make_jump_tag_but_local_jump(state, th->errinfo);
01303 if (!NIL_P(err))
01304 rb_threadptr_pending_interrupt_enque(th, err);
01305 }
01306 RUBY_VM_SET_INTERRUPT(th);
01307 }
01308
01309 rb_fiber_terminate(fib);
01310 rb_bug("rb_fiber_start: unreachable");
01311 }
01312
01313 static rb_fiber_t *
01314 root_fiber_alloc(rb_thread_t *th)
01315 {
01316 rb_fiber_t *fib;
01317
01318 fib = fiber_t_alloc(fiber_alloc(rb_cFiber));
01319 fib->cont.type = ROOT_FIBER_CONTEXT;
01320 #if FIBER_USE_NATIVE
01321 #ifdef _WIN32
01322 fib->fib_handle = ConvertThreadToFiber(0);
01323 #endif
01324 #endif
01325 fib->status = RUNNING;
01326 fib->prev_fiber = fib->next_fiber = fib;
01327
01328 return fib;
01329 }
01330
01331 VALUE
01332 rb_fiber_current(void)
01333 {
01334 rb_thread_t *th = GET_THREAD();
01335 if (th->fiber == 0) {
01336
01337 rb_fiber_t *fib = root_fiber_alloc(th);
01338 th->root_fiber = th->fiber = fib->cont.self;
01339 }
01340 return th->fiber;
01341 }
01342
01343 static VALUE
01344 fiber_store(rb_fiber_t *next_fib)
01345 {
01346 rb_thread_t *th = GET_THREAD();
01347 rb_fiber_t *fib;
01348
01349 if (th->fiber) {
01350 GetFiberPtr(th->fiber, fib);
01351 cont_save_thread(&fib->cont, th);
01352 }
01353 else {
01354
01355 fib = root_fiber_alloc(th);
01356 th->root_fiber = th->fiber = fib->cont.self;
01357 }
01358
01359 #if !FIBER_USE_NATIVE
01360 cont_save_machine_stack(th, &fib->cont);
01361 #endif
01362
01363 if (FIBER_USE_NATIVE || ruby_setjmp(fib->cont.jmpbuf)) {
01364 #if FIBER_USE_NATIVE
01365 fiber_setcontext(next_fib, fib);
01366 #ifndef _WIN32
01367 if (terminated_machine_stack.ptr) {
01368 if (machine_stack_cache_index < MAX_MACHINE_STACK_CACHE) {
01369 machine_stack_cache[machine_stack_cache_index].ptr = terminated_machine_stack.ptr;
01370 machine_stack_cache[machine_stack_cache_index].size = terminated_machine_stack.size;
01371 machine_stack_cache_index++;
01372 }
01373 else {
01374 if (terminated_machine_stack.ptr != fib->cont.machine.stack) {
01375 munmap((void*)terminated_machine_stack.ptr, terminated_machine_stack.size * sizeof(VALUE));
01376 }
01377 else {
01378 rb_bug("terminated fiber resumed");
01379 }
01380 }
01381 terminated_machine_stack.ptr = NULL;
01382 terminated_machine_stack.size = 0;
01383 }
01384 #endif
01385 #endif
01386
01387 GetFiberPtr(th->fiber, fib);
01388 if (fib->cont.argc == -1) rb_exc_raise(fib->cont.value);
01389 return fib->cont.value;
01390 }
01391 #if !FIBER_USE_NATIVE
01392 else {
01393 return Qundef;
01394 }
01395 #endif
01396 }
01397
01398 static inline VALUE
01399 fiber_switch(VALUE fibval, int argc, VALUE *argv, int is_resume)
01400 {
01401 VALUE value;
01402 rb_fiber_t *fib;
01403 rb_context_t *cont;
01404 rb_thread_t *th = GET_THREAD();
01405
01406 GetFiberPtr(fibval, fib);
01407 cont = &fib->cont;
01408
01409 if (th->fiber == fibval) {
01410
01411
01412
01413 return make_passing_arg(argc, argv);
01414 }
01415
01416 if (cont->saved_thread.self != th->self) {
01417 rb_raise(rb_eFiberError, "fiber called across threads");
01418 }
01419 else if (cont->saved_thread.protect_tag != th->protect_tag) {
01420 rb_raise(rb_eFiberError, "fiber called across stack rewinding barrier");
01421 }
01422 else if (fib->status == TERMINATED) {
01423 value = rb_exc_new2(rb_eFiberError, "dead fiber called");
01424 if (th->fiber != fibval) {
01425 GetFiberPtr(th->fiber, fib);
01426 if (fib->status != TERMINATED) rb_exc_raise(value);
01427 fibval = th->root_fiber;
01428 }
01429 else {
01430 fibval = fib->prev;
01431 if (NIL_P(fibval)) fibval = th->root_fiber;
01432 }
01433 GetFiberPtr(fibval, fib);
01434 cont = &fib->cont;
01435 cont->argc = -1;
01436 cont->value = value;
01437 #if FIBER_USE_NATIVE
01438 {
01439 VALUE oldfibval;
01440 rb_fiber_t *oldfib;
01441 oldfibval = rb_fiber_current();
01442 GetFiberPtr(oldfibval, oldfib);
01443 fiber_setcontext(fib, oldfib);
01444 }
01445 #else
01446 cont_restore_0(cont, &value);
01447 #endif
01448 }
01449
01450 if (is_resume) {
01451 fib->prev = rb_fiber_current();
01452 }
01453 else {
01454
01455 th->trace_arg = cont->saved_thread.trace_arg;
01456 }
01457
01458 cont->argc = argc;
01459 cont->value = make_passing_arg(argc, argv);
01460
01461 value = fiber_store(fib);
01462 #if !FIBER_USE_NATIVE
01463 if (value == Qundef) {
01464 cont_restore_0(cont, &value);
01465 rb_bug("rb_fiber_resume: unreachable");
01466 }
01467 #endif
01468 RUBY_VM_CHECK_INTS(th);
01469
01470 return value;
01471 }
01472
01473 VALUE
01474 rb_fiber_transfer(VALUE fib, int argc, VALUE *argv)
01475 {
01476 return fiber_switch(fib, argc, argv, 0);
01477 }
01478
01479 VALUE
01480 rb_fiber_resume(VALUE fibval, int argc, VALUE *argv)
01481 {
01482 rb_fiber_t *fib;
01483 GetFiberPtr(fibval, fib);
01484
01485 if (fib->prev != Qnil || fib->cont.type == ROOT_FIBER_CONTEXT) {
01486 rb_raise(rb_eFiberError, "double resume");
01487 }
01488 if (fib->transfered != 0) {
01489 rb_raise(rb_eFiberError, "cannot resume transferred Fiber");
01490 }
01491
01492 return fiber_switch(fibval, argc, argv, 1);
01493 }
01494
01495 VALUE
01496 rb_fiber_yield(int argc, VALUE *argv)
01497 {
01498 return rb_fiber_transfer(return_fiber(), argc, argv);
01499 }
01500
01501 void
01502 rb_fiber_reset_root_local_storage(VALUE thval)
01503 {
01504 rb_thread_t *th;
01505 rb_fiber_t *fib;
01506
01507 GetThreadPtr(thval, th);
01508 if (th->root_fiber && th->root_fiber != th->fiber) {
01509 GetFiberPtr(th->root_fiber, fib);
01510 th->local_storage = fib->cont.saved_thread.local_storage;
01511 }
01512 }
01513
01514
01515
01516
01517
01518
01519
01520
01521
01522
01523 VALUE
01524 rb_fiber_alive_p(VALUE fibval)
01525 {
01526 rb_fiber_t *fib;
01527 GetFiberPtr(fibval, fib);
01528 return fib->status != TERMINATED ? Qtrue : Qfalse;
01529 }
01530
01531
01532
01533
01534
01535
01536
01537
01538
01539
01540
01541
01542
01543
01544
01545
01546 static VALUE
01547 rb_fiber_m_resume(int argc, VALUE *argv, VALUE fib)
01548 {
01549 return rb_fiber_resume(fib, argc, argv);
01550 }
01551
01552
01553
01554
01555
01556
01557
01558
01559
01560
01561
01562
01563
01564
01565
01566
01567
01568
01569
01570
01571
01572
01573
01574
01575
01576
01577
01578
01579
01580
01581
01582
01583
01584
01585
01586
01587
01588
01589
01590
01591
01592
01593
01594
01595
01596
01597 static VALUE
01598 rb_fiber_m_transfer(int argc, VALUE *argv, VALUE fibval)
01599 {
01600 rb_fiber_t *fib;
01601 GetFiberPtr(fibval, fib);
01602 fib->transfered = 1;
01603 return rb_fiber_transfer(fibval, argc, argv);
01604 }
01605
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615
01616 static VALUE
01617 rb_fiber_s_yield(int argc, VALUE *argv, VALUE klass)
01618 {
01619 return rb_fiber_yield(argc, argv);
01620 }
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630 static VALUE
01631 rb_fiber_s_current(VALUE klass)
01632 {
01633 return rb_fiber_current();
01634 }
01635
01636
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651 void
01652 Init_Cont(void)
01653 {
01654 #if FIBER_USE_NATIVE
01655 rb_thread_t *th = GET_THREAD();
01656
01657 #ifdef _WIN32
01658 SYSTEM_INFO info;
01659 GetSystemInfo(&info);
01660 pagesize = info.dwPageSize;
01661 #else
01662 pagesize = sysconf(_SC_PAGESIZE);
01663 #endif
01664 SET_MACHINE_STACK_END(&th->machine.stack_end);
01665 #endif
01666
01667 rb_cFiber = rb_define_class("Fiber", rb_cObject);
01668 rb_define_alloc_func(rb_cFiber, fiber_alloc);
01669 rb_eFiberError = rb_define_class("FiberError", rb_eStandardError);
01670 rb_define_singleton_method(rb_cFiber, "yield", rb_fiber_s_yield, -1);
01671 rb_define_method(rb_cFiber, "initialize", rb_fiber_init, 0);
01672 rb_define_method(rb_cFiber, "resume", rb_fiber_m_resume, -1);
01673 }
01674
01675 RUBY_SYMBOL_EXPORT_BEGIN
01676
01677 void
01678 ruby_Init_Continuation_body(void)
01679 {
01680 rb_cContinuation = rb_define_class("Continuation", rb_cObject);
01681 rb_undef_alloc_func(rb_cContinuation);
01682 rb_undef_method(CLASS_OF(rb_cContinuation), "new");
01683 rb_define_method(rb_cContinuation, "call", rb_cont_call, -1);
01684 rb_define_method(rb_cContinuation, "[]", rb_cont_call, -1);
01685 rb_define_global_function("callcc", rb_callcc, 0);
01686 }
01687
01688 void
01689 ruby_Init_Fiber_as_Coroutine(void)
01690 {
01691 rb_define_method(rb_cFiber, "transfer", rb_fiber_m_transfer, -1);
01692 rb_define_method(rb_cFiber, "alive?", rb_fiber_alive_p, 0);
01693 rb_define_singleton_method(rb_cFiber, "current", rb_fiber_s_current, 0);
01694 }
01695
01696 RUBY_SYMBOL_EXPORT_END
01697