2007-05-23 18:52:19 -04:00
/**********************************************************************
2009-02-22 09:23:33 -05:00
cont . c -
2007-05-23 18:52:19 -04:00
$ Author $
created at : Thu May 23 09 : 03 : 43 2007
Copyright ( C ) 2007 Koichi Sasada
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
* internal.h: declare internal functions here.
* node.h: declare NODE dependent internal functions here.
* iseq.h: declare rb_iseq_t dependent internal functions here.
* vm_core.h: declare rb_thread_t dependent internal functions here.
* bignum.c, class.c, compile.c, complex.c, cont.c, dir.c, encoding.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c, io.c,
iseq.c, load.c, marshal.c, math.c, numeric.c, object.c, parse.y,
proc.c, process.c, range.c, rational.c, re.c, ruby.c, string.c,
thread.c, time.c, transcode.c, variable.c, vm.c,
tool/compile_prelude.rb: don't declare internal functions declared
in above headers. include above headers if required.
Note that rb_thread_mark() was declared as
void rb_thread_mark(rb_thread_t *th) in cont.c but defined as
void rb_thread_mark(void *ptr) in vm.c. Now it is declared as
the later in internal.h.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@32156 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2011-06-17 18:43:38 -04:00
# include "internal.h"
* blockinlining.c: remove "yarv" prefix.
* array.c, numeric.c: ditto.
* insnhelper.ci, insns.def, vm_evalbody.ci: ditto.
* yarvcore.c: removed.
* yarvcore.h: renamed to core.h.
* cont.c, debug.c, error.c, process.c, signal.c : ditto.
* ext/probeprofiler/probeprofiler.c: ditto.
* id.c, id.h: added.
* inits.c: ditto.
* compile.c: rename internal functions.
* compile.h: fix debug flag.
* eval.c, object.c, vm.c: remove ruby_top_self.
use rb_vm_top_self() instead.
* eval_intern.h, eval_load: ditto.
* gc.c: rename yarv_machine_stack_mark() to
rb_gc_mark_machine_stack().
* insnhelper.h: remove unused macros.
* iseq.c: add iseq_compile() to create iseq object
from source string.
* proc.c: rename a internal function.
* template/insns.inc.tmpl: remove YARV prefix.
* thread.c:
* vm.c (rb_iseq_eval): added.
* vm.c: move some functions from yarvcore.c.
* vm_dump.c: fix to remove compiler warning.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12741 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-07-12 00:25:46 -04:00
# include "vm_core.h"
2007-05-23 18:52:19 -04:00
# include "gc.h"
# include "eval_intern.h"
mjit.c: merge MJIT infrastructure
that allows to JIT-compile Ruby methods by generating C code and
using C compiler. See the first comment of mjit.c to know what this
file does.
mjit.c is authored by Vladimir Makarov <vmakarov@redhat.com>.
After he invented great method JIT infrastructure for MRI as MJIT,
Lars Kanis <lars@greiz-reinsdorf.de> sent the patch to support MinGW
in MJIT. In addition to merging it, I ported pthread to Windows native
threads. Now this MJIT infrastructure can be compiled on Visual Studio.
This commit simplifies mjit.c to decrease code at initial merge. For
example, this commit does not provide multiple JIT threads support.
We can resurrect them later if we really want them, but I wanted to minimize
diff to make it easier to review this patch.
`/tmp/_mjitXXX` file is renamed to `/tmp/_ruby_mjitXXX` because non-Ruby
developers may not know the name "mjit" and the file name should make
sure it's from Ruby and not from some harmful programs. TODO: it may be
better to store this to some temporary directory which Ruby is already using
by Tempfile, if it's not bad for performance.
mjit.h: New. It has `mjit_exec` interface similar to `vm_exec`, which is
for triggering MJIT. This drops interface for AOT compared to the original
MJIT.
Makefile.in: define macros to let MJIT know the path of MJIT header.
Probably we can refactor this to reduce the number of macros (TODO).
win32/Makefile.sub: ditto.
common.mk: compile mjit.o and mjit_compile.o. Unlike original MJIT, this
commit separates MJIT infrastructure and JIT compiler code as independent
object files. As initial patch is NOT going to have ultra-fast JIT compiler,
it's likely to replace JIT compiler, e.g. original MJIT's compiler or some
future JIT impelementations which are not public now.
inits.c: define MJIT module. This is added because `MJIT.enabled?` was
necessary for testing.
test/lib/zombie_hunter.rb: skip if `MJIT.enabled?`. Obviously this
wouldn't work with current code when JIT is enabled.
test/ruby/test_io.rb: skip this too. This would make no sense with MJIT.
ruby.c: define MJIT CLI options. As major difference from original MJIT,
"-j:l"/"--jit:llvm" are renamed to "--jit-cc" because I want to support
not only gcc/clang but also cl.exe (Visual Studio) in the future. But it
takes only "--jit-cc=gcc", "--jit-cc=clang" for now. And only long "--jit"
options are allowed since some Ruby committers preferred it at Ruby
developers Meeting on January, and some of options are renamed.
This file also triggers to initialize MJIT thread and variables.
eval.c: finalize MJIT worker thread and variables.
test/ruby/test_rubyoptions.rb: fix number of CLI options for --jit.
thread_pthread.c: change for pthread abstraction in MJIT. Prefix rb_ for
functions which are used by other files.
thread_win32.c: ditto, for Windows. Those pthread porting is one of major
works that YARV-MJIT created, which is my fork of MJIT, in Feature 14235.
thread.c: follow rb_ prefix changes
vm.c: trigger MJIT call on VM invocation. Also trigger `mjit_mark` to avoid
SEGV by race between JIT and GC of ISeq. The improvement was provided by
wanabe <s.wanabe@gmail.com>.
In JIT compiler I created and am going to add in my next commit, I found
that having `mjit_exec` after `vm_loop_start:` is harmful because the
JIT-ed function doesn't proceed other ISeqs on RESTORE_REGS of leave insn.
Executing non-FINISH frame is unexpected for my JIT compiler and
`exception_handler` triggers executions of such ISeqs. So `mjit_exec`
here should be executed only when it directly comes from `vm_exec` call.
`RubyVM::MJIT` module and `.enabled?` method is added so that we can skip
some tests which don't expect JIT threads or compiler file descriptors.
vm_insnhelper.h: trigger MJIT on method calls during VM execution.
vm_core.h: add fields required for mjit.c. `bp` must be `cfp[6]` because
rb_control_frame_struct is likely to be casted to another struct. The
last position is the safest place to add the new field.
vm_insnhelper.c: save initial value of cfp->ep as cfp->bp. This is an
optimization which are done in both MJIT and YARV-MJIT. So this change
is added in this commit. Calculating bp from ep is a little heavy work,
so bp is kind of cache for it.
iseq.c: notify ISeq GC to MJIT. We should know which iseq in MJIT queue
is GCed to avoid SEGV. TODO: unload some GCed units in some safe way.
gc.c: add hooks so that MJIT can wait GC, and vice versa. Simultaneous
JIT and GC executions may cause SEGV and so we should synchronize them.
cont.c: save continuation information in MJIT worker. As MJIT shouldn't
unload JIT-ed code which is being used, MJIT wants to know full list of
saved execution contexts for continuation and detect ISeqs in use.
mjit_compile.c: added empty JIT compiler so that you can reuse this commit
to build your own JIT compiler. This commit tries to compile ISeqs but
all of them are considered as not supported in this commit. So you can't
use JIT compiler in this commit yet while we added --jit option now.
Patch author: Vladimir Makarov <vmakarov@redhat.com>.
Contributors:
Takashi Kokubun <takashikkbn@gmail.com>.
wanabe <s.wanabe@gmail.com>.
Lars Kanis <lars@greiz-reinsdorf.de>.
Part of Feature 12589 and 14235.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62189 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2018-02-04 01:58:09 -05:00
# include "mjit.h"
2007-05-23 18:52:19 -04:00
2019-06-28 21:07:07 -04:00
# include COROUTINE_H
2018-11-20 04:59:10 -05:00
2010-05-05 14:37:37 -04:00
# ifndef _WIN32
# include <unistd.h>
# include <sys/mman.h>
2010-07-27 20:38:21 -04:00
# endif
2019-06-01 01:48:25 -04:00
2019-06-01 20:49:58 -04:00
static const int DEBUG = 0 ;
2010-07-27 20:25:53 -04:00
# define RB_PAGE_SIZE (pagesize)
# define RB_PAGE_MASK (~(RB_PAGE_SIZE - 1))
2010-05-05 14:37:37 -04:00
static long pagesize ;
2019-06-01 20:49:58 -04:00
static const rb_data_type_t cont_data_type , fiber_data_type ;
static VALUE rb_cContinuation ;
static VALUE rb_cFiber ;
static VALUE rb_eFiberError ;
# ifdef RB_EXPERIMENTAL_FIBER_POOL
static VALUE rb_cFiberPool ;
# endif
2008-11-18 11:19:37 -05:00
# define CAPTURE_JUST_VALID_VM_STACK 1
2007-11-08 20:11:49 -05:00
enum context_type {
CONTINUATION_CONTEXT = 0 ,
2018-09-12 16:49:24 -04:00
FIBER_CONTEXT = 1
2007-11-08 20:11:49 -05:00
} ;
2017-08-21 20:41:24 -04:00
struct cont_saved_vm_stack {
VALUE * ptr ;
# ifdef CAPTURE_JUST_VALID_VM_STACK
2017-10-26 04:42:44 -04:00
size_t slen ; /* length of stack (head of ec->vm_stack) */
size_t clen ; /* length of control frames (tail of ec->vm_stack) */
2017-08-21 20:41:24 -04:00
# endif
} ;
2019-06-01 20:49:58 -04:00
struct fiber_pool ;
// Represents a single stack.
struct fiber_pool_stack {
// A pointer to the memory allocation (lowest address) for the stack.
void * base ;
// The current stack pointer, taking into account the direction of the stack.
void * current ;
// The size of the stack including any guard pages.
size_t size ;
// The available stack capacity w.r.t. the current stack offset.
size_t available ;
// The pool this stack is managed by.
struct fiber_pool * pool ;
} ;
// A singly linked list of vacant (unused) stacks.
// This structure is stored in the first page of a stack if it is not in use.
// @sa fiber_pool_vacancy_pointer
struct fiber_pool_vacancy {
// Details about the vacant stack:
struct fiber_pool_stack stack ;
// The next vacancy in the linked list.
struct fiber_pool_vacancy * next ;
} ;
// Manages singly linked list of mapped regions of memory which contains 1 more more stack:
//
// base = +-------------------------------+-----------------------+ +
// |VM Stack |VM Stack | | |
// | | | | |
// | | | | |
// +-------------------------------+ | |
// |Machine Stack |Machine Stack | | |
// | | | | |
// | | | | |
// | | | . . . . | | size
// | | | | |
// | | | | |
// | | | | |
// | | | | |
// | | | | |
// +-------------------------------+ | |
// |Guard Page |Guard Page | | |
// +-------------------------------+-----------------------+ v
//
// +------------------------------------------------------->
//
// count
//
struct fiber_pool_allocation {
// A pointer to the memory mapped region.
void * base ;
// The size of the individual stacks.
size_t size ;
// The number of stacks that were allocated.
size_t count ;
// The number of stacks used in this allocation.
// size_t used;
// The next allocation in the linked list.
struct fiber_pool_allocation * next ;
} ;
// A fiber pool manages vacant stacks to reduce the overhead of creating fibers.
struct fiber_pool {
// A singly-linked list of allocations which contain 1 or more stacks each.
struct fiber_pool_allocation * allocations ;
// Provides O(1) stack "allocation":
struct fiber_pool_vacancy * vacancies ;
// The size of the stack allocations including guard page.
size_t size ;
// The total number of stacks that have been allocated in this pool.
size_t count ;
// The number of stacks that have been used in this pool.
size_t used ;
// The amount to allocate for the vm_stack:
size_t vm_stack_size ;
} ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
typedef struct rb_context_struct {
2008-10-22 11:12:07 -04:00
enum context_type type ;
2008-11-30 22:00:48 -05:00
int argc ;
2014-08-14 20:25:34 -04:00
VALUE self ;
2007-06-02 03:48:29 -04:00
VALUE value ;
2017-08-21 20:41:24 -04:00
struct cont_saved_vm_stack saved_vm_stack ;
2014-01-28 01:09:58 -05:00
struct {
2019-06-01 01:48:25 -04:00
VALUE * stack ;
VALUE * stack_src ;
size_t stack_size ;
2014-01-28 01:09:58 -05:00
} machine ;
2017-09-10 15:00:08 -04:00
rb_execution_context_t saved_ec ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
rb_jmpbuf_t jmpbuf ;
2013-11-15 12:15:31 -05:00
rb_ensure_entry_t * ensure_array ;
mjit.c: merge MJIT infrastructure
that allows to JIT-compile Ruby methods by generating C code and
using C compiler. See the first comment of mjit.c to know what this
file does.
mjit.c is authored by Vladimir Makarov <vmakarov@redhat.com>.
After he invented great method JIT infrastructure for MRI as MJIT,
Lars Kanis <lars@greiz-reinsdorf.de> sent the patch to support MinGW
in MJIT. In addition to merging it, I ported pthread to Windows native
threads. Now this MJIT infrastructure can be compiled on Visual Studio.
This commit simplifies mjit.c to decrease code at initial merge. For
example, this commit does not provide multiple JIT threads support.
We can resurrect them later if we really want them, but I wanted to minimize
diff to make it easier to review this patch.
`/tmp/_mjitXXX` file is renamed to `/tmp/_ruby_mjitXXX` because non-Ruby
developers may not know the name "mjit" and the file name should make
sure it's from Ruby and not from some harmful programs. TODO: it may be
better to store this to some temporary directory which Ruby is already using
by Tempfile, if it's not bad for performance.
mjit.h: New. It has `mjit_exec` interface similar to `vm_exec`, which is
for triggering MJIT. This drops interface for AOT compared to the original
MJIT.
Makefile.in: define macros to let MJIT know the path of MJIT header.
Probably we can refactor this to reduce the number of macros (TODO).
win32/Makefile.sub: ditto.
common.mk: compile mjit.o and mjit_compile.o. Unlike original MJIT, this
commit separates MJIT infrastructure and JIT compiler code as independent
object files. As initial patch is NOT going to have ultra-fast JIT compiler,
it's likely to replace JIT compiler, e.g. original MJIT's compiler or some
future JIT impelementations which are not public now.
inits.c: define MJIT module. This is added because `MJIT.enabled?` was
necessary for testing.
test/lib/zombie_hunter.rb: skip if `MJIT.enabled?`. Obviously this
wouldn't work with current code when JIT is enabled.
test/ruby/test_io.rb: skip this too. This would make no sense with MJIT.
ruby.c: define MJIT CLI options. As major difference from original MJIT,
"-j:l"/"--jit:llvm" are renamed to "--jit-cc" because I want to support
not only gcc/clang but also cl.exe (Visual Studio) in the future. But it
takes only "--jit-cc=gcc", "--jit-cc=clang" for now. And only long "--jit"
options are allowed since some Ruby committers preferred it at Ruby
developers Meeting on January, and some of options are renamed.
This file also triggers to initialize MJIT thread and variables.
eval.c: finalize MJIT worker thread and variables.
test/ruby/test_rubyoptions.rb: fix number of CLI options for --jit.
thread_pthread.c: change for pthread abstraction in MJIT. Prefix rb_ for
functions which are used by other files.
thread_win32.c: ditto, for Windows. Those pthread porting is one of major
works that YARV-MJIT created, which is my fork of MJIT, in Feature 14235.
thread.c: follow rb_ prefix changes
vm.c: trigger MJIT call on VM invocation. Also trigger `mjit_mark` to avoid
SEGV by race between JIT and GC of ISeq. The improvement was provided by
wanabe <s.wanabe@gmail.com>.
In JIT compiler I created and am going to add in my next commit, I found
that having `mjit_exec` after `vm_loop_start:` is harmful because the
JIT-ed function doesn't proceed other ISeqs on RESTORE_REGS of leave insn.
Executing non-FINISH frame is unexpected for my JIT compiler and
`exception_handler` triggers executions of such ISeqs. So `mjit_exec`
here should be executed only when it directly comes from `vm_exec` call.
`RubyVM::MJIT` module and `.enabled?` method is added so that we can skip
some tests which don't expect JIT threads or compiler file descriptors.
vm_insnhelper.h: trigger MJIT on method calls during VM execution.
vm_core.h: add fields required for mjit.c. `bp` must be `cfp[6]` because
rb_control_frame_struct is likely to be casted to another struct. The
last position is the safest place to add the new field.
vm_insnhelper.c: save initial value of cfp->ep as cfp->bp. This is an
optimization which are done in both MJIT and YARV-MJIT. So this change
is added in this commit. Calculating bp from ep is a little heavy work,
so bp is kind of cache for it.
iseq.c: notify ISeq GC to MJIT. We should know which iseq in MJIT queue
is GCed to avoid SEGV. TODO: unload some GCed units in some safe way.
gc.c: add hooks so that MJIT can wait GC, and vice versa. Simultaneous
JIT and GC executions may cause SEGV and so we should synchronize them.
cont.c: save continuation information in MJIT worker. As MJIT shouldn't
unload JIT-ed code which is being used, MJIT wants to know full list of
saved execution contexts for continuation and detect ISeqs in use.
mjit_compile.c: added empty JIT compiler so that you can reuse this commit
to build your own JIT compiler. This commit tries to compile ISeqs but
all of them are considered as not supported in this commit. So you can't
use JIT compiler in this commit yet while we added --jit option now.
Patch author: Vladimir Makarov <vmakarov@redhat.com>.
Contributors:
Takashi Kokubun <takashikkbn@gmail.com>.
wanabe <s.wanabe@gmail.com>.
Lars Kanis <lars@greiz-reinsdorf.de>.
Part of Feature 12589 and 14235.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62189 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2018-02-04 01:58:09 -05:00
/* Pointer to MJIT info about the continuation. */
struct mjit_cont * mjit_cont ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
} rb_context_t ;
2017-08-09 21:47:13 -04:00
/*
* Fiber status :
* [ Fiber . new ] - - - - - - > FIBER_CREATED
* | [ Fiber # resume ]
* v
* + - - > FIBER_RESUMED - - - - +
* [ Fiber # resume ] | | [ Fiber . yield ] |
* | v |
* + - - FIBER_SUSPENDED | [ Terminate ]
* |
* FIBER_TERMINATED < - +
*/
2008-10-22 11:12:07 -04:00
enum fiber_status {
2017-06-26 01:36:10 -04:00
FIBER_CREATED ,
2017-08-09 21:47:13 -04:00
FIBER_RESUMED ,
FIBER_SUSPENDED ,
2017-06-26 01:36:10 -04:00
FIBER_TERMINATED
2008-10-22 11:12:07 -04:00
} ;
2019-07-08 01:59:28 -04:00
# define FIBER_CREATED_P(fiber) ((fiber)->status == FIBER_CREATED)
# define FIBER_RESUMED_P(fiber) ((fiber)->status == FIBER_RESUMED)
# define FIBER_SUSPENDED_P(fiber) ((fiber)->status == FIBER_SUSPENDED)
# define FIBER_TERMINATED_P(fiber) ((fiber)->status == FIBER_TERMINATED)
# define FIBER_RUNNABLE_P(fiber) (FIBER_CREATED_P(fiber) || FIBER_SUSPENDED_P(fiber))
2017-08-09 21:47:13 -04:00
2014-10-15 20:19:22 -04:00
struct rb_fiber_struct {
2008-10-22 11:12:07 -04:00
rb_context_t cont ;
2017-06-28 11:25:30 -04:00
VALUE first_proc ;
2014-10-15 18:35:08 -04:00
struct rb_fiber_struct * prev ;
2018-08-22 00:04:06 -04:00
BITFIELD ( enum fiber_status , status , 2 ) ;
2011-11-08 23:26:39 -05:00
/* If a fiber invokes "transfer",
* then this fiber can ' t " resume " any more after that .
* You shouldn ' t mix " transfer " and " resume " .
*/
2018-08-20 19:48:03 -04:00
unsigned int transferred : 1 ;
2011-11-08 23:26:39 -05:00
2019-06-24 07:54:19 -04:00
struct coroutine_context context ;
2019-06-01 20:49:58 -04:00
struct fiber_pool_stack stack ;
2014-10-15 20:17:44 -04:00
} ;
2008-10-22 11:12:07 -04:00
2019-06-01 20:49:58 -04:00
static struct fiber_pool shared_fiber_pool = { NULL , NULL , 0 , 0 , 0 , 0 } ;
/*
* FreeBSD require a first ( i . e . addr ) argument of mmap ( 2 ) is not NULL
* if MAP_STACK is passed .
* http : //www.FreeBSD.org/cgi/query-pr.cgi?pr=158755
*/
# if defined(MAP_STACK) && !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__)
# define FIBER_STACK_FLAGS (MAP_PRIVATE | MAP_ANON | MAP_STACK)
# else
# define FIBER_STACK_FLAGS (MAP_PRIVATE | MAP_ANON)
# endif
# define ERRNOMSG strerror(errno)
// Locates the stack vacancy details for the given stack.
// Requires that fiber_pool_vacancy fits within one page.
inline static struct fiber_pool_vacancy *
fiber_pool_vacancy_pointer ( void * base , size_t size )
{
STACK_GROW_DIR_DETECTION ;
return ( struct fiber_pool_vacancy * ) (
( char * ) base + STACK_DIR_UPPER ( 0 , size - RB_PAGE_SIZE )
) ;
}
// Given an existing fiber pool, expand it by the specified number of stacks.
static struct fiber_pool_allocation *
fiber_pool_expand ( struct fiber_pool * fiber_pool , size_t count )
{
size_t i ;
struct fiber_pool_vacancy * vacancies = fiber_pool - > vacancies ;
struct fiber_pool_allocation * allocation = RB_ALLOC ( struct fiber_pool_allocation ) ;
size_t size = fiber_pool - > size ;
/* Initialize fiber pool */
allocation - > base = NULL ;
allocation - > size = size ;
allocation - > count = count ;
if ( DEBUG ) fprintf ( stderr , " fiber_pool_expand(%zu): %p, %zu/%zu x [%zu:%zu] \n " , count , fiber_pool , fiber_pool - > used , fiber_pool - > count , size , fiber_pool - > vm_stack_size ) ;
# ifdef _WIN32
DWORD old_protect ;
allocation - > base = VirtualAlloc ( 0 , count * size , MEM_COMMIT , PAGE_READWRITE ) ;
if ( ! allocation - > base ) {
rb_raise ( rb_eFiberError , " can't alloc machine stack to fiber (%zu x %zu bytes): %s " , count , size , ERRNOMSG ) ;
}
for ( i = 0 ; i < count ; i + = 1 ) {
void * base = ( char * ) allocation - > base + ( size * i ) ;
if ( ! VirtualProtect ( base , RB_PAGE_SIZE , PAGE_READWRITE | PAGE_GUARD , & old_protect ) ) {
VirtualFree ( allocation - > base , 0 , MEM_RELEASE ) ;
rb_raise ( rb_eFiberError , " can't set a guard page: %s " , ERRNOMSG ) ;
}
struct fiber_pool_vacancy * vacancy = fiber_pool_vacancy_pointer ( base , size ) ;
vacancy - > stack . base = base ;
vacancy - > stack . current = ( char * ) base + size ;
vacancy - > stack . size = size ;
vacancy - > stack . available = size - pagesize ;
vacancy - > stack . pool = fiber_pool ;
vacancy - > next = vacancies ;
vacancies = vacancy ;
}
# else
STACK_GROW_DIR_DETECTION ;
errno = 0 ;
allocation - > base = mmap ( NULL , count * size , PROT_READ | PROT_WRITE , FIBER_STACK_FLAGS , - 1 , 0 ) ;
if ( allocation - > base = = MAP_FAILED ) {
rb_raise ( rb_eFiberError , " can't alloc machine stack to fiber (%zu x %zu bytes): %s " , count , size , ERRNOMSG ) ;
}
for ( i = 0 ; i < count ; i + = 1 ) {
void * base = ( char * ) allocation - > base + ( size * i ) ;
void * page = ( char * ) base + STACK_DIR_UPPER ( size - RB_PAGE_SIZE , 0 ) ;
if ( mprotect ( page , RB_PAGE_SIZE , PROT_NONE ) < 0 ) {
munmap ( allocation - > base , count * size ) ;
rb_raise ( rb_eFiberError , " can't set a guard page: %s " , ERRNOMSG ) ;
}
struct fiber_pool_vacancy * vacancy = fiber_pool_vacancy_pointer ( base , size ) ;
vacancy - > stack . base = base ;
vacancy - > stack . current = ( char * ) base + STACK_DIR_UPPER ( 0 , size ) ;
vacancy - > stack . size = size ;
vacancy - > stack . available = size - pagesize ;
vacancy - > stack . pool = fiber_pool ;
vacancy - > next = vacancies ;
vacancies = vacancy ;
}
# endif
// Insert the allocation into the head of the pool:
allocation - > next = fiber_pool - > allocations ;
fiber_pool - > allocations = allocation ;
fiber_pool - > vacancies = vacancies ;
fiber_pool - > count + = count ;
return allocation ;
}
// Initialize the specified fiber pool with the given number of stacks.
// @param vm_stack_size The size of the vm stack to allocate.
static void
fiber_pool_initialize ( struct fiber_pool * fiber_pool , size_t size , size_t count , size_t vm_stack_size )
{
VM_ASSERT ( vm_stack_size < size ) ;
fiber_pool - > allocations = NULL ;
fiber_pool - > vacancies = NULL ;
fiber_pool - > size = ( ( size / RB_PAGE_SIZE ) + 1 ) * RB_PAGE_SIZE ;
fiber_pool - > count = count ;
fiber_pool - > used = 0 ;
fiber_pool - > vm_stack_size = vm_stack_size ;
fiber_pool_expand ( fiber_pool , count ) ;
}
# ifdef RB_EXPERIMENTAL_FIBER_POOL
// Free the list of fiber pool allocations.
static void
fiber_pool_free_allocations ( struct fiber_pool_allocation * allocation )
{
// If no stacks are being used, we can free this allocation:
// VM_ASSERT(allocation->used == 0);
# ifdef _WIN32
VirtualFree ( allocation - > base , 0 , MEM_RELEASE ) ;
# else
munmap ( allocation - > base , allocation - > size * allocation - > count ) ;
# endif
allocation - > base = NULL ;
if ( allocation - > next ! = NULL ) {
fiber_pool_free_allocations ( allocation - > next ) ;
}
ruby_xfree ( allocation ) ;
}
# endif
// Reset the current stack pointer and available size of the given stack.
inline static void
fiber_pool_stack_reset ( struct fiber_pool_stack * stack )
{
STACK_GROW_DIR_DETECTION ;
stack - > current = ( char * ) stack - > base + STACK_DIR_UPPER ( 0 , stack - > size ) ;
stack - > available = stack - > size - RB_PAGE_SIZE ;
}
// A pointer to the base of the current unused portion of the stack.
inline static void *
fiber_pool_stack_base ( struct fiber_pool_stack * stack )
{
STACK_GROW_DIR_DETECTION ;
return STACK_DIR_UPPER ( stack - > current , ( char * ) stack - > current - stack - > available ) ;
}
// Allocate some memory from the stack. Used to allocate vm_stack inline with machine stack.
// @sa fiber_initialize_coroutine
inline static void *
fiber_pool_stack_alloca ( struct fiber_pool_stack * stack , size_t offset )
{
STACK_GROW_DIR_DETECTION ;
VM_ASSERT ( stack - > available > = offset ) ;
// The pointer to the memory being allocated:
void * pointer = STACK_DIR_UPPER ( stack - > current , ( char * ) stack - > current - offset ) ;
// Move the stack pointer:
stack - > current = STACK_DIR_UPPER ( ( char * ) stack - > current + offset , ( char * ) stack - > current - offset ) ;
stack - > available - = offset ;
return pointer ;
}
// Acquire a stack from the given fiber pool. If none are avilable, allocate more.
static struct fiber_pool_stack
fiber_pool_stack_acquire ( struct fiber_pool * fiber_pool ) {
struct fiber_pool_vacancy * vacancy = fiber_pool - > vacancies ;
if ( DEBUG ) fprintf ( stderr , " fiber_pool_stack_acquire: %p used=%zu \n " , fiber_pool - > vacancies , fiber_pool - > used ) ;
if ( ! vacancy ) {
size_t count = fiber_pool - > count ;
if ( count > 1024 ) count = 1024 ;
fiber_pool_expand ( fiber_pool , count ) ;
// The free list should now contain some stacks:
VM_ASSERT ( fiber_pool - > vacancies ) ;
vacancy = fiber_pool - > vacancies ;
}
// Take the top item from the free list:
fiber_pool - > vacancies = vacancy - > next ;
fiber_pool - > used + = 1 ;
fiber_pool_stack_reset ( & vacancy - > stack ) ;
return vacancy - > stack ;
}
// Release and return a stack to the vacancy list.
static void
fiber_pool_stack_release ( struct fiber_pool_stack stack ) {
struct fiber_pool_vacancy * vacancy = fiber_pool_vacancy_pointer ( stack . base , stack . size ) ;
# if defined(MADV_FREE) && defined(__linux__)
// Using madvise can make physical memory available to OS when there is memory pressure.
// But bencmarks show that this approach makes performance worse.
// madvise(vacancy->stack.base, vacancy->stack.size - RB_PAGE_SIZE, MADV_FREE);
# endif
vacancy - > stack = stack ;
vacancy - > next = stack . pool - > vacancies ;
stack . pool - > vacancies = vacancy ;
stack . pool - > used - = 1 ;
if ( DEBUG ) fprintf ( stderr , " fiber_pool_stack_release: %p used=%zu \n " , stack . base , stack . pool - > used ) ;
}
static COROUTINE
fiber_entry ( struct coroutine_context * from , struct coroutine_context * to )
{
rb_fiber_start ( ) ;
}
2019-06-27 02:59:25 -04:00
// Initialize a fiber's coroutine's machine stack and vm stack.
2019-06-01 20:49:58 -04:00
static VALUE *
2019-06-27 02:59:25 -04:00
fiber_initialize_coroutine ( rb_fiber_t * fiber , size_t * vm_stack_size )
2019-06-01 20:49:58 -04:00
{
struct fiber_pool * fiber_pool = fiber - > stack . pool ;
rb_execution_context_t * sec = & fiber - > cont . saved_ec ;
void * vm_stack = NULL ;
STACK_GROW_DIR_DETECTION ;
VM_ASSERT ( fiber_pool ! = NULL ) ;
fiber - > stack = fiber_pool_stack_acquire ( fiber_pool ) ;
vm_stack = fiber_pool_stack_alloca ( & fiber - > stack , fiber_pool - > vm_stack_size ) ;
* vm_stack_size = fiber_pool - > vm_stack_size ;
2019-06-27 02:59:25 -04:00
# ifdef COROUTINE_PRIVATE_STACK
coroutine_initialize ( & fiber - > context , fiber_entry , fiber_pool_stack_base ( & fiber - > stack ) , fiber - > stack . available , sec - > machine . stack_start ) ;
// The stack for this execution context is still the main machine stack, so don't adjust it.
// If this is not managed correctly, you will fail in `rb_ec_stack_check`.
// We limit the machine stack usage to the fiber stack size.
if ( sec - > machine . stack_maxsize > fiber - > stack . available ) {
sec - > machine . stack_maxsize = fiber - > stack . available ;
}
# else
2019-06-01 20:49:58 -04:00
coroutine_initialize ( & fiber - > context , fiber_entry , fiber_pool_stack_base ( & fiber - > stack ) , fiber - > stack . available ) ;
2019-06-27 02:59:25 -04:00
// The stack for this execution context is the one we allocated:
2019-06-01 20:49:58 -04:00
sec - > machine . stack_start = fiber - > stack . current ;
sec - > machine . stack_maxsize = fiber - > stack . available ;
2019-06-27 02:59:25 -04:00
# endif
2019-06-01 20:49:58 -04:00
return vm_stack ;
}
2018-11-20 05:18:12 -05:00
2017-08-09 21:47:13 -04:00
static const char *
fiber_status_name ( enum fiber_status s )
{
switch ( s ) {
case FIBER_CREATED : return " created " ;
case FIBER_RESUMED : return " resumed " ;
case FIBER_SUSPENDED : return " suspended " ;
case FIBER_TERMINATED : return " terminated " ;
}
VM_UNREACHABLE ( fiber_status_name ) ;
return NULL ;
}
2017-10-26 04:32:49 -04:00
static void
2019-07-08 01:59:28 -04:00
fiber_verify ( const rb_fiber_t * fiber )
2017-10-26 04:32:49 -04:00
{
# if VM_CHECK_MODE > 0
2019-07-08 01:59:28 -04:00
VM_ASSERT ( fiber - > cont . saved_ec . fiber_ptr = = fiber ) ;
2017-10-26 04:32:49 -04:00
2019-07-08 01:59:28 -04:00
switch ( fiber - > status ) {
2017-10-26 04:32:49 -04:00
case FIBER_RESUMED :
2019-07-08 03:00:29 -04:00
VM_ASSERT ( fiber - > cont . saved_ec . vm_stack ! = NULL ) ;
2019-06-01 01:48:25 -04:00
break ;
2017-10-26 04:32:49 -04:00
case FIBER_SUSPENDED :
2019-07-08 03:00:29 -04:00
VM_ASSERT ( fiber - > cont . saved_ec . vm_stack ! = NULL ) ;
2019-06-01 01:48:25 -04:00
break ;
2017-10-26 04:32:49 -04:00
case FIBER_CREATED :
case FIBER_TERMINATED :
2019-06-01 01:48:25 -04:00
/* TODO */
break ;
2017-10-26 04:32:49 -04:00
default :
2019-06-01 01:48:25 -04:00
VM_UNREACHABLE ( fiber_verify ) ;
2017-10-26 04:32:49 -04:00
}
# endif
}
# if VM_CHECK_MODE > 0
void
rb_ec_verify ( const rb_execution_context_t * ec )
{
/* TODO */
}
# endif
2019-06-01 20:49:58 -04:00
inline static void
2019-07-08 01:59:28 -04:00
fiber_status_set ( rb_fiber_t * fiber , enum fiber_status s )
2017-08-09 21:47:13 -04:00
{
2019-06-01 20:49:58 -04:00
if ( DEBUG ) fprintf ( stderr , " fiber: %p, status: %s -> %s \n " , ( void * ) fiber , fiber_status_name ( fiber - > status ) , fiber_status_name ( s ) ) ;
2019-07-08 01:59:28 -04:00
VM_ASSERT ( ! FIBER_TERMINATED_P ( fiber ) ) ;
VM_ASSERT ( fiber - > status ! = s ) ;
fiber_verify ( fiber ) ;
fiber - > status = s ;
2017-08-09 21:47:13 -04:00
}
2017-10-26 04:32:49 -04:00
static inline void
2019-07-08 01:59:28 -04:00
ec_switch ( rb_thread_t * th , rb_fiber_t * fiber )
2017-10-26 04:32:49 -04:00
{
2019-07-08 01:59:28 -04:00
rb_execution_context_t * ec = & fiber - > cont . saved_ec ;
2018-07-26 04:30:10 -04:00
2017-10-26 04:32:49 -04:00
ruby_current_execution_context_ptr = th - > ec = ec ;
2018-07-26 04:30:10 -04:00
/*
* timer - thread may set trap interrupt on previous th - > ec at any time ;
* ensure we do not delay ( or lose ) the trap interrupt handling .
*/
if ( th - > vm - > main_thread = = th & & rb_signal_buff_size ( ) > 0 ) {
RUBY_VM_SET_TRAP_INTERRUPT ( ec ) ;
}
2017-11-06 00:41:48 -05:00
VM_ASSERT ( ec - > fiber_ptr - > cont . self = = 0 | | ec - > vm_stack ! = NULL ) ;
2017-10-26 04:32:49 -04:00
}
2018-08-20 21:01:37 -04:00
static rb_context_t *
cont_ptr ( VALUE obj )
{
rb_context_t * cont ;
TypedData_Get_Struct ( obj , rb_context_t , & cont_data_type , cont ) ;
return cont ;
}
2007-05-23 18:52:19 -04:00
2018-08-20 21:01:37 -04:00
static rb_fiber_t *
fiber_ptr ( VALUE obj )
{
2019-07-08 01:59:28 -04:00
rb_fiber_t * fiber ;
2018-08-20 21:01:37 -04:00
2019-07-08 01:59:28 -04:00
TypedData_Get_Struct ( obj , rb_fiber_t , & fiber_data_type , fiber ) ;
if ( ! fiber ) rb_raise ( rb_eFiberError , " uninitialized fiber " ) ;
2018-08-20 21:01:37 -04:00
2019-07-08 01:59:28 -04:00
return fiber ;
2018-08-20 21:01:37 -04:00
}
2008-10-22 11:12:07 -04:00
2016-12-07 18:47:59 -05:00
NOINLINE ( static VALUE cont_capture ( volatile int * volatile stat ) ) ;
2007-05-23 18:52:19 -04:00
2009-09-20 21:13:24 -04:00
# define THREAD_MUST_BE_RUNNING(th) do { \
2019-06-01 01:48:25 -04:00
if ( ! ( th ) - > ec - > tag ) rb_raise ( rb_eThreadError , " not running thread " ) ; \
2009-09-20 21:13:24 -04:00
} while ( 0 )
2007-05-23 18:52:19 -04:00
2017-09-10 15:00:08 -04:00
static VALUE
cont_thread_value ( const rb_context_t * cont )
{
2017-10-29 08:57:04 -04:00
return cont - > saved_ec . thread_ptr - > self ;
2017-09-10 15:00:08 -04:00
}
2019-05-31 16:25:24 -04:00
static void
cont_compact ( void * ptr )
{
rb_context_t * cont = ptr ;
cont - > value = rb_gc_location ( cont - > value ) ;
rb_execution_context_update ( & cont - > saved_ec ) ;
}
2007-05-23 18:52:19 -04:00
static void
cont_mark ( void * ptr )
{
2017-02-12 20:05:23 -05:00
rb_context_t * cont = ptr ;
2007-06-24 22:44:20 -04:00
RUBY_MARK_ENTER ( " cont " ) ;
2019-05-31 16:25:24 -04:00
rb_gc_mark_no_pin ( cont - > value ) ;
2016-07-28 07:02:30 -04:00
2017-09-10 15:00:08 -04:00
rb_execution_context_mark ( & cont - > saved_ec ) ;
rb_gc_mark ( cont_thread_value ( cont ) ) ;
2007-05-23 18:52:19 -04:00
2017-08-21 20:41:24 -04:00
if ( cont - > saved_vm_stack . ptr ) {
2008-11-18 11:19:37 -05:00
# ifdef CAPTURE_JUST_VALID_VM_STACK
2019-06-01 01:48:25 -04:00
rb_gc_mark_locations ( cont - > saved_vm_stack . ptr ,
cont - > saved_vm_stack . ptr + cont - > saved_vm_stack . slen + cont - > saved_vm_stack . clen ) ;
2009-02-05 11:13:54 -05:00
# else
2019-06-01 01:48:25 -04:00
rb_gc_mark_locations ( cont - > saved_vm_stack . ptr ,
cont - > saved_vm_stack . ptr , cont - > saved_ec . stack_size ) ;
2008-11-18 11:19:37 -05:00
# endif
2017-02-12 20:05:23 -05:00
}
2007-05-28 21:59:53 -04:00
2017-02-12 20:05:23 -05:00
if ( cont - > machine . stack ) {
2019-06-01 01:48:25 -04:00
if ( cont - > type = = CONTINUATION_CONTEXT ) {
/* cont */
rb_gc_mark_locations ( cont - > machine . stack ,
cont - > machine . stack + cont - > machine . stack_size ) ;
}
else {
/* fiber */
2019-07-08 03:00:29 -04:00
const rb_fiber_t * fiber = ( rb_fiber_t * ) cont ;
2017-06-28 00:49:30 -04:00
2019-07-08 03:00:29 -04:00
if ( ! FIBER_TERMINATED_P ( fiber ) ) {
2019-06-01 01:48:25 -04:00
rb_gc_mark_locations ( cont - > machine . stack ,
cont - > machine . stack + cont - > machine . stack_size ) ;
}
}
2017-02-12 20:05:23 -05:00
}
2007-06-24 22:44:20 -04:00
RUBY_MARK_LEAVE ( " cont " ) ;
2007-05-23 18:52:19 -04:00
}
2018-09-12 16:49:24 -04:00
static int
2019-07-08 01:59:28 -04:00
fiber_is_root_p ( const rb_fiber_t * fiber )
2018-09-12 16:49:24 -04:00
{
2019-07-08 01:59:28 -04:00
return fiber = = fiber - > cont . saved_ec . thread_ptr - > root_fiber ;
2018-09-12 16:49:24 -04:00
}
2007-05-23 18:52:19 -04:00
static void
cont_free ( void * ptr )
{
2017-03-17 15:59:56 -04:00
rb_context_t * cont = ptr ;
2007-06-24 22:44:20 -04:00
RUBY_FREE_ENTER ( " cont " ) ;
2019-06-05 07:39:17 -04:00
2017-03-17 15:59:56 -04:00
if ( cont - > type = = CONTINUATION_CONTEXT ) {
2019-06-01 20:49:58 -04:00
ruby_xfree ( cont - > saved_ec . vm_stack ) ;
2019-06-01 01:48:25 -04:00
ruby_xfree ( cont - > ensure_array ) ;
RUBY_FREE_UNLESS_NULL ( cont - > machine . stack ) ;
} else {
2019-07-08 03:00:29 -04:00
rb_fiber_t * fiber = ( rb_fiber_t * ) cont ;
coroutine_destroy ( & fiber - > context ) ;
2019-06-01 20:49:58 -04:00
if ( fiber - > stack . base ! = NULL ) {
2019-07-08 02:13:59 -04:00
if ( fiber_is_root_p ( fiber ) ) {
rb_bug ( " Illegal root fiber parameter " ) ;
}
2019-06-01 20:49:58 -04:00
if ( fiber - > stack . base ) {
fiber_pool_stack_release ( fiber - > stack ) ;
fiber - > stack . base = NULL ;
}
2019-06-01 01:48:25 -04:00
}
2017-03-17 15:59:56 -04:00
}
2019-06-01 01:48:25 -04:00
2017-08-21 20:41:24 -04:00
RUBY_FREE_UNLESS_NULL ( cont - > saved_vm_stack . ptr ) ;
2007-11-08 20:11:49 -05:00
2018-06-23 09:41:06 -04:00
if ( mjit_enabled & & cont - > mjit_cont ! = NULL ) {
mjit.c: merge MJIT infrastructure
that allows to JIT-compile Ruby methods by generating C code and
using C compiler. See the first comment of mjit.c to know what this
file does.
mjit.c is authored by Vladimir Makarov <vmakarov@redhat.com>.
After he invented great method JIT infrastructure for MRI as MJIT,
Lars Kanis <lars@greiz-reinsdorf.de> sent the patch to support MinGW
in MJIT. In addition to merging it, I ported pthread to Windows native
threads. Now this MJIT infrastructure can be compiled on Visual Studio.
This commit simplifies mjit.c to decrease code at initial merge. For
example, this commit does not provide multiple JIT threads support.
We can resurrect them later if we really want them, but I wanted to minimize
diff to make it easier to review this patch.
`/tmp/_mjitXXX` file is renamed to `/tmp/_ruby_mjitXXX` because non-Ruby
developers may not know the name "mjit" and the file name should make
sure it's from Ruby and not from some harmful programs. TODO: it may be
better to store this to some temporary directory which Ruby is already using
by Tempfile, if it's not bad for performance.
mjit.h: New. It has `mjit_exec` interface similar to `vm_exec`, which is
for triggering MJIT. This drops interface for AOT compared to the original
MJIT.
Makefile.in: define macros to let MJIT know the path of MJIT header.
Probably we can refactor this to reduce the number of macros (TODO).
win32/Makefile.sub: ditto.
common.mk: compile mjit.o and mjit_compile.o. Unlike original MJIT, this
commit separates MJIT infrastructure and JIT compiler code as independent
object files. As initial patch is NOT going to have ultra-fast JIT compiler,
it's likely to replace JIT compiler, e.g. original MJIT's compiler or some
future JIT impelementations which are not public now.
inits.c: define MJIT module. This is added because `MJIT.enabled?` was
necessary for testing.
test/lib/zombie_hunter.rb: skip if `MJIT.enabled?`. Obviously this
wouldn't work with current code when JIT is enabled.
test/ruby/test_io.rb: skip this too. This would make no sense with MJIT.
ruby.c: define MJIT CLI options. As major difference from original MJIT,
"-j:l"/"--jit:llvm" are renamed to "--jit-cc" because I want to support
not only gcc/clang but also cl.exe (Visual Studio) in the future. But it
takes only "--jit-cc=gcc", "--jit-cc=clang" for now. And only long "--jit"
options are allowed since some Ruby committers preferred it at Ruby
developers Meeting on January, and some of options are renamed.
This file also triggers to initialize MJIT thread and variables.
eval.c: finalize MJIT worker thread and variables.
test/ruby/test_rubyoptions.rb: fix number of CLI options for --jit.
thread_pthread.c: change for pthread abstraction in MJIT. Prefix rb_ for
functions which are used by other files.
thread_win32.c: ditto, for Windows. Those pthread porting is one of major
works that YARV-MJIT created, which is my fork of MJIT, in Feature 14235.
thread.c: follow rb_ prefix changes
vm.c: trigger MJIT call on VM invocation. Also trigger `mjit_mark` to avoid
SEGV by race between JIT and GC of ISeq. The improvement was provided by
wanabe <s.wanabe@gmail.com>.
In JIT compiler I created and am going to add in my next commit, I found
that having `mjit_exec` after `vm_loop_start:` is harmful because the
JIT-ed function doesn't proceed other ISeqs on RESTORE_REGS of leave insn.
Executing non-FINISH frame is unexpected for my JIT compiler and
`exception_handler` triggers executions of such ISeqs. So `mjit_exec`
here should be executed only when it directly comes from `vm_exec` call.
`RubyVM::MJIT` module and `.enabled?` method is added so that we can skip
some tests which don't expect JIT threads or compiler file descriptors.
vm_insnhelper.h: trigger MJIT on method calls during VM execution.
vm_core.h: add fields required for mjit.c. `bp` must be `cfp[6]` because
rb_control_frame_struct is likely to be casted to another struct. The
last position is the safest place to add the new field.
vm_insnhelper.c: save initial value of cfp->ep as cfp->bp. This is an
optimization which are done in both MJIT and YARV-MJIT. So this change
is added in this commit. Calculating bp from ep is a little heavy work,
so bp is kind of cache for it.
iseq.c: notify ISeq GC to MJIT. We should know which iseq in MJIT queue
is GCed to avoid SEGV. TODO: unload some GCed units in some safe way.
gc.c: add hooks so that MJIT can wait GC, and vice versa. Simultaneous
JIT and GC executions may cause SEGV and so we should synchronize them.
cont.c: save continuation information in MJIT worker. As MJIT shouldn't
unload JIT-ed code which is being used, MJIT wants to know full list of
saved execution contexts for continuation and detect ISeqs in use.
mjit_compile.c: added empty JIT compiler so that you can reuse this commit
to build your own JIT compiler. This commit tries to compile ISeqs but
all of them are considered as not supported in this commit. So you can't
use JIT compiler in this commit yet while we added --jit option now.
Patch author: Vladimir Makarov <vmakarov@redhat.com>.
Contributors:
Takashi Kokubun <takashikkbn@gmail.com>.
wanabe <s.wanabe@gmail.com>.
Lars Kanis <lars@greiz-reinsdorf.de>.
Part of Feature 12589 and 14235.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62189 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2018-02-04 01:58:09 -05:00
mjit_cont_free ( cont - > mjit_cont ) ;
}
2017-03-17 15:59:56 -04:00
/* free rb_cont_t or rb_fiber_t */
ruby_xfree ( ptr ) ;
2007-06-24 22:44:20 -04:00
RUBY_FREE_LEAVE ( " cont " ) ;
2007-05-23 18:52:19 -04:00
}
2009-09-08 11:27:31 -04:00
static size_t
2009-09-08 22:22:08 -04:00
cont_memsize ( const void * ptr )
2009-09-08 11:27:31 -04:00
{
2009-09-08 22:26:06 -04:00
const rb_context_t * cont = ptr ;
2009-09-08 11:27:31 -04:00
size_t size = 0 ;
2015-12-08 19:38:32 -05:00
size = sizeof ( * cont ) ;
2017-08-21 20:41:24 -04:00
if ( cont - > saved_vm_stack . ptr ) {
2009-09-08 11:27:31 -04:00
# ifdef CAPTURE_JUST_VALID_VM_STACK
2019-06-01 01:48:25 -04:00
size_t n = ( cont - > saved_vm_stack . slen + cont - > saved_vm_stack . clen ) ;
2009-09-08 11:27:31 -04:00
# else
2019-06-01 01:48:25 -04:00
size_t n = cont - > saved_ec . vm_stack_size ;
2009-09-08 11:27:31 -04:00
# endif
2019-06-01 01:48:25 -04:00
size + = n * sizeof ( * cont - > saved_vm_stack . ptr ) ;
2015-12-08 19:38:32 -05:00
}
2009-09-08 11:27:31 -04:00
2015-12-08 19:38:32 -05:00
if ( cont - > machine . stack ) {
2019-06-01 01:48:25 -04:00
size + = cont - > machine . stack_size * sizeof ( * cont - > machine . stack ) ;
2015-12-08 19:38:32 -05:00
}
2019-06-19 05:06:57 -04:00
2009-09-08 11:27:31 -04:00
return size ;
}
2019-05-31 16:25:24 -04:00
void
2019-07-08 01:59:28 -04:00
rb_fiber_update_self ( rb_fiber_t * fiber )
2019-05-31 16:25:24 -04:00
{
2019-07-08 01:59:28 -04:00
if ( fiber - > cont . self ) {
fiber - > cont . self = rb_gc_location ( fiber - > cont . self ) ;
2019-05-31 16:25:24 -04:00
}
else {
2019-07-08 01:59:28 -04:00
rb_execution_context_update ( & fiber - > cont . saved_ec ) ;
2019-05-31 16:25:24 -04:00
}
}
2014-10-15 18:35:08 -04:00
void
2019-07-08 01:59:28 -04:00
rb_fiber_mark_self ( const rb_fiber_t * fiber )
2014-10-15 18:35:08 -04:00
{
2019-07-08 01:59:28 -04:00
if ( fiber - > cont . self ) {
rb_gc_mark_no_pin ( fiber - > cont . self ) ;
2017-10-26 04:32:49 -04:00
}
else {
2019-07-08 03:00:29 -04:00
rb_execution_context_mark ( & fiber - > cont . saved_ec ) ;
2017-10-26 04:32:49 -04:00
}
2014-10-15 18:35:08 -04:00
}
2019-05-31 16:25:24 -04:00
static void
fiber_compact ( void * ptr )
{
2019-07-08 01:59:28 -04:00
rb_fiber_t * fiber = ptr ;
fiber - > first_proc = rb_gc_location ( fiber - > first_proc ) ;
2019-05-31 16:25:24 -04:00
2019-07-08 01:59:28 -04:00
if ( fiber - > prev ) rb_fiber_update_self ( fiber - > prev ) ;
2019-05-31 16:25:24 -04:00
2019-07-08 01:59:28 -04:00
cont_compact ( & fiber - > cont ) ;
fiber_verify ( fiber ) ;
2019-05-31 16:25:24 -04:00
}
2008-10-22 11:12:07 -04:00
static void
fiber_mark ( void * ptr )
{
2019-07-08 01:59:28 -04:00
rb_fiber_t * fiber = ptr ;
2008-10-22 11:12:07 -04:00
RUBY_MARK_ENTER ( " cont " ) ;
2019-07-08 01:59:28 -04:00
fiber_verify ( fiber ) ;
rb_gc_mark_no_pin ( fiber - > first_proc ) ;
if ( fiber - > prev ) rb_fiber_mark_self ( fiber - > prev ) ;
cont_mark ( & fiber - > cont ) ;
2008-10-22 11:12:07 -04:00
RUBY_MARK_LEAVE ( " cont " ) ;
}
static void
fiber_free ( void * ptr )
{
2019-07-08 01:59:28 -04:00
rb_fiber_t * fiber = ptr ;
2008-10-22 11:12:07 -04:00
RUBY_FREE_ENTER ( " fiber " ) ;
2017-10-26 10:21:31 -04:00
2019-07-08 01:59:28 -04:00
if ( fiber - > cont . saved_ec . local_storage ) {
2019-07-08 03:00:29 -04:00
st_free_table ( fiber - > cont . saved_ec . local_storage ) ;
2008-10-22 11:12:07 -04:00
}
2017-03-17 15:59:56 -04:00
2019-07-08 01:59:28 -04:00
cont_free ( & fiber - > cont ) ;
2008-10-22 11:12:07 -04:00
RUBY_FREE_LEAVE ( " fiber " ) ;
}
2009-09-08 11:27:31 -04:00
static size_t
2009-09-08 22:22:08 -04:00
fiber_memsize ( const void * ptr )
2009-09-08 11:27:31 -04:00
{
2019-07-08 01:59:28 -04:00
const rb_fiber_t * fiber = ptr ;
size_t size = sizeof ( * fiber ) ;
const rb_execution_context_t * saved_ec = & fiber - > cont . saved_ec ;
2018-09-12 16:49:19 -04:00
const rb_thread_t * th = rb_ec_thread_ptr ( saved_ec ) ;
2015-12-08 19:38:32 -05:00
2018-09-12 16:49:19 -04:00
/*
* vm . c : : thread_memsize already counts th - > ec - > local_storage
*/
2019-07-08 01:59:28 -04:00
if ( saved_ec - > local_storage & & fiber ! = th - > root_fiber ) {
2019-06-01 01:48:25 -04:00
size + = st_memsize ( saved_ec - > local_storage ) ;
2009-09-08 11:27:31 -04:00
}
2019-07-08 01:59:28 -04:00
size + = cont_memsize ( & fiber - > cont ) ;
2010-10-03 19:00:21 -04:00
return size ;
2009-09-08 11:27:31 -04:00
}
2012-02-15 09:00:11 -05:00
VALUE
rb_obj_is_fiber ( VALUE obj )
{
if ( rb_typeddata_is_kind_of ( obj , & fiber_data_type ) ) {
2019-06-01 01:48:25 -04:00
return Qtrue ;
2012-02-15 09:00:11 -05:00
}
else {
2019-06-01 01:48:25 -04:00
return Qfalse ;
2012-02-15 09:00:11 -05:00
}
}
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
static void
cont_save_machine_stack ( rb_thread_t * th , rb_context_t * cont )
2007-05-23 18:52:19 -04:00
{
2009-05-31 21:11:04 -04:00
size_t size ;
2007-05-23 18:52:19 -04:00
2017-10-26 04:32:49 -04:00
SET_MACHINE_STACK_END ( & th - > ec - > machine . stack_end ) ;
2007-06-14 04:35:20 -04:00
2017-10-26 04:32:49 -04:00
if ( th - > ec - > machine . stack_start > th - > ec - > machine . stack_end ) {
2019-06-01 01:48:25 -04:00
size = cont - > machine . stack_size = th - > ec - > machine . stack_start - th - > ec - > machine . stack_end ;
cont - > machine . stack_src = th - > ec - > machine . stack_end ;
2007-05-23 18:52:19 -04:00
}
else {
2019-06-01 01:48:25 -04:00
size = cont - > machine . stack_size = th - > ec - > machine . stack_end - th - > ec - > machine . stack_start ;
cont - > machine . stack_src = th - > ec - > machine . stack_start ;
2007-05-23 18:52:19 -04:00
}
2014-01-28 01:09:58 -05:00
if ( cont - > machine . stack ) {
2019-06-01 01:48:25 -04:00
REALLOC_N ( cont - > machine . stack , VALUE , size ) ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
}
else {
2019-06-01 01:48:25 -04:00
cont - > machine . stack = ALLOC_N ( VALUE , size ) ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
}
2007-12-23 14:03:23 -05:00
FLUSH_REGISTER_WINDOWS ;
2014-01-28 01:09:58 -05:00
MEMCPY ( cont - > machine . stack , cont - > machine . stack_src , VALUE , size ) ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
}
2009-09-08 11:27:31 -04:00
static const rb_data_type_t cont_data_type = {
" continuation " ,
2019-05-31 16:25:24 -04:00
{ cont_mark , cont_free , cont_memsize , cont_compact } ,
2014-12-01 01:38:04 -05:00
0 , 0 , RUBY_TYPED_FREE_IMMEDIATELY
2009-09-08 11:27:31 -04:00
} ;
2014-10-15 18:35:08 -04:00
static inline void
2011-06-14 08:57:50 -04:00
cont_save_thread ( rb_context_t * cont , rb_thread_t * th )
2008-10-22 11:12:07 -04:00
{
2017-09-10 15:00:08 -04:00
rb_execution_context_t * sec = & cont - > saved_ec ;
2014-10-15 18:35:01 -04:00
2017-06-28 10:27:49 -04:00
VM_ASSERT ( th - > status = = THREAD_RUNNABLE ) ;
2008-10-22 11:12:07 -04:00
/* save thread context */
2017-10-26 04:32:49 -04:00
* sec = * th - > ec ;
2014-10-15 18:35:01 -04:00
2017-12-25 09:22:21 -05:00
/* saved_ec->machine.stack_end should be NULL */
2011-06-14 08:57:50 -04:00
/* because it may happen GC afterward */
2017-09-10 15:00:08 -04:00
sec - > machine . stack_end = NULL ;
2011-06-14 08:57:50 -04:00
}
static void
cont_init ( rb_context_t * cont , rb_thread_t * th )
{
/* save thread context */
cont_save_thread ( cont , th ) ;
2017-10-29 08:57:04 -04:00
cont - > saved_ec . thread_ptr = th ;
2017-09-10 15:00:08 -04:00
cont - > saved_ec . local_storage = NULL ;
cont - > saved_ec . local_storage_recursive_hash = Qnil ;
cont - > saved_ec . local_storage_recursive_hash_for_trace = Qnil ;
2018-06-23 09:41:06 -04:00
if ( mjit_enabled ) {
mjit.c: merge MJIT infrastructure
that allows to JIT-compile Ruby methods by generating C code and
using C compiler. See the first comment of mjit.c to know what this
file does.
mjit.c is authored by Vladimir Makarov <vmakarov@redhat.com>.
After he invented great method JIT infrastructure for MRI as MJIT,
Lars Kanis <lars@greiz-reinsdorf.de> sent the patch to support MinGW
in MJIT. In addition to merging it, I ported pthread to Windows native
threads. Now this MJIT infrastructure can be compiled on Visual Studio.
This commit simplifies mjit.c to decrease code at initial merge. For
example, this commit does not provide multiple JIT threads support.
We can resurrect them later if we really want them, but I wanted to minimize
diff to make it easier to review this patch.
`/tmp/_mjitXXX` file is renamed to `/tmp/_ruby_mjitXXX` because non-Ruby
developers may not know the name "mjit" and the file name should make
sure it's from Ruby and not from some harmful programs. TODO: it may be
better to store this to some temporary directory which Ruby is already using
by Tempfile, if it's not bad for performance.
mjit.h: New. It has `mjit_exec` interface similar to `vm_exec`, which is
for triggering MJIT. This drops interface for AOT compared to the original
MJIT.
Makefile.in: define macros to let MJIT know the path of MJIT header.
Probably we can refactor this to reduce the number of macros (TODO).
win32/Makefile.sub: ditto.
common.mk: compile mjit.o and mjit_compile.o. Unlike original MJIT, this
commit separates MJIT infrastructure and JIT compiler code as independent
object files. As initial patch is NOT going to have ultra-fast JIT compiler,
it's likely to replace JIT compiler, e.g. original MJIT's compiler or some
future JIT impelementations which are not public now.
inits.c: define MJIT module. This is added because `MJIT.enabled?` was
necessary for testing.
test/lib/zombie_hunter.rb: skip if `MJIT.enabled?`. Obviously this
wouldn't work with current code when JIT is enabled.
test/ruby/test_io.rb: skip this too. This would make no sense with MJIT.
ruby.c: define MJIT CLI options. As major difference from original MJIT,
"-j:l"/"--jit:llvm" are renamed to "--jit-cc" because I want to support
not only gcc/clang but also cl.exe (Visual Studio) in the future. But it
takes only "--jit-cc=gcc", "--jit-cc=clang" for now. And only long "--jit"
options are allowed since some Ruby committers preferred it at Ruby
developers Meeting on January, and some of options are renamed.
This file also triggers to initialize MJIT thread and variables.
eval.c: finalize MJIT worker thread and variables.
test/ruby/test_rubyoptions.rb: fix number of CLI options for --jit.
thread_pthread.c: change for pthread abstraction in MJIT. Prefix rb_ for
functions which are used by other files.
thread_win32.c: ditto, for Windows. Those pthread porting is one of major
works that YARV-MJIT created, which is my fork of MJIT, in Feature 14235.
thread.c: follow rb_ prefix changes
vm.c: trigger MJIT call on VM invocation. Also trigger `mjit_mark` to avoid
SEGV by race between JIT and GC of ISeq. The improvement was provided by
wanabe <s.wanabe@gmail.com>.
In JIT compiler I created and am going to add in my next commit, I found
that having `mjit_exec` after `vm_loop_start:` is harmful because the
JIT-ed function doesn't proceed other ISeqs on RESTORE_REGS of leave insn.
Executing non-FINISH frame is unexpected for my JIT compiler and
`exception_handler` triggers executions of such ISeqs. So `mjit_exec`
here should be executed only when it directly comes from `vm_exec` call.
`RubyVM::MJIT` module and `.enabled?` method is added so that we can skip
some tests which don't expect JIT threads or compiler file descriptors.
vm_insnhelper.h: trigger MJIT on method calls during VM execution.
vm_core.h: add fields required for mjit.c. `bp` must be `cfp[6]` because
rb_control_frame_struct is likely to be casted to another struct. The
last position is the safest place to add the new field.
vm_insnhelper.c: save initial value of cfp->ep as cfp->bp. This is an
optimization which are done in both MJIT and YARV-MJIT. So this change
is added in this commit. Calculating bp from ep is a little heavy work,
so bp is kind of cache for it.
iseq.c: notify ISeq GC to MJIT. We should know which iseq in MJIT queue
is GCed to avoid SEGV. TODO: unload some GCed units in some safe way.
gc.c: add hooks so that MJIT can wait GC, and vice versa. Simultaneous
JIT and GC executions may cause SEGV and so we should synchronize them.
cont.c: save continuation information in MJIT worker. As MJIT shouldn't
unload JIT-ed code which is being used, MJIT wants to know full list of
saved execution contexts for continuation and detect ISeqs in use.
mjit_compile.c: added empty JIT compiler so that you can reuse this commit
to build your own JIT compiler. This commit tries to compile ISeqs but
all of them are considered as not supported in this commit. So you can't
use JIT compiler in this commit yet while we added --jit option now.
Patch author: Vladimir Makarov <vmakarov@redhat.com>.
Contributors:
Takashi Kokubun <takashikkbn@gmail.com>.
wanabe <s.wanabe@gmail.com>.
Lars Kanis <lars@greiz-reinsdorf.de>.
Part of Feature 12589 and 14235.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62189 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2018-02-04 01:58:09 -05:00
cont - > mjit_cont = mjit_cont_new ( & cont - > saved_ec ) ;
}
2008-10-22 11:12:07 -04:00
}
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
static rb_context_t *
cont_new ( VALUE klass )
{
rb_context_t * cont ;
volatile VALUE contval ;
2009-09-20 21:13:24 -04:00
rb_thread_t * th = GET_THREAD ( ) ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
2009-09-20 21:13:24 -04:00
THREAD_MUST_BE_RUNNING ( th ) ;
2009-09-08 11:27:31 -04:00
contval = TypedData_Make_Struct ( klass , rb_context_t , & cont_data_type , cont ) ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
cont - > self = contval ;
2009-09-20 21:13:24 -04:00
cont_init ( cont , th ) ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
return cont ;
}
2017-10-26 04:32:49 -04:00
#if 0
void
show_vm_stack ( const rb_execution_context_t * ec )
{
VALUE * p = ec - > vm_stack ;
while ( p < ec - > cfp - > sp ) {
2019-06-01 01:48:25 -04:00
fprintf ( stderr , " %3d " , ( int ) ( p - ec - > vm_stack ) ) ;
rb_obj_info_dump ( * p ) ;
p + + ;
2017-10-26 04:32:49 -04:00
}
}
void
show_vm_pcs ( const rb_control_frame_t * cfp ,
2019-06-01 01:48:25 -04:00
const rb_control_frame_t * end_of_cfp )
2017-10-26 04:32:49 -04:00
{
int i = 0 ;
while ( cfp ! = end_of_cfp ) {
2019-06-01 01:48:25 -04:00
int pc = 0 ;
if ( cfp - > iseq ) {
pc = cfp - > pc - cfp - > iseq - > body - > iseq_encoded ;
}
fprintf ( stderr , " %2d pc: %d \n " , i + + , pc ) ;
cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME ( cfp ) ;
2017-10-26 04:32:49 -04:00
}
}
# endif
2018-07-30 03:07:48 -04:00
COMPILER_WARNING_PUSH
2018-01-02 01:41:39 -05:00
# ifdef __clang__
2018-07-30 03:07:48 -04:00
COMPILER_WARNING_IGNORED ( - Wduplicate - decl - specifier )
2018-01-02 01:41:39 -05:00
# endif
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
static VALUE
2016-12-07 18:47:59 -05:00
cont_capture ( volatile int * volatile stat )
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
{
2016-12-07 18:27:51 -05:00
rb_context_t * volatile cont ;
2014-10-15 18:34:53 -04:00
rb_thread_t * th = GET_THREAD ( ) ;
2007-06-14 04:35:20 -04:00
volatile VALUE contval ;
2017-10-26 04:32:49 -04:00
const rb_execution_context_t * ec = th - > ec ;
2007-05-30 01:56:13 -04:00
2009-09-20 21:13:24 -04:00
THREAD_MUST_BE_RUNNING ( th ) ;
2017-10-28 06:47:19 -04:00
rb_vm_stack_to_heap ( th - > ec ) ;
2007-08-24 22:03:44 -04:00
cont = cont_new ( rb_cContinuation ) ;
2007-06-14 04:35:20 -04:00
contval = cont - > self ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
2008-11-18 11:19:37 -05:00
# ifdef CAPTURE_JUST_VALID_VM_STACK
2017-08-21 20:41:24 -04:00
cont - > saved_vm_stack . slen = ec - > cfp - > sp - ec - > vm_stack ;
cont - > saved_vm_stack . clen = ec - > vm_stack + ec - > vm_stack_size - ( VALUE * ) ec - > cfp ;
cont - > saved_vm_stack . ptr = ALLOC_N ( VALUE , cont - > saved_vm_stack . slen + cont - > saved_vm_stack . clen ) ;
2017-10-26 04:32:49 -04:00
MEMCPY ( cont - > saved_vm_stack . ptr ,
2019-06-01 01:48:25 -04:00
ec - > vm_stack ,
VALUE , cont - > saved_vm_stack . slen ) ;
2017-08-21 20:41:24 -04:00
MEMCPY ( cont - > saved_vm_stack . ptr + cont - > saved_vm_stack . slen ,
2019-06-01 01:48:25 -04:00
( VALUE * ) ec - > cfp ,
VALUE ,
cont - > saved_vm_stack . clen ) ;
2009-02-05 11:13:54 -05:00
# else
2017-08-21 20:41:24 -04:00
cont - > saved_vm_stack . ptr = ALLOC_N ( VALUE , ec - > vm_stack_size ) ;
MEMCPY ( cont - > saved_vm_stack . ptr , ec - > vm_stack , VALUE , ec - > vm_stack_size ) ;
2008-11-18 11:19:37 -05:00
# endif
2019-06-19 19:31:22 -04:00
rb_ec_clear_vm_stack ( & cont - > saved_ec ) ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
cont_save_machine_stack ( th , cont ) ;
2007-05-23 18:52:19 -04:00
2013-11-15 12:15:31 -05:00
/* backup ensure_list to array for search in another context */
{
2019-06-01 01:48:25 -04:00
rb_ensure_list_t * p ;
int size = 0 ;
rb_ensure_entry_t * entry ;
for ( p = th - > ec - > ensure_list ; p ; p = p - > next )
size + + ;
entry = cont - > ensure_array = ALLOC_N ( rb_ensure_entry_t , size + 1 ) ;
for ( p = th - > ec - > ensure_list ; p ; p = p - > next ) {
if ( ! p - > entry . marker )
p - > entry . marker = rb_ary_tmp_new ( 0 ) ; /* dummy object */
* entry + + = p - > entry ;
}
entry - > marker = 0 ;
2013-11-15 12:15:31 -05:00
}
2007-05-23 18:52:19 -04:00
if ( ruby_setjmp ( cont - > jmpbuf ) ) {
2019-06-01 01:48:25 -04:00
VALUE value ;
2007-05-23 18:52:19 -04:00
2019-06-01 01:48:25 -04:00
VAR_INITIALIZED ( cont ) ;
value = cont - > value ;
if ( cont - > argc = = - 1 ) rb_exc_raise ( value ) ;
cont - > value = Qnil ;
* stat = 1 ;
return value ;
2007-05-23 18:52:19 -04:00
}
else {
2019-06-01 01:48:25 -04:00
* stat = 0 ;
return contval ;
2007-05-23 18:52:19 -04:00
}
}
2018-07-30 03:07:48 -04:00
COMPILER_WARNING_POP
2007-05-23 18:52:19 -04:00
2017-08-10 02:01:57 -04:00
static inline void
2019-07-08 01:59:28 -04:00
fiber_restore_thread ( rb_thread_t * th , rb_fiber_t * fiber )
2017-08-10 02:01:57 -04:00
{
2019-07-08 01:59:28 -04:00
ec_switch ( th , fiber ) ;
VM_ASSERT ( th - > ec - > fiber_ptr = = fiber ) ;
2017-08-10 02:01:57 -04:00
}
2014-10-15 18:35:08 -04:00
static inline void
2010-05-05 14:37:37 -04:00
cont_restore_thread ( rb_context_t * cont )
2007-05-23 18:52:19 -04:00
{
2017-08-10 02:01:57 -04:00
rb_thread_t * th = GET_THREAD ( ) ;
2007-05-23 18:52:19 -04:00
/* restore thread context */
2007-11-08 20:11:49 -05:00
if ( cont - > type = = CONTINUATION_CONTEXT ) {
2019-06-01 01:48:25 -04:00
/* continuation */
rb_execution_context_t * sec = & cont - > saved_ec ;
2019-07-08 03:00:29 -04:00
rb_fiber_t * fiber = NULL ;
2007-06-06 23:48:13 -04:00
2019-06-01 01:48:25 -04:00
if ( sec - > fiber_ptr ! = NULL ) {
2019-07-08 03:00:29 -04:00
fiber = sec - > fiber_ptr ;
2019-06-01 01:48:25 -04:00
}
else if ( th - > root_fiber ) {
2019-07-08 03:00:29 -04:00
fiber = th - > root_fiber ;
2019-06-01 01:48:25 -04:00
}
2007-06-06 14:19:42 -04:00
2019-07-08 03:00:29 -04:00
if ( fiber & & th - > ec ! = & fiber - > cont . saved_ec ) {
ec_switch ( th , fiber ) ;
2019-06-01 01:48:25 -04:00
}
2017-10-26 04:32:49 -04:00
2018-11-26 14:59:08 -05:00
if ( th - > ec - > trace_arg ! = sec - > trace_arg ) {
rb_raise ( rb_eRuntimeError , " can't call across trace_func " ) ;
}
2019-06-01 01:48:25 -04:00
/* copy vm stack */
2008-11-18 11:19:37 -05:00
# ifdef CAPTURE_JUST_VALID_VM_STACK
2019-06-01 01:48:25 -04:00
MEMCPY ( th - > ec - > vm_stack ,
cont - > saved_vm_stack . ptr ,
VALUE , cont - > saved_vm_stack . slen ) ;
MEMCPY ( th - > ec - > vm_stack + th - > ec - > vm_stack_size - cont - > saved_vm_stack . clen ,
cont - > saved_vm_stack . ptr + cont - > saved_vm_stack . slen ,
VALUE , cont - > saved_vm_stack . clen ) ;
2009-02-05 11:13:54 -05:00
# else
2019-06-01 01:48:25 -04:00
MEMCPY ( th - > ec - > vm_stack , cont - > saved_vm_stack . ptr , VALUE , sec - > vm_stack_size ) ;
2008-11-18 11:19:37 -05:00
# endif
2019-06-01 01:48:25 -04:00
/* other members of ec */
2017-10-26 04:32:49 -04:00
2019-06-01 01:48:25 -04:00
th - > ec - > cfp = sec - > cfp ;
th - > ec - > raised_flag = sec - > raised_flag ;
th - > ec - > tag = sec - > tag ;
th - > ec - > protect_tag = sec - > protect_tag ;
th - > ec - > root_lep = sec - > root_lep ;
th - > ec - > root_svar = sec - > root_svar ;
th - > ec - > ensure_list = sec - > ensure_list ;
th - > ec - > errinfo = sec - > errinfo ;
2017-10-26 04:32:49 -04:00
2019-06-01 01:48:25 -04:00
VM_ASSERT ( th - > ec - > vm_stack ! = NULL ) ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
}
2007-11-08 20:11:49 -05:00
else {
2019-06-01 01:48:25 -04:00
/* fiber */
fiber_restore_thread ( th , ( rb_fiber_t * ) cont ) ;
2007-11-08 20:11:49 -05:00
}
2010-05-05 14:37:37 -04:00
}
2019-07-08 01:59:28 -04:00
NOINLINE ( static void fiber_setcontext ( rb_fiber_t * new_fiber , rb_fiber_t * old_fiber ) ) ;
2010-05-05 14:37:37 -04:00
static void
2019-07-08 01:59:28 -04:00
fiber_setcontext ( rb_fiber_t * new_fiber , rb_fiber_t * old_fiber )
2010-05-05 14:37:37 -04:00
{
2017-09-10 11:49:45 -04:00
rb_thread_t * th = GET_THREAD ( ) ;
2010-05-05 14:37:37 -04:00
2019-07-08 01:59:28 -04:00
/* save old_fiber's machine stack / TODO: is it needed? */
if ( ! FIBER_TERMINATED_P ( old_fiber ) ) {
2019-06-01 01:48:25 -04:00
STACK_GROW_DIR_DETECTION ;
SET_MACHINE_STACK_END ( & th - > ec - > machine . stack_end ) ;
if ( STACK_DIR_UPPER ( 0 , 1 ) ) {
2019-07-08 03:00:29 -04:00
old_fiber - > cont . machine . stack_size = th - > ec - > machine . stack_start - th - > ec - > machine . stack_end ;
old_fiber - > cont . machine . stack = th - > ec - > machine . stack_end ;
2019-06-01 01:48:25 -04:00
}
else {
2019-07-08 03:00:29 -04:00
old_fiber - > cont . machine . stack_size = th - > ec - > machine . stack_end - th - > ec - > machine . stack_start ;
old_fiber - > cont . machine . stack = th - > ec - > machine . stack_start ;
2019-06-01 01:48:25 -04:00
}
2010-05-05 14:37:37 -04:00
}
2017-09-10 11:49:45 -04:00
2019-07-08 01:59:28 -04:00
/* exchange machine_stack_start between old_fiber and new_fiber */
old_fiber - > cont . saved_ec . machine . stack_start = th - > ec - > machine . stack_start ;
2017-09-10 11:49:45 -04:00
2019-07-08 01:59:28 -04:00
/* old_fiber->machine.stack_end should be NULL */
old_fiber - > cont . saved_ec . machine . stack_end = NULL ;
2017-09-10 11:49:45 -04:00
/* restore thread context */
2019-07-08 01:59:28 -04:00
fiber_restore_thread ( th , new_fiber ) ;
2017-09-10 11:49:45 -04:00
2010-05-05 14:37:37 -04:00
/* swap machine context */
2019-07-08 01:59:28 -04:00
coroutine_transfer ( & old_fiber - > context , & new_fiber - > context ) ;
2010-05-05 14:37:37 -04:00
}
NOINLINE ( NORETURN ( static void cont_restore_1 ( rb_context_t * ) ) ) ;
static void
cont_restore_1 ( rb_context_t * cont )
{
cont_restore_thread ( cont ) ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
2007-05-23 18:52:19 -04:00
/* restore machine stack */
2007-07-08 13:19:01 -04:00
# ifdef _M_AMD64
{
2019-06-01 01:48:25 -04:00
/* workaround for x64 SEH */
jmp_buf buf ;
setjmp ( buf ) ;
( ( _JUMP_BUFFER * ) ( & cont - > jmpbuf ) ) - > Frame =
( ( _JUMP_BUFFER * ) ( & buf ) ) - > Frame ;
2007-07-08 13:19:01 -04:00
}
# endif
2014-01-28 01:09:58 -05:00
if ( cont - > machine . stack_src ) {
2019-06-01 01:48:25 -04:00
FLUSH_REGISTER_WINDOWS ;
MEMCPY ( cont - > machine . stack_src , cont - > machine . stack ,
VALUE , cont - > machine . stack_size ) ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
}
2007-05-23 18:52:19 -04:00
ruby_longjmp ( cont - > jmpbuf , 1 ) ;
}
2007-05-27 21:25:55 -04:00
NORETURN ( NOINLINE ( static void cont_restore_0 ( rb_context_t * , VALUE * ) ) ) ;
2007-05-23 18:52:19 -04:00
static void
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
cont_restore_0 ( rb_context_t * cont , VALUE * addr_in_prev_frame )
2007-05-23 18:52:19 -04:00
{
2014-01-28 01:09:58 -05:00
if ( cont - > machine . stack_src ) {
2009-01-16 21:11:38 -05:00
# ifdef HAVE_ALLOCA
# define STACK_PAD_SIZE 1
# else
2007-05-23 18:52:19 -04:00
# define STACK_PAD_SIZE 1024
2009-01-16 21:11:38 -05:00
# endif
2019-06-01 01:48:25 -04:00
VALUE space [ STACK_PAD_SIZE ] ;
2007-05-23 18:52:19 -04:00
2009-01-06 05:09:54 -05:00
# if !STACK_GROW_DIRECTION
2019-06-01 01:48:25 -04:00
if ( addr_in_prev_frame > & space [ 0 ] ) {
/* Stack grows downward */
2009-01-06 05:09:54 -05:00
# endif
# if STACK_GROW_DIRECTION <= 0
2019-06-01 01:48:25 -04:00
volatile VALUE * const end = cont - > machine . stack_src ;
if ( & space [ 0 ] > end ) {
2009-01-06 05:09:54 -05:00
# ifdef HAVE_ALLOCA
2019-06-01 01:48:25 -04:00
volatile VALUE * sp = ALLOCA_N ( VALUE , & space [ 0 ] - end ) ;
space [ 0 ] = * sp ;
2009-01-06 05:09:54 -05:00
# else
2019-06-01 01:48:25 -04:00
cont_restore_0 ( cont , & space [ 0 ] ) ;
2009-01-06 05:09:54 -05:00
# endif
2019-06-01 01:48:25 -04:00
}
2009-01-06 05:09:54 -05:00
# endif
# if !STACK_GROW_DIRECTION
2019-06-01 01:48:25 -04:00
}
else {
/* Stack grows upward */
2009-01-06 05:09:54 -05:00
# endif
# if STACK_GROW_DIRECTION >= 0
2019-06-01 01:48:25 -04:00
volatile VALUE * const end = cont - > machine . stack_src + cont - > machine . stack_size ;
if ( & space [ STACK_PAD_SIZE ] < end ) {
2009-01-06 05:09:54 -05:00
# ifdef HAVE_ALLOCA
2019-06-01 01:48:25 -04:00
volatile VALUE * sp = ALLOCA_N ( VALUE , end - & space [ STACK_PAD_SIZE ] ) ;
space [ 0 ] = * sp ;
2009-01-06 05:09:54 -05:00
# else
2019-06-01 01:48:25 -04:00
cont_restore_0 ( cont , & space [ STACK_PAD_SIZE - 1 ] ) ;
2009-01-06 05:09:54 -05:00
# endif
2019-06-01 01:48:25 -04:00
}
2009-01-06 05:09:54 -05:00
# endif
# if !STACK_GROW_DIRECTION
2019-06-01 01:48:25 -04:00
}
2007-05-23 18:52:19 -04:00
# endif
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
}
cont_restore_1 ( cont ) ;
2007-05-23 18:52:19 -04:00
}
/*
* Document - class : Continuation
*
2012-07-14 04:31:21 -04:00
* Continuation objects are generated by Kernel # callcc ,
* after having + require + d < i > continuation < / i > . They hold
2010-10-26 20:26:29 -04:00
* a return address and execution context , allowing a nonlocal return
2019-03-22 07:04:59 -04:00
* to the end of the # callcc block from anywhere within a
2012-07-14 04:31:21 -04:00
* program . Continuations are somewhat analogous to a structured
2010-10-26 20:26:29 -04:00
* version of C ' s < code > setjmp / longjmp < / code > ( although they contain
* more state , so you might consider them closer to threads ) .
2009-02-22 09:23:33 -05:00
*
2007-05-23 18:52:19 -04:00
* For instance :
2009-02-22 09:23:33 -05:00
*
2010-10-26 20:26:29 -04:00
* require " continuation "
2007-05-23 18:52:19 -04:00
* arr = [ " Freddie " , " Herbie " , " Ron " , " Max " , " Ringo " ]
2010-10-26 20:26:29 -04:00
* callcc { | cc | $ cc = cc }
2007-05-23 18:52:19 -04:00
* puts ( message = arr . shift )
* $ cc . call unless message = ~ / Max /
2009-02-22 09:23:33 -05:00
*
2007-05-23 18:52:19 -04:00
* < em > produces : < / em >
2009-02-22 09:23:33 -05:00
*
2007-05-23 18:52:19 -04:00
* Freddie
* Herbie
* Ron
* Max
2009-02-22 09:23:33 -05:00
*
2015-09-19 21:07:40 -04:00
* Also you can call callcc in other methods :
*
* require " continuation "
*
* def g
* arr = [ " Freddie " , " Herbie " , " Ron " , " Max " , " Ringo " ]
* cc = callcc { | cc | cc }
* puts arr . shift
* return cc , arr . size
* end
*
* def f
* c , size = g
* c . call ( c ) if size > 1
* end
*
* f
*
2007-05-23 18:52:19 -04:00
* This ( somewhat contrived ) example allows the inner loop to abandon
* processing early :
2009-02-22 09:23:33 -05:00
*
2010-10-26 20:26:29 -04:00
* require " continuation "
2007-05-23 18:52:19 -04:00
* callcc { | cont |
* for i in 0. .4
2019-06-01 20:49:58 -04:00
* print " #{i}: "
2007-05-23 18:52:19 -04:00
* for j in i * 5. . . ( i + 1 ) * 5
* cont . call ( ) if j = = 17
* printf " %3d " , j
* end
* end
* }
2010-10-26 20:26:29 -04:00
* puts
2009-02-22 09:23:33 -05:00
*
2007-05-23 18:52:19 -04:00
* < em > produces : < / em >
2009-02-22 09:23:33 -05:00
*
2007-05-23 18:52:19 -04:00
* 0 : 0 1 2 3 4
* 1 : 5 6 7 8 9
* 2 : 10 11 12 13 14
* 3 : 15 16
*/
/*
* call - seq :
2010-05-17 17:07:33 -04:00
* callcc { | cont | block } - > obj
2009-02-22 09:23:33 -05:00
*
2012-07-14 04:31:21 -04:00
* Generates a Continuation object , which it passes to
2010-10-26 20:26:29 -04:00
* the associated block . You need to < code > require
* ' continuation ' < / code > before using this method . Performing a
2012-07-14 04:31:21 -04:00
* < em > cont < / em > < code > . call < / code > will cause the # callcc
2010-10-26 20:26:29 -04:00
* to return ( as will falling through the end of the block ) . The
2012-07-14 04:31:21 -04:00
* value returned by the # callcc is the value of the
2010-10-26 20:26:29 -04:00
* block , or the value passed to < em > cont < / em > < code > . call < / code > . See
2012-07-14 04:31:21 -04:00
* class Continuation for more details . Also see
* Kernel # throw for an alternative mechanism for
2010-10-26 20:26:29 -04:00
* unwinding a call stack .
2007-05-23 18:52:19 -04:00
*/
static VALUE
rb_callcc ( VALUE self )
{
volatile int called ;
volatile VALUE val = cont_capture ( & called ) ;
if ( called ) {
2019-06-01 01:48:25 -04:00
return val ;
2007-05-23 18:52:19 -04:00
}
else {
2019-06-01 01:48:25 -04:00
return rb_yield ( val ) ;
2007-05-23 18:52:19 -04:00
}
}
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
static VALUE
2014-06-18 02:16:39 -04:00
make_passing_arg ( int argc , const VALUE * argv )
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
{
2012-12-29 07:22:04 -05:00
switch ( argc ) {
2018-12-28 08:03:09 -05:00
case - 1 :
2019-06-01 01:48:25 -04:00
return argv [ 0 ] ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
case 0 :
2019-06-01 01:48:25 -04:00
return Qnil ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
case 1 :
2019-06-01 01:48:25 -04:00
return argv [ 0 ] ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
default :
2019-06-01 01:48:25 -04:00
return rb_ary_new4 ( argc , argv ) ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
}
}
2013-11-15 12:15:31 -05:00
/* CAUTION!! : Currently, error in rollback_func is not supported */
/* same as rb_protect if set rollback_func to NULL */
void
ruby_register_rollback_func_for_ensure ( VALUE ( * ensure_func ) ( ANYARGS ) , VALUE ( * rollback_func ) ( ANYARGS ) )
{
st_table * * table_p = & GET_VM ( ) - > ensure_rollback_table ;
if ( UNLIKELY ( * table_p = = NULL ) ) {
2019-06-01 01:48:25 -04:00
* table_p = st_init_numtable ( ) ;
2013-11-15 12:15:31 -05:00
}
st_insert ( * table_p , ( st_data_t ) ensure_func , ( st_data_t ) rollback_func ) ;
}
static inline VALUE
lookup_rollback_func ( VALUE ( * ensure_func ) ( ANYARGS ) )
{
st_table * table = GET_VM ( ) - > ensure_rollback_table ;
st_data_t val ;
if ( table & & st_lookup ( table , ( st_data_t ) ensure_func , & val ) )
2019-06-01 01:48:25 -04:00
return ( VALUE ) val ;
2013-11-15 12:15:31 -05:00
return Qundef ;
}
static inline void
rollback_ensure_stack ( VALUE self , rb_ensure_list_t * current , rb_ensure_entry_t * target )
{
rb_ensure_list_t * p ;
rb_ensure_entry_t * entry ;
2018-11-12 19:40:52 -05:00
size_t i , j ;
2013-11-15 12:15:31 -05:00
size_t cur_size ;
size_t target_size ;
size_t base_point ;
VALUE ( * func ) ( ANYARGS ) ;
cur_size = 0 ;
for ( p = current ; p ; p = p - > next )
2019-06-01 01:48:25 -04:00
cur_size + + ;
2013-11-15 12:15:31 -05:00
target_size = 0 ;
for ( entry = target ; entry - > marker ; entry + + )
2019-06-01 01:48:25 -04:00
target_size + + ;
2013-11-15 12:15:31 -05:00
/* search common stack point */
p = current ;
base_point = cur_size ;
while ( base_point ) {
2019-06-01 01:48:25 -04:00
if ( target_size > = base_point & &
p - > entry . marker = = target [ target_size - base_point ] . marker )
break ;
base_point - - ;
p = p - > next ;
2013-11-15 12:15:31 -05:00
}
/* rollback function check */
for ( i = 0 ; i < target_size - base_point ; i + + ) {
2019-06-01 01:48:25 -04:00
if ( ! lookup_rollback_func ( target [ i ] . e_proc ) ) {
rb_raise ( rb_eRuntimeError , " continuation called from out of critical rb_ensure scope " ) ;
}
2013-11-15 12:15:31 -05:00
}
/* pop ensure stack */
while ( cur_size > base_point ) {
2019-06-01 01:48:25 -04:00
/* escape from ensure block */
( * current - > entry . e_proc ) ( current - > entry . data2 ) ;
current = current - > next ;
cur_size - - ;
2013-11-15 12:15:31 -05:00
}
/* push ensure stack */
2018-11-12 19:40:52 -05:00
for ( j = 0 ; j < i ; j + + ) {
func = ( VALUE ( * ) ( ANYARGS ) ) lookup_rollback_func ( target [ i - j - 1 ] . e_proc ) ;
if ( ( VALUE ) func ! = Qundef ) {
( * func ) ( target [ i - j - 1 ] . data2 ) ;
}
2013-11-15 12:15:31 -05:00
}
}
2007-05-23 18:52:19 -04:00
/*
* call - seq :
* cont . call ( args , . . . )
* cont [ args , . . . ]
2009-02-22 09:23:33 -05:00
*
2019-03-22 07:04:59 -04:00
* Invokes the continuation . The program continues from the end of
* the # callcc block . If no arguments are given , the original # callcc
* returns + nil + . If one argument is given , # callcc returns
* it . Otherwise , an array containing < i > args < / i > is returned .
2009-02-22 09:23:33 -05:00
*
2007-05-23 18:52:19 -04:00
* callcc { | cont | cont . call } # = > nil
* callcc { | cont | cont . call 1 } # = > 1
* callcc { | cont | cont . call 1 , 2 , 3 } # = > [ 1 , 2 , 3 ]
*/
static VALUE
rb_cont_call ( int argc , VALUE * argv , VALUE contval )
{
2018-08-20 21:01:37 -04:00
rb_context_t * cont = cont_ptr ( contval ) ;
2007-05-23 18:52:19 -04:00
rb_thread_t * th = GET_THREAD ( ) ;
2017-09-10 15:00:08 -04:00
if ( cont_thread_value ( cont ) ! = th - > self ) {
2019-06-01 01:48:25 -04:00
rb_raise ( rb_eRuntimeError , " continuation called across threads " ) ;
2007-05-23 18:52:19 -04:00
}
2017-10-26 04:32:49 -04:00
if ( cont - > saved_ec . protect_tag ! = th - > ec - > protect_tag ) {
2019-06-01 01:48:25 -04:00
rb_raise ( rb_eRuntimeError , " continuation called across stack rewinding barrier " ) ;
2010-01-25 13:22:58 -05:00
}
2017-11-06 00:41:48 -05:00
if ( cont - > saved_ec . fiber_ptr ) {
2019-06-01 01:48:25 -04:00
if ( th - > ec - > fiber_ptr ! = cont - > saved_ec . fiber_ptr ) {
rb_raise ( rb_eRuntimeError , " continuation called across fiber " ) ;
}
2007-06-05 21:55:09 -04:00
}
2017-10-26 04:32:49 -04:00
rollback_ensure_stack ( contval , th - > ec - > ensure_list , cont - > ensure_array ) ;
2007-05-23 18:52:19 -04:00
2008-11-30 22:00:48 -05:00
cont - > argc = argc ;
2007-06-02 03:48:29 -04:00
cont - > value = make_passing_arg ( argc , argv ) ;
2007-05-23 18:52:19 -04:00
2007-08-23 03:55:37 -04:00
cont_restore_0 ( cont , & contval ) ;
2007-05-23 18:52:19 -04:00
return Qnil ; /* unreachable */
}
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
/*********/
/* fiber */
/*********/
2008-12-26 19:25:47 -05:00
/*
* Document - class : Fiber
*
* Fibers are primitives for implementing light weight cooperative
2009-02-22 09:23:33 -05:00
* concurrency in Ruby . Basically they are a means of creating code blocks
* that can be paused and resumed , much like threads . The main difference
* is that they are never preempted and that the scheduling must be done by
* the programmer and not the VM .
2008-12-26 19:25:47 -05:00
*
* As opposed to other stackless light weight concurrency models , each fiber
2016-12-27 03:52:32 -05:00
* comes with a stack . This enables the fiber to be paused from deeply
* nested function calls within the fiber block . See the ruby ( 1 )
* manpage to configure the size of the fiber stack ( s ) .
2008-12-26 19:25:47 -05:00
*
2015-12-10 00:16:17 -05:00
* When a fiber is created it will not run automatically . Rather it must
2019-03-22 07:04:59 -04:00
* be explicitly asked to run using the Fiber # resume method .
2009-02-22 09:23:33 -05:00
* The code running inside the fiber can give up control by calling
2019-03-22 07:04:59 -04:00
* Fiber . yield in which case it yields control back to caller ( the
* caller of the Fiber # resume ) .
2009-02-22 09:23:33 -05:00
*
* Upon yielding or termination the Fiber returns the value of the last
2008-12-26 19:25:47 -05:00
* executed expression
2009-02-22 09:23:33 -05:00
*
2008-12-26 19:25:47 -05:00
* For instance :
2009-02-22 09:23:33 -05:00
*
2008-12-26 19:25:47 -05:00
* fiber = Fiber . new do
* Fiber . yield 1
* 2
* end
*
* puts fiber . resume
* puts fiber . resume
* puts fiber . resume
2009-02-22 09:23:33 -05:00
*
2008-12-26 19:25:47 -05:00
* < em > produces < / em >
2009-02-22 09:23:33 -05:00
*
2008-12-26 19:25:47 -05:00
* 1
* 2
* FiberError : dead fiber called
2009-02-22 09:23:33 -05:00
*
2019-03-22 07:04:59 -04:00
* The Fiber # resume method accepts an arbitrary number of parameters ,
* if it is the first call to # resume then they will be passed as
* block arguments . Otherwise they will be the return value of the
* call to Fiber . yield
2008-12-26 19:25:47 -05:00
*
* Example :
2009-02-22 09:23:33 -05:00
*
2008-12-26 19:25:47 -05:00
* fiber = Fiber . new do | first |
* second = Fiber . yield first + 2
* end
*
* puts fiber . resume 10
* puts fiber . resume 14
* puts fiber . resume 18
*
* < em > produces < / em >
2009-02-22 09:23:33 -05:00
*
2008-12-26 19:25:47 -05:00
* 12
* 14
* FiberError : dead fiber called
*
*/
2009-09-08 11:27:31 -04:00
static const rb_data_type_t fiber_data_type = {
" fiber " ,
2019-05-31 16:25:24 -04:00
{ fiber_mark , fiber_free , fiber_memsize , fiber_compact , } ,
2014-12-01 01:38:04 -05:00
0 , 0 , RUBY_TYPED_FREE_IMMEDIATELY
2009-09-08 11:27:31 -04:00
} ;
2008-11-28 10:23:09 -05:00
static VALUE
2007-11-08 20:11:49 -05:00
fiber_alloc ( VALUE klass )
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
{
2009-09-08 11:27:31 -04:00
return TypedData_Wrap_Struct ( klass , & fiber_data_type , 0 ) ;
2008-11-28 10:23:09 -05:00
}
2007-11-08 20:11:49 -05:00
2008-11-28 10:23:09 -05:00
static rb_fiber_t *
2019-07-08 01:59:28 -04:00
fiber_t_alloc ( VALUE fiber_value )
2008-11-28 10:23:09 -05:00
{
2019-07-08 01:59:28 -04:00
rb_fiber_t * fiber ;
2009-09-20 21:13:24 -04:00
rb_thread_t * th = GET_THREAD ( ) ;
2008-11-28 10:23:09 -05:00
2019-07-08 01:59:28 -04:00
if ( DATA_PTR ( fiber_value ) ! = 0 ) {
2019-06-01 01:48:25 -04:00
rb_raise ( rb_eRuntimeError , " cannot initialize twice " ) ;
2010-11-03 13:08:35 -04:00
}
2009-09-20 21:13:24 -04:00
THREAD_MUST_BE_RUNNING ( th ) ;
2019-07-08 01:59:28 -04:00
fiber = ZALLOC ( rb_fiber_t ) ;
fiber - > cont . self = fiber_value ;
fiber - > cont . type = FIBER_CONTEXT ;
cont_init ( & fiber - > cont , th ) ;
fiber - > cont . saved_ec . fiber_ptr = fiber ;
fiber - > prev = NULL ;
2017-08-09 21:47:13 -04:00
2019-07-08 01:59:28 -04:00
/* fiber->status == 0 == CREATED
* So that we don ' t need to set status : fiber_status_set ( fiber , FIBER_CREATED ) ; */
VM_ASSERT ( FIBER_CREATED_P ( fiber ) ) ;
2007-11-08 20:11:49 -05:00
2019-07-08 01:59:28 -04:00
DATA_PTR ( fiber_value ) = fiber ;
2008-11-28 10:23:09 -05:00
2019-07-08 01:59:28 -04:00
return fiber ;
2007-11-08 20:11:49 -05:00
}
2016-07-28 07:02:30 -04:00
rb_control_frame_t *
2017-09-10 15:00:08 -04:00
rb_vm_push_frame ( rb_execution_context_t * sec ,
2019-06-01 01:48:25 -04:00
const rb_iseq_t * iseq ,
VALUE type ,
VALUE self ,
VALUE specval ,
VALUE cref_or_me ,
const VALUE * pc ,
VALUE * sp ,
int local_size ,
int stack_max ) ;
2016-07-28 07:02:30 -04:00
2007-11-08 20:11:49 -05:00
static VALUE
2019-06-01 20:49:58 -04:00
fiber_initialize ( VALUE self , VALUE proc , struct fiber_pool * fiber_pool )
{
rb_fiber_t * fiber = fiber_t_alloc ( self ) ;
fiber - > first_proc = proc ;
fiber - > stack . base = NULL ;
fiber - > stack . pool = fiber_pool ;
return self ;
}
static void
fiber_prepare_stack ( rb_fiber_t * fiber )
2007-11-08 20:11:49 -05:00
{
2019-07-08 01:59:28 -04:00
rb_context_t * cont = & fiber - > cont ;
2017-09-10 15:00:08 -04:00
rb_execution_context_t * sec = & cont - > saved_ec ;
2019-06-01 20:49:58 -04:00
size_t vm_stack_size = 0 ;
2019-06-27 02:59:25 -04:00
VALUE * vm_stack = fiber_initialize_coroutine ( fiber , & vm_stack_size ) ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
2008-10-22 11:12:07 -04:00
/* initialize cont */
2017-08-21 20:41:24 -04:00
cont - > saved_vm_stack . ptr = NULL ;
2019-06-01 20:49:58 -04:00
rb_ec_initialize_vm_stack ( sec , vm_stack , vm_stack_size / sizeof ( VALUE ) ) ;
2016-07-28 07:02:30 -04:00
2017-09-10 15:00:08 -04:00
sec - > tag = NULL ;
sec - > local_storage = NULL ;
sec - > local_storage_recursive_hash = Qnil ;
sec - > local_storage_recursive_hash_for_trace = Qnil ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
}
2009-09-21 07:06:32 -04:00
/* :nodoc: */
2008-11-28 10:23:09 -05:00
static VALUE
2019-06-01 20:49:58 -04:00
rb_fiber_initialize ( int argc , VALUE * argv , VALUE self )
2007-08-25 23:31:20 -04:00
{
2019-06-01 20:49:58 -04:00
return fiber_initialize ( self , rb_block_proc ( ) , & shared_fiber_pool ) ;
2007-08-25 23:31:20 -04:00
}
2008-11-28 10:23:09 -05:00
VALUE
rb_fiber_new ( VALUE ( * func ) ( ANYARGS ) , VALUE obj )
2007-08-25 23:31:20 -04:00
{
2019-06-01 20:49:58 -04:00
return fiber_initialize ( fiber_alloc ( rb_cFiber ) , rb_proc_new ( func , obj ) , & shared_fiber_pool ) ;
2007-08-25 23:31:20 -04:00
}
2019-07-08 01:59:28 -04:00
static void rb_fiber_terminate ( rb_fiber_t * fiber , int need_interrupt ) ;
2007-08-21 14:51:39 -04:00
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
void
rb_fiber_start ( void )
{
2017-10-26 04:32:49 -04:00
rb_thread_t * volatile th = GET_THREAD ( ) ;
2019-07-08 01:59:28 -04:00
rb_fiber_t * fiber = th - > ec - > fiber_ptr ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
rb_proc_t * proc ;
2017-06-23 03:25:52 -04:00
enum ruby_tag_type state ;
2017-11-06 02:44:28 -05:00
int need_interrupt = TRUE ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
2017-10-26 04:32:49 -04:00
VM_ASSERT ( th - > ec = = ruby_current_execution_context_ptr ) ;
2019-07-08 01:59:28 -04:00
VM_ASSERT ( FIBER_RESUMED_P ( fiber ) ) ;
2017-08-09 21:47:13 -04:00
2017-10-26 07:02:13 -04:00
EC_PUSH_TAG ( th - > ec ) ;
2017-12-05 22:16:08 -05:00
if ( ( state = EC_EXEC_TAG ( ) ) = = TAG_NONE ) {
2019-07-08 03:00:29 -04:00
rb_context_t * cont = & VAR_FROM_MEMORY ( fiber ) - > cont ;
2019-06-01 01:48:25 -04:00
int argc ;
const VALUE * argv , args = cont - > value ;
2019-07-08 03:00:29 -04:00
GetProcPtr ( fiber - > first_proc , proc ) ;
2019-06-01 01:48:25 -04:00
argv = ( argc = cont - > argc ) > 1 ? RARRAY_CONST_PTR ( args ) : & args ;
cont - > value = Qnil ;
th - > ec - > errinfo = Qnil ;
2019-07-08 03:00:29 -04:00
th - > ec - > root_lep = rb_vm_proc_local_ep ( fiber - > first_proc ) ;
2019-06-01 01:48:25 -04:00
th - > ec - > root_svar = Qfalse ;
2015-08-21 05:51:01 -04:00
2019-06-01 01:48:25 -04:00
EXEC_EVENT_HOOK ( th - > ec , RUBY_EVENT_FIBER_SWITCH , th - > self , 0 , 0 , 0 , Qnil ) ;
cont - > value = rb_vm_invoke_proc ( th - > ec , proc , argc , argv , VM_BLOCK_HANDLER_NONE ) ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
}
2017-10-26 07:02:13 -04:00
EC_POP_TAG ( ) ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
if ( state ) {
2019-06-01 01:48:25 -04:00
VALUE err = th - > ec - > errinfo ;
2019-07-08 03:00:29 -04:00
VM_ASSERT ( FIBER_RESUMED_P ( fiber ) ) ;
2017-08-09 21:47:13 -04:00
2019-06-01 01:48:25 -04:00
if ( state = = TAG_RAISE | | state = = TAG_FATAL ) {
rb_threadptr_pending_interrupt_enque ( th , err ) ;
}
else {
err = rb_vm_make_jump_tag_but_local_jump ( state , err ) ;
if ( ! NIL_P ( err ) ) {
rb_threadptr_pending_interrupt_enque ( th , err ) ;
}
}
need_interrupt = TRUE ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
}
2019-07-08 01:59:28 -04:00
rb_fiber_terminate ( fiber , need_interrupt ) ;
2017-08-10 02:26:52 -04:00
VM_UNREACHABLE ( rb_fiber_start ) ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
}
2008-10-22 11:12:07 -04:00
static rb_fiber_t *
root_fiber_alloc ( rb_thread_t * th )
{
2019-07-08 01:59:28 -04:00
VALUE fiber_value = fiber_alloc ( rb_cFiber ) ;
rb_fiber_t * fiber = th - > ec - > fiber_ptr ;
2017-10-26 04:32:49 -04:00
2019-07-08 01:59:28 -04:00
VM_ASSERT ( DATA_PTR ( fiber_value ) = = NULL ) ;
VM_ASSERT ( fiber - > cont . type = = FIBER_CONTEXT ) ;
VM_ASSERT ( fiber - > status = = FIBER_RESUMED ) ;
2017-10-26 04:32:49 -04:00
2019-07-08 01:59:28 -04:00
th - > root_fiber = fiber ;
DATA_PTR ( fiber_value ) = fiber ;
fiber - > cont . self = fiber_value ;
2018-04-04 04:19:28 -04:00
2019-06-27 02:59:25 -04:00
# ifdef COROUTINE_PRIVATE_STACK
fiber - > stack = fiber_pool_stack_acquire ( & shared_fiber_pool ) ;
coroutine_initialize_main ( & fiber - > context , fiber_pool_stack_base ( & fiber - > stack ) , fiber - > stack . available , th - > ec - > machine . stack_start ) ;
# else
2019-07-08 01:59:28 -04:00
coroutine_initialize_main ( & fiber - > context ) ;
2019-06-27 02:59:25 -04:00
# endif
2018-04-04 04:19:28 -04:00
2019-07-08 01:59:28 -04:00
return fiber ;
2008-10-22 11:12:07 -04:00
}
2017-10-26 04:32:49 -04:00
void
2018-04-04 04:19:28 -04:00
rb_threadptr_root_fiber_setup ( rb_thread_t * th )
2017-10-26 04:32:49 -04:00
{
2019-07-08 01:59:28 -04:00
rb_fiber_t * fiber = ruby_mimmalloc ( sizeof ( rb_fiber_t ) ) ;
MEMZERO ( fiber , rb_fiber_t , 1 ) ;
fiber - > cont . type = FIBER_CONTEXT ;
fiber - > cont . saved_ec . fiber_ptr = fiber ;
fiber - > cont . saved_ec . thread_ptr = th ;
fiber_status_set ( fiber , FIBER_RESUMED ) ; /* skip CREATED */
th - > ec = & fiber - > cont . saved_ec ;
2017-10-26 04:32:49 -04:00
}
2017-10-26 10:21:31 -04:00
void
rb_threadptr_root_fiber_release ( rb_thread_t * th )
{
if ( th - > root_fiber ) {
2019-06-01 01:48:25 -04:00
/* ignore. A root fiber object will free th->ec */
2017-10-26 10:21:31 -04:00
}
else {
2019-06-01 01:48:25 -04:00
VM_ASSERT ( th - > ec - > fiber_ptr - > cont . type = = FIBER_CONTEXT ) ;
VM_ASSERT ( th - > ec - > fiber_ptr - > cont . self = = 0 ) ;
fiber_free ( th - > ec - > fiber_ptr ) ;
2019-06-05 07:39:17 -04:00
2019-06-01 01:48:25 -04:00
if ( th - > ec = = ruby_current_execution_context_ptr ) {
ruby_current_execution_context_ptr = NULL ;
}
th - > ec = NULL ;
2017-10-26 10:21:31 -04:00
}
}
2019-06-20 04:29:35 -04:00
void
rb_threadptr_root_fiber_terminate ( rb_thread_t * th )
{
rb_fiber_t * fiber = th - > ec - > fiber_ptr ;
fiber - > status = FIBER_TERMINATED ;
// The vm_stack is `alloca`ed on the thread stack, so it's gone too:
rb_ec_clear_vm_stack ( th - > ec ) ;
}
2014-10-15 18:35:08 -04:00
static inline rb_fiber_t *
fiber_current ( void )
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
{
2017-11-06 03:22:27 -05:00
rb_execution_context_t * ec = GET_EC ( ) ;
if ( ec - > fiber_ptr - > cont . self = = 0 ) {
2019-06-01 01:48:25 -04:00
root_fiber_alloc ( rb_ec_thread_ptr ( ec ) ) ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
}
2017-11-06 03:22:27 -05:00
return ec - > fiber_ptr ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
}
2014-10-15 18:35:08 -04:00
static inline rb_fiber_t *
return_fiber ( void )
{
2019-07-08 01:59:28 -04:00
rb_fiber_t * fiber = fiber_current ( ) ;
rb_fiber_t * prev = fiber - > prev ;
2014-10-15 18:35:08 -04:00
if ( ! prev ) {
2019-06-01 01:48:25 -04:00
rb_thread_t * th = GET_THREAD ( ) ;
rb_fiber_t * root_fiber = th - > root_fiber ;
2017-10-26 10:38:22 -04:00
2019-06-01 01:48:25 -04:00
VM_ASSERT ( root_fiber ! = NULL ) ;
2014-10-15 18:35:08 -04:00
2019-07-08 03:00:29 -04:00
if ( root_fiber = = fiber ) {
2019-06-01 01:48:25 -04:00
rb_raise ( rb_eFiberError , " can't yield from root fiber " ) ;
}
return root_fiber ;
2014-10-15 18:35:08 -04:00
}
else {
2019-07-08 03:00:29 -04:00
fiber - > prev = NULL ;
2019-06-01 01:48:25 -04:00
return prev ;
2014-10-15 18:35:08 -04:00
}
}
VALUE
rb_fiber_current ( void )
{
return fiber_current ( ) - > cont . self ;
}
2019-06-01 20:49:58 -04:00
static void
fiber_stack_release ( rb_fiber_t * fiber )
{
rb_execution_context_t * ec = & fiber - > cont . saved_ec ;
if ( fiber - > stack . base ) {
fiber_pool_stack_release ( fiber - > stack ) ;
fiber - > stack . base = NULL ;
}
// The stack is no longer associated with this execution context:
rb_ec_clear_vm_stack ( ec ) ;
}
2014-10-15 18:35:08 -04:00
static inline VALUE
2019-07-08 01:59:28 -04:00
fiber_store ( rb_fiber_t * next_fiber , rb_thread_t * th )
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
{
2019-07-08 01:59:28 -04:00
rb_fiber_t * fiber ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
2017-11-06 00:41:48 -05:00
if ( th - > ec - > fiber_ptr ! = NULL ) {
2019-07-08 01:59:28 -04:00
fiber = th - > ec - > fiber_ptr ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
}
else {
2018-11-21 21:17:44 -05:00
/* create root fiber */
2019-07-08 01:59:28 -04:00
fiber = root_fiber_alloc ( th ) ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
}
2019-07-08 01:59:28 -04:00
if ( FIBER_CREATED_P ( next_fiber ) ) {
2019-06-01 20:49:58 -04:00
fiber_prepare_stack ( next_fiber ) ;
2017-08-09 21:47:13 -04:00
}
2019-06-01 20:49:58 -04:00
VM_ASSERT ( FIBER_RESUMED_P ( fiber ) | | FIBER_TERMINATED_P ( fiber ) ) ;
VM_ASSERT ( FIBER_RUNNABLE_P ( next_fiber ) ) ;
2019-07-08 01:59:28 -04:00
if ( FIBER_RESUMED_P ( fiber ) ) fiber_status_set ( fiber , FIBER_SUSPENDED ) ;
2017-09-10 14:37:55 -04:00
2019-07-08 01:59:28 -04:00
fiber_status_set ( next_fiber , FIBER_RESUMED ) ;
fiber_setcontext ( next_fiber , fiber ) ;
2019-06-01 01:48:25 -04:00
2019-07-08 01:59:28 -04:00
fiber = th - > ec - > fiber_ptr ;
2019-06-01 20:49:58 -04:00
/* Raise an exception if that was the result of executing the fiber */
2019-07-08 01:59:28 -04:00
if ( fiber - > cont . argc = = - 1 ) rb_exc_raise ( fiber - > cont . value ) ;
2019-06-01 20:49:58 -04:00
2019-07-08 01:59:28 -04:00
return fiber - > cont . value ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
}
2007-08-21 14:51:39 -04:00
static inline VALUE
2019-07-08 01:59:28 -04:00
fiber_switch ( rb_fiber_t * fiber , int argc , const VALUE * argv , int is_resume )
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
{
2007-06-02 03:48:29 -04:00
VALUE value ;
2019-07-08 01:59:28 -04:00
rb_context_t * cont = & fiber - > cont ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
rb_thread_t * th = GET_THREAD ( ) ;
2017-10-26 10:38:22 -04:00
/* make sure the root_fiber object is available */
if ( th - > root_fiber = = NULL ) root_fiber_alloc ( th ) ;
2019-07-08 01:59:28 -04:00
if ( th - > ec - > fiber_ptr = = fiber ) {
2019-06-01 01:48:25 -04:00
/* ignore fiber context switch
2011-11-20 16:17:57 -05:00
* because destination fiber is same as current fiber
2019-06-01 01:48:25 -04:00
*/
return make_passing_arg ( argc , argv ) ;
2011-11-20 16:17:57 -05:00
}
2017-09-10 15:00:08 -04:00
if ( cont_thread_value ( cont ) ! = th - > self ) {
2019-06-01 01:48:25 -04:00
rb_raise ( rb_eFiberError , " fiber called across threads " ) ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
}
2017-10-26 04:32:49 -04:00
else if ( cont - > saved_ec . protect_tag ! = th - > ec - > protect_tag ) {
2019-06-01 01:48:25 -04:00
rb_raise ( rb_eFiberError , " fiber called across stack rewinding barrier " ) ;
2010-01-25 13:22:58 -05:00
}
2019-07-08 01:59:28 -04:00
else if ( FIBER_TERMINATED_P ( fiber ) ) {
2019-06-01 01:48:25 -04:00
value = rb_exc_new2 ( rb_eFiberError , " dead fiber called " ) ;
if ( ! FIBER_TERMINATED_P ( th - > ec - > fiber_ptr ) ) {
rb_exc_raise ( value ) ;
VM_UNREACHABLE ( fiber_switch ) ;
}
else {
/* th->ec->fiber_ptr is also dead => switch to root fiber */
/* (this means we're being called from rb_fiber_terminate, */
/* and the terminated fiber's return_fiber() is already dead) */
VM_ASSERT ( FIBER_SUSPENDED_P ( th - > root_fiber ) ) ;
cont = & th - > root_fiber - > cont ;
cont - > argc = - 1 ;
cont - > value = value ;
fiber_setcontext ( th - > root_fiber , th - > ec - > fiber_ptr ) ;
VM_UNREACHABLE ( fiber_switch ) ;
}
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
}
2007-08-21 14:51:39 -04:00
if ( is_resume ) {
2019-07-08 03:00:29 -04:00
fiber - > prev = fiber_current ( ) ;
2007-08-21 14:51:39 -04:00
}
2007-08-25 04:51:59 -04:00
2019-07-08 01:59:28 -04:00
VM_ASSERT ( FIBER_RUNNABLE_P ( fiber ) ) ;
2017-08-09 21:47:13 -04:00
2008-11-30 22:00:48 -05:00
cont - > argc = argc ;
2007-06-02 03:48:29 -04:00
cont - > value = make_passing_arg ( argc , argv ) ;
2019-06-01 20:49:58 -04:00
2019-07-08 01:59:28 -04:00
value = fiber_store ( fiber , th ) ;
2019-06-01 20:49:58 -04:00
if ( is_resume & & FIBER_TERMINATED_P ( fiber ) ) {
fiber_stack_release ( fiber ) ;
}
2017-11-06 02:44:28 -05:00
RUBY_VM_CHECK_INTS ( th - > ec ) ;
2007-08-21 14:51:39 -04:00
2017-10-29 09:19:14 -04:00
EXEC_EVENT_HOOK ( th - > ec , RUBY_EVENT_FIBER_SWITCH , th - > self , 0 , 0 , 0 , Qnil ) ;
2015-08-21 05:51:01 -04:00
2007-06-02 03:48:29 -04:00
return value ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
}
2007-08-21 14:51:39 -04:00
VALUE
2019-07-08 01:59:28 -04:00
rb_fiber_transfer ( VALUE fiber_value , int argc , const VALUE * argv )
2007-08-15 13:56:22 -04:00
{
2019-07-08 01:59:28 -04:00
return fiber_switch ( fiber_ptr ( fiber_value ) , argc , argv , 0 ) ;
2007-08-15 13:56:22 -04:00
}
2017-10-26 04:32:49 -04:00
void
2019-07-08 01:59:28 -04:00
rb_fiber_close ( rb_fiber_t * fiber )
2017-10-26 04:32:49 -04:00
{
2019-07-08 01:59:28 -04:00
fiber_status_set ( fiber , FIBER_TERMINATED ) ;
2019-06-01 20:49:58 -04:00
fiber_stack_release ( fiber ) ;
2017-10-26 04:32:49 -04:00
}
2014-10-15 18:35:08 -04:00
static void
2019-07-08 01:59:28 -04:00
rb_fiber_terminate ( rb_fiber_t * fiber , int need_interrupt )
2014-10-15 18:35:08 -04:00
{
2019-07-08 01:59:28 -04:00
VALUE value = fiber - > cont . value ;
2019-06-01 20:49:58 -04:00
rb_fiber_t * next_fiber ;
2017-08-09 21:47:13 -04:00
2019-07-08 01:59:28 -04:00
VM_ASSERT ( FIBER_RESUMED_P ( fiber ) ) ;
rb_fiber_close ( fiber ) ;
2017-10-26 04:32:49 -04:00
2019-07-08 01:59:28 -04:00
coroutine_destroy ( & fiber - > context ) ;
2018-11-20 05:18:08 -05:00
2019-07-08 01:59:28 -04:00
fiber - > cont . machine . stack = NULL ;
fiber - > cont . machine . stack_size = 0 ;
2017-10-26 04:32:49 -04:00
2019-06-01 20:49:58 -04:00
next_fiber = return_fiber ( ) ;
if ( need_interrupt ) RUBY_VM_SET_INTERRUPT ( & next_fiber - > cont . saved_ec ) ;
fiber_switch ( next_fiber , 1 , & value , 0 ) ;
2014-10-15 18:35:08 -04:00
}
2007-08-21 14:51:39 -04:00
VALUE
2019-07-08 01:59:28 -04:00
rb_fiber_resume ( VALUE fiber_value , int argc , const VALUE * argv )
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
{
2019-07-08 01:59:28 -04:00
rb_fiber_t * fiber = fiber_ptr ( fiber_value ) ;
2007-08-21 14:51:39 -04:00
2019-07-08 01:59:28 -04:00
if ( argc = = - 1 & & FIBER_CREATED_P ( fiber ) ) {
2018-12-28 08:03:14 -05:00
rb_raise ( rb_eFiberError , " cannot raise exception on unborn fiber " ) ;
}
2019-07-08 01:59:28 -04:00
if ( fiber - > prev ! = 0 | | fiber_is_root_p ( fiber ) ) {
2019-06-01 01:48:25 -04:00
rb_raise ( rb_eFiberError , " double resume " ) ;
2007-08-21 14:51:39 -04:00
}
2018-12-28 08:03:14 -05:00
2019-07-08 01:59:28 -04:00
if ( fiber - > transferred ! = 0 ) {
2019-06-01 01:48:25 -04:00
rb_raise ( rb_eFiberError , " cannot resume transferred Fiber " ) ;
2011-11-08 23:26:39 -05:00
}
2007-08-21 14:51:39 -04:00
2019-07-08 01:59:28 -04:00
return fiber_switch ( fiber , argc , argv , 1 ) ;
2007-08-21 14:51:39 -04:00
}
VALUE
2014-06-18 02:16:39 -04:00
rb_fiber_yield ( int argc , const VALUE * argv )
2007-08-21 14:51:39 -04:00
{
2014-10-15 18:35:08 -04:00
return fiber_switch ( return_fiber ( ) , argc , argv , 0 ) ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
}
2012-02-15 09:00:11 -05:00
void
2018-11-06 05:19:55 -05:00
rb_fiber_reset_root_local_storage ( rb_thread_t * th )
2012-02-15 09:00:11 -05:00
{
2017-11-06 00:41:48 -05:00
if ( th - > root_fiber & & th - > root_fiber ! = th - > ec - > fiber_ptr ) {
2019-06-01 01:48:25 -04:00
th - > ec - > local_storage = th - > root_fiber - > cont . saved_ec . local_storage ;
2012-02-15 09:00:11 -05:00
}
}
2008-12-26 19:25:47 -05:00
/*
* call - seq :
* fiber . alive ? - > true or false
2009-02-22 09:23:33 -05:00
*
2010-10-26 20:26:29 -04:00
* Returns true if the fiber can still be resumed ( or transferred
* to ) . After finishing execution of the fiber block this method will
* always return false . You need to < code > require ' fiber ' < / code >
* before using this method .
2008-12-26 19:25:47 -05:00
*/
2007-08-06 12:41:17 -04:00
VALUE
2019-07-08 01:59:28 -04:00
rb_fiber_alive_p ( VALUE fiber_value )
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
{
2019-07-08 01:59:28 -04:00
return FIBER_TERMINATED_P ( fiber_ptr ( fiber_value ) ) ? Qfalse : Qtrue ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
}
2008-12-26 19:25:47 -05:00
/*
* call - seq :
* fiber . resume ( args , . . . ) - > obj
2009-02-22 09:23:33 -05:00
*
2019-03-22 07:04:59 -04:00
* Resumes the fiber from the point at which the last Fiber . yield was
* called , or starts running it if it is the first call to
* # resume . Arguments passed to resume will be the value of the
* Fiber . yield expression or will be passed as block parameters to
* the fiber ' s block if this is the first # resume .
2009-02-22 09:23:33 -05:00
*
2008-12-26 19:25:47 -05:00
* Alternatively , when resume is called it evaluates to the arguments passed
2019-03-22 07:04:59 -04:00
* to the next Fiber . yield statement inside the fiber ' s block
2008-12-26 19:25:47 -05:00
* or to the block value if it runs to completion without any
2019-03-22 07:04:59 -04:00
* Fiber . yield
2008-12-26 19:25:47 -05:00
*/
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
static VALUE
2019-07-08 01:59:28 -04:00
rb_fiber_m_resume ( int argc , VALUE * argv , VALUE fiber )
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
{
2019-07-08 01:59:28 -04:00
return rb_fiber_resume ( fiber , argc , argv ) ;
2007-08-21 14:51:39 -04:00
}
2018-12-28 08:03:09 -05:00
/*
* call - seq :
* fiber . raise - > obj
* fiber . raise ( string ) - > obj
* fiber . raise ( exception [ , string [ , array ] ] ) - > obj
*
* Raises an exception in the fiber at the point at which the last
2019-03-22 07:04:59 -04:00
* Fiber . yield was called , or at the start if neither + resume +
2018-12-28 08:03:09 -05:00
* nor + raise + were called before .
*
* With no arguments , raises a + RuntimeError + . With a single + String +
* argument , raises a + RuntimeError + with the string as a message . Otherwise ,
* the first parameter should be the name of an + Exception + class ( or an
* object that returns an + Exception + object when sent an + exception +
* message ) . The optional second parameter sets the message associated with
* the exception , and the third parameter is an array of callback information .
* Exceptions are caught by the + rescue + clause of < code > begin . . . end < / code >
* blocks .
*/
static VALUE
2019-07-08 01:59:28 -04:00
rb_fiber_raise ( int argc , VALUE * argv , VALUE fiber )
2018-12-28 08:03:09 -05:00
{
VALUE exc = rb_make_exception ( argc , argv ) ;
2019-07-08 01:59:28 -04:00
return rb_fiber_resume ( fiber , - 1 , & exc ) ;
2018-12-28 08:03:09 -05:00
}
2008-12-26 19:25:47 -05:00
/*
* call - seq :
* fiber . transfer ( args , . . . ) - > obj
2009-02-22 09:23:33 -05:00
*
2008-12-26 19:25:47 -05:00
* Transfer control to another fiber , resuming it from where it last
2009-02-22 09:23:33 -05:00
* stopped or starting it if it was not resumed before . The calling
2010-10-26 20:26:29 -04:00
* fiber will be suspended much like in a call to
2019-03-22 07:04:59 -04:00
* Fiber . yield . You need to < code > require ' fiber ' < / code >
2010-10-26 20:26:29 -04:00
* before using this method .
2009-02-22 09:23:33 -05:00
*
2009-11-03 12:46:28 -05:00
* The fiber which receives the transfer call is treats it much like
2008-12-26 19:25:47 -05:00
* a resume call . Arguments passed to transfer are treated like those
* passed to resume .
2009-02-22 09:23:33 -05:00
*
2008-12-26 19:25:47 -05:00
* You cannot resume a fiber that transferred control to another one .
* This will cause a double resume error . You need to transfer control
* back to this fiber before it can yield and resume .
2012-05-02 06:13:28 -04:00
*
* Example :
*
* fiber1 = Fiber . new do
* puts " In Fiber 1 "
* Fiber . yield
* end
*
* fiber2 = Fiber . new do
* puts " In Fiber 2 "
* fiber1 . transfer
2012-05-02 10:30:48 -04:00
* puts " Never see this message "
2012-05-02 06:13:28 -04:00
* end
*
* fiber3 = Fiber . new do
* puts " In Fiber 3 "
* end
*
* fiber2 . resume
* fiber3 . resume
*
2014-05-24 21:17:52 -04:00
* < em > produces < / em >
2012-05-02 06:13:28 -04:00
*
2012-05-02 20:14:10 -04:00
* In fiber 2
* In fiber 1
* In fiber 3
2012-05-02 06:13:28 -04:00
*
2008-12-26 19:25:47 -05:00
*/
2007-08-21 14:51:39 -04:00
static VALUE
2019-07-08 01:59:28 -04:00
rb_fiber_m_transfer ( int argc , VALUE * argv , VALUE fiber_value )
2007-08-21 14:51:39 -04:00
{
2019-07-08 01:59:28 -04:00
rb_fiber_t * fiber = fiber_ptr ( fiber_value ) ;
fiber - > transferred = 1 ;
return fiber_switch ( fiber , argc , argv , 0 ) ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
}
2008-12-26 19:25:47 -05:00
/*
* call - seq :
* Fiber . yield ( args , . . . ) - > obj
2009-02-22 09:23:33 -05:00
*
2008-12-26 19:25:47 -05:00
* Yields control back to the context that resumed the fiber , passing
* along any arguments that were passed to it . The fiber will resume
2019-03-22 07:04:59 -04:00
* processing at this point when # resume is called next .
* Any arguments passed to the next # resume will be the value that
* this Fiber . yield expression evaluates to .
2008-12-26 19:25:47 -05:00
*/
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
static VALUE
2007-08-21 14:51:39 -04:00
rb_fiber_s_yield ( int argc , VALUE * argv , VALUE klass )
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
{
2007-08-21 14:51:39 -04:00
return rb_fiber_yield ( argc , argv ) ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
}
2008-12-26 19:25:47 -05:00
/*
* call - seq :
* Fiber . current ( ) - > fiber
2009-02-22 09:23:33 -05:00
*
2008-12-26 19:25:47 -05:00
* Returns the current fiber . You need to < code > require ' fiber ' < / code >
* before using this method . If you are not running in the context of
* a fiber this method will return the root fiber .
*/
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
static VALUE
2007-08-21 14:51:39 -04:00
rb_fiber_s_current ( VALUE klass )
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
{
2007-08-21 14:51:39 -04:00
return rb_fiber_current ( ) ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
}
2017-08-09 22:58:36 -04:00
/*
* call - seq :
* fiber . to_s - > string
*
* Returns fiber information string .
*
*/
static VALUE
2019-07-08 01:59:28 -04:00
fiber_to_s ( VALUE fiber_value )
2017-08-09 22:58:36 -04:00
{
2019-07-08 01:59:28 -04:00
const rb_fiber_t * fiber = fiber_ptr ( fiber_value ) ;
2017-08-09 22:58:36 -04:00
const rb_proc_t * proc ;
char status_info [ 0x10 ] ;
2019-07-08 01:59:28 -04:00
snprintf ( status_info , 0x10 , " (%s) " , fiber_status_name ( fiber - > status ) ) ;
if ( ! rb_obj_is_proc ( fiber - > first_proc ) ) {
2019-07-08 03:00:29 -04:00
VALUE str = rb_any_to_s ( fiber_value ) ;
2019-06-01 01:48:25 -04:00
strlcat ( status_info , " > " , sizeof ( status_info ) ) ;
rb_str_set_len ( str , RSTRING_LEN ( str ) - 1 ) ;
rb_str_cat_cstr ( str , status_info ) ;
return str ;
2017-09-01 21:47:43 -04:00
}
2019-07-08 01:59:28 -04:00
GetProcPtr ( fiber - > first_proc , proc ) ;
return rb_block_to_s ( fiber_value , & proc - > block , status_info ) ;
2017-08-09 22:58:36 -04:00
}
2010-05-08 00:50:09 -04:00
2018-08-29 04:04:09 -04:00
# ifdef HAVE_WORKING_FORK
void
rb_fiber_atfork ( rb_thread_t * th )
{
2018-08-30 15:14:37 -04:00
if ( th - > root_fiber ) {
if ( & th - > root_fiber - > cont . saved_ec ! = th - > ec ) {
th - > root_fiber = th - > ec - > fiber_ptr ;
}
th - > root_fiber - > prev = 0 ;
2018-08-29 04:04:09 -04:00
}
}
# endif
2019-06-01 20:49:58 -04:00
# ifdef RB_EXPERIMENTAL_FIBER_POOL
static void
fiber_pool_free ( void * ptr )
{
struct fiber_pool * fiber_pool = ptr ;
RUBY_FREE_ENTER ( " fiber_pool " ) ;
fiber_pool_free_allocations ( fiber_pool - > allocations ) ;
ruby_xfree ( fiber_pool ) ;
RUBY_FREE_LEAVE ( " fiber_pool " ) ;
}
static size_t
fiber_pool_memsize ( const void * ptr )
{
const struct fiber_pool * fiber_pool = ptr ;
size_t size = sizeof ( * fiber_pool ) ;
size + = fiber_pool - > count * fiber_pool - > size ;
return size ;
}
static const rb_data_type_t FiberPoolDataType = {
" fiber_pool " ,
{ NULL , fiber_pool_free , fiber_pool_memsize , } ,
0 , 0 , RUBY_TYPED_FREE_IMMEDIATELY
} ;
static VALUE
fiber_pool_alloc ( VALUE klass )
{
struct fiber_pool * fiber_pool = RB_ALLOC ( struct fiber_pool ) ;
return TypedData_Wrap_Struct ( klass , & FiberPoolDataType , fiber_pool ) ;
}
static VALUE
rb_fiber_pool_initialize ( int argc , VALUE * argv , VALUE self )
{
rb_thread_t * th = GET_THREAD ( ) ;
VALUE size = Qnil , count = Qnil , vm_stack_size = Qnil ;
struct fiber_pool * fiber_pool = NULL ;
// Maybe these should be keyworkd arguments.
rb_scan_args ( argc , argv , " 03 " , & size , & count , & vm_stack_size ) ;
if ( NIL_P ( size ) ) {
size = INT2NUM ( th - > vm - > default_params . fiber_machine_stack_size ) ;
}
if ( NIL_P ( count ) ) {
count = INT2NUM ( 128 ) ;
}
if ( NIL_P ( vm_stack_size ) ) {
vm_stack_size = INT2NUM ( th - > vm - > default_params . fiber_vm_stack_size ) ;
}
TypedData_Get_Struct ( self , struct fiber_pool , & FiberPoolDataType , fiber_pool ) ;
fiber_pool_initialize ( fiber_pool , NUM2SIZET ( size ) , NUM2SIZET ( count ) , NUM2SIZET ( vm_stack_size ) ) ;
return self ;
}
# endif
2010-05-08 00:50:09 -04:00
/*
* Document - class : FiberError
*
* Raised when an invalid operation is attempted on a Fiber , in
* particular when attempting to call / resume a dead fiber ,
* attempting to yield from the root fiber , or calling a fiber across
* threads .
*
* fiber = Fiber . new { }
* fiber . resume # = > nil
* fiber . resume # = > FiberError : dead fiber called
*/
2007-05-23 18:52:19 -04:00
void
Init_Cont ( void )
{
2010-05-05 14:37:37 -04:00
rb_thread_t * th = GET_THREAD ( ) ;
2019-06-01 20:49:58 -04:00
size_t vm_stack_size = th - > vm - > default_params . fiber_vm_stack_size ;
size_t machine_stack_size = th - > vm - > default_params . fiber_machine_stack_size ;
size_t stack_size = machine_stack_size + vm_stack_size ;
2010-05-05 14:37:37 -04:00
# ifdef _WIN32
SYSTEM_INFO info ;
GetSystemInfo ( & info ) ;
pagesize = info . dwPageSize ;
# else /* not WIN32 */
pagesize = sysconf ( _SC_PAGESIZE ) ;
# endif
2017-10-26 04:32:49 -04:00
SET_MACHINE_STACK_END ( & th - > ec - > machine . stack_end ) ;
2010-05-05 14:37:37 -04:00
2019-06-01 20:49:58 -04:00
fiber_pool_initialize ( & shared_fiber_pool , stack_size , 8 , vm_stack_size ) ;
* cont.c: support Fiber. Check test/ruby/test_fiber.rb for detail.
Fiber is known as "Micro Thread", "Coroutine", and other terms.
At this time, only Fiber#pass is supported to change context.
I want to know more suitable method name/API for Fiber (... do you
know more suitable class name instead of Fiber?) as "suspend/resume",
"call", "yield", "start/kick/stop/restart", ....
* eval.c, eval_intern.h, thread.c, yarvcore.c, yarvcore.h: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12395 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-05-27 15:12:43 -04:00
rb_cFiber = rb_define_class ( " Fiber " , rb_cObject ) ;
2008-11-28 10:23:09 -05:00
rb_define_alloc_func ( rb_cFiber , fiber_alloc ) ;
2007-06-02 03:48:29 -04:00
rb_eFiberError = rb_define_class ( " FiberError " , rb_eStandardError ) ;
2007-09-26 06:26:35 -04:00
rb_define_singleton_method ( rb_cFiber , " yield " , rb_fiber_s_yield , - 1 ) ;
2019-06-01 20:49:58 -04:00
rb_define_method ( rb_cFiber , " initialize " , rb_fiber_initialize , - 1 ) ;
2007-09-26 06:26:35 -04:00
rb_define_method ( rb_cFiber , " resume " , rb_fiber_m_resume , - 1 ) ;
2018-12-28 08:03:09 -05:00
rb_define_method ( rb_cFiber , " raise " , rb_fiber_raise , - 1 ) ;
2017-08-09 22:58:36 -04:00
rb_define_method ( rb_cFiber , " to_s " , fiber_to_s , 0 ) ;
rb_define_alias ( rb_cFiber , " inspect " , " to_s " ) ;
2019-06-01 20:49:58 -04:00
# ifdef RB_EXPERIMENTAL_FIBER_POOL
rb_cFiberPool = rb_define_class ( " Pool " , rb_cFiber ) ;
rb_define_alloc_func ( rb_cFiberPool , fiber_pool_alloc ) ;
rb_define_method ( rb_cFiberPool , " initialize " , rb_fiber_pool_initialize , - 1 ) ;
# endif
2007-05-23 18:52:19 -04:00
}
2013-04-05 06:29:38 -04:00
RUBY_SYMBOL_EXPORT_BEGIN
2010-07-21 17:38:25 -04:00
2007-08-24 22:03:44 -04:00
void
2009-01-20 02:17:28 -05:00
ruby_Init_Continuation_body ( void )
2007-08-24 22:03:44 -04:00
{
rb_cContinuation = rb_define_class ( " Continuation " , rb_cObject ) ;
rb_undef_alloc_func ( rb_cContinuation ) ;
rb_undef_method ( CLASS_OF ( rb_cContinuation ) , " new " ) ;
rb_define_method ( rb_cContinuation , " call " , rb_cont_call , - 1 ) ;
rb_define_method ( rb_cContinuation , " [] " , rb_cont_call , - 1 ) ;
rb_define_global_function ( " callcc " , rb_callcc , 0 ) ;
}
void
2009-01-20 02:17:28 -05:00
ruby_Init_Fiber_as_Coroutine ( void )
2007-08-24 22:03:44 -04:00
{
rb_define_method ( rb_cFiber , " transfer " , rb_fiber_m_transfer , - 1 ) ;
rb_define_method ( rb_cFiber , " alive? " , rb_fiber_alive_p , 0 ) ;
rb_define_singleton_method ( rb_cFiber , " current " , rb_fiber_s_current , 0 ) ;
}
2010-07-21 17:38:25 -04:00
2013-04-05 06:29:38 -04:00
RUBY_SYMBOL_EXPORT_END