* eval_thread.c, common.mk: remove eval_thread.c.
* yarvcore.c: rename cYarvThread to rb_cThread. * gc.c: remove YARV_* prefix. * gc.h: add an include guard and prototype of rb_gc_set_stack_end(). * inits.c: fix to ANSI prototype style and reorder Init_*(). * io.c (pipe_finalize): TODO: comment out last_status. * process.c, yarvcore.h: fix to use yarv_vm_t#last_status instead of rb_last_status and make last_status_get() to access $?. * yarvcore.c (vm_mark): mark yarv_vm_t#last_status. * ruby.h: add declarations of rb_cISeq and rb_cVM. * thread.c: move eval_thread.c codes to thread.c and remove yarv_* function prefix. * thread.c (thread_start_func_2): use yarv_thread_t#first_func if it is not null. * vm.c: fix copyright year. * yarvcore.c (Init_vm): rename to Init_VM(). git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11631 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
72f2d2a00d
commit
025cfde57d
31
ChangeLog
31
ChangeLog
@ -1,3 +1,34 @@
|
|||||||
|
Mon Feb 5 21:06:50 2007 Koichi Sasada <ko1@atdot.net>
|
||||||
|
|
||||||
|
* eval_thread.c, common.mk: remove eval_thread.c.
|
||||||
|
|
||||||
|
* yarvcore.c: rename cYarvThread to rb_cThread.
|
||||||
|
|
||||||
|
* gc.c: remove YARV_* prefix.
|
||||||
|
|
||||||
|
* gc.h: add an include guard and prototype of rb_gc_set_stack_end().
|
||||||
|
|
||||||
|
* inits.c: fix to ANSI prototype style and reorder Init_*().
|
||||||
|
|
||||||
|
* io.c (pipe_finalize): TODO: comment out last_status.
|
||||||
|
|
||||||
|
* process.c, yarvcore.h: fix to use yarv_vm_t#last_status instead of
|
||||||
|
rb_last_status and make last_status_get() to access $?.
|
||||||
|
|
||||||
|
* yarvcore.c (vm_mark): mark yarv_vm_t#last_status.
|
||||||
|
|
||||||
|
* ruby.h: add declarations of rb_cISeq and rb_cVM.
|
||||||
|
|
||||||
|
* thread.c: move eval_thread.c codes to thread.c and remove yarv_*
|
||||||
|
function prefix.
|
||||||
|
|
||||||
|
* thread.c (thread_start_func_2): use yarv_thread_t#first_func if
|
||||||
|
it is not null.
|
||||||
|
|
||||||
|
* vm.c: fix copyright year.
|
||||||
|
|
||||||
|
* yarvcore.c (Init_vm): rename to Init_VM().
|
||||||
|
|
||||||
Mon Feb 5 04:09:48 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
|
Mon Feb 5 04:09:48 2007 Yukihiro Matsumoto <matz@ruby-lang.org>
|
||||||
|
|
||||||
* eval.c (rb_frame_callee): check if prev_cfp can be accessible.
|
* eval.c (rb_frame_callee): check if prev_cfp can be accessible.
|
||||||
|
@ -32,7 +32,6 @@ OBJS = array.$(OBJEXT) \
|
|||||||
eval.$(OBJEXT) \
|
eval.$(OBJEXT) \
|
||||||
eval_load.$(OBJEXT) \
|
eval_load.$(OBJEXT) \
|
||||||
proc.$(OBJEXT) \
|
proc.$(OBJEXT) \
|
||||||
eval_thread.$(OBJEXT) \
|
|
||||||
file.$(OBJEXT) \
|
file.$(OBJEXT) \
|
||||||
gc.$(OBJEXT) \
|
gc.$(OBJEXT) \
|
||||||
hash.$(OBJEXT) \
|
hash.$(OBJEXT) \
|
||||||
@ -403,11 +402,6 @@ eval_load.$(OBJEXT): {$(VPATH)}eval_load.c {$(VPATH)}eval_intern.h \
|
|||||||
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
|
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
|
||||||
{$(VPATH)}node.h {$(VPATH)}util.h {$(VPATH)}yarvcore.h \
|
{$(VPATH)}node.h {$(VPATH)}util.h {$(VPATH)}yarvcore.h \
|
||||||
{$(VPATH)}rubysig.h {$(VPATH)}st.h {$(VPATH)}dln.h {$(VPATH)}yarv.h
|
{$(VPATH)}rubysig.h {$(VPATH)}st.h {$(VPATH)}dln.h {$(VPATH)}yarv.h
|
||||||
eval_thread.$(OBJEXT): {$(VPATH)}eval_thread.c {$(VPATH)}eval_intern.h \
|
|
||||||
{$(VPATH)}ruby.h config.h {$(VPATH)}yarvcore.h \
|
|
||||||
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
|
|
||||||
{$(VPATH)}node.h {$(VPATH)}util.h \
|
|
||||||
{$(VPATH)}rubysig.h {$(VPATH)}st.h {$(VPATH)}dln.h {$(VPATH)}yarv.h
|
|
||||||
proc.$(OBJEXT): {$(VPATH)}proc.c {$(VPATH)}eval_intern.h \
|
proc.$(OBJEXT): {$(VPATH)}proc.c {$(VPATH)}eval_intern.h \
|
||||||
{$(VPATH)}ruby.h config.h {$(VPATH)}yarvcore.h \
|
{$(VPATH)}ruby.h config.h {$(VPATH)}yarvcore.h \
|
||||||
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
|
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
|
||||||
|
683
eval_thread.c
683
eval_thread.c
@ -1,683 +0,0 @@
|
|||||||
/*
|
|
||||||
* Thread from eval.c
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "eval_intern.h"
|
|
||||||
|
|
||||||
#ifdef __ia64__
|
|
||||||
#if defined(__FreeBSD__)
|
|
||||||
/*
|
|
||||||
* FreeBSD/ia64 currently does not have a way for a process to get the
|
|
||||||
* base address for the RSE backing store, so hardcode it.
|
|
||||||
*/
|
|
||||||
#define __libc_ia64_register_backing_store_base (4ULL<<61)
|
|
||||||
#else
|
|
||||||
#if defined(HAVE_UNWIND_H) && defined(HAVE__UNW_CREATECONTEXTFORSELF)
|
|
||||||
#include <unwind.h>
|
|
||||||
#else
|
|
||||||
#pragma weak __libc_ia64_register_backing_store_base
|
|
||||||
extern unsigned long __libc_ia64_register_backing_store_base;
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Windows SEH refers data on the stack. */
|
|
||||||
#undef SAVE_WIN32_EXCEPTION_LIST
|
|
||||||
#if defined _WIN32 || defined __CYGWIN__
|
|
||||||
#if defined __CYGWIN__
|
|
||||||
typedef unsigned long DWORD;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static inline DWORD
|
|
||||||
win32_get_exception_list()
|
|
||||||
{
|
|
||||||
DWORD p;
|
|
||||||
# if defined _MSC_VER
|
|
||||||
# ifdef _M_IX86
|
|
||||||
# define SAVE_WIN32_EXCEPTION_LIST
|
|
||||||
# if _MSC_VER >= 1310
|
|
||||||
/* warning: unsafe assignment to fs:0 ... this is ok */
|
|
||||||
# pragma warning(disable: 4733)
|
|
||||||
# endif
|
|
||||||
__asm mov eax, fs:[0];
|
|
||||||
__asm mov p, eax;
|
|
||||||
# endif
|
|
||||||
# elif defined __GNUC__
|
|
||||||
# ifdef __i386__
|
|
||||||
# define SAVE_WIN32_EXCEPTION_LIST
|
|
||||||
__asm__("movl %%fs:0,%0":"=r"(p));
|
|
||||||
# endif
|
|
||||||
# elif defined __BORLANDC__
|
|
||||||
# define SAVE_WIN32_EXCEPTION_LIST
|
|
||||||
__emit__(0x64, 0xA1, 0, 0, 0, 0); /* mov eax, fs:[0] */
|
|
||||||
p = _EAX;
|
|
||||||
# endif
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
win32_set_exception_list(p)
|
|
||||||
DWORD p;
|
|
||||||
{
|
|
||||||
# if defined _MSC_VER
|
|
||||||
# ifdef _M_IX86
|
|
||||||
__asm mov eax, p;
|
|
||||||
__asm mov fs:[0], eax;
|
|
||||||
# endif
|
|
||||||
# elif defined __GNUC__
|
|
||||||
# ifdef __i386__
|
|
||||||
__asm__("movl %0,%%fs:0"::"r"(p));
|
|
||||||
# endif
|
|
||||||
# elif defined __BORLANDC__
|
|
||||||
_EAX = p;
|
|
||||||
__emit__(0x64, 0xA3, 0, 0, 0, 0); /* mov fs:[0], eax */
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !defined SAVE_WIN32_EXCEPTION_LIST && !defined _WIN32_WCE
|
|
||||||
# error unsupported platform
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int rb_thread_pending = 0;
|
|
||||||
|
|
||||||
VALUE rb_cThread;
|
|
||||||
|
|
||||||
extern VALUE rb_last_status;
|
|
||||||
|
|
||||||
#define WAIT_FD (1<<0)
|
|
||||||
#define WAIT_SELECT (1<<1)
|
|
||||||
#define WAIT_TIME (1<<2)
|
|
||||||
#define WAIT_JOIN (1<<3)
|
|
||||||
#define WAIT_PID (1<<4)
|
|
||||||
|
|
||||||
/* +infty, for this purpose */
|
|
||||||
#define DELAY_INFTY 1E30
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef NFDBITS
|
|
||||||
void
|
|
||||||
rb_fd_init(fds)
|
|
||||||
volatile rb_fdset_t *fds;
|
|
||||||
{
|
|
||||||
fds->maxfd = 0;
|
|
||||||
fds->fdset = ALLOC(fd_set);
|
|
||||||
FD_ZERO(fds->fdset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
rb_fd_term(fds)
|
|
||||||
rb_fdset_t *fds;
|
|
||||||
{
|
|
||||||
if (fds->fdset)
|
|
||||||
free(fds->fdset);
|
|
||||||
fds->maxfd = 0;
|
|
||||||
fds->fdset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
rb_fd_zero(fds)
|
|
||||||
rb_fdset_t *fds;
|
|
||||||
{
|
|
||||||
if (fds->fdset) {
|
|
||||||
MEMZERO(fds->fdset, fd_mask, howmany(fds->maxfd, NFDBITS));
|
|
||||||
FD_ZERO(fds->fdset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
rb_fd_resize(n, fds)
|
|
||||||
int n;
|
|
||||||
rb_fdset_t *fds;
|
|
||||||
{
|
|
||||||
int m = howmany(n + 1, NFDBITS) * sizeof(fd_mask);
|
|
||||||
int o = howmany(fds->maxfd, NFDBITS) * sizeof(fd_mask);
|
|
||||||
|
|
||||||
if (m < sizeof(fd_set))
|
|
||||||
m = sizeof(fd_set);
|
|
||||||
if (o < sizeof(fd_set))
|
|
||||||
o = sizeof(fd_set);
|
|
||||||
|
|
||||||
if (m > o) {
|
|
||||||
fds->fdset = realloc(fds->fdset, m);
|
|
||||||
memset((char *)fds->fdset + o, 0, m - o);
|
|
||||||
}
|
|
||||||
if (n >= fds->maxfd)
|
|
||||||
fds->maxfd = n + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
rb_fd_set(n, fds)
|
|
||||||
int n;
|
|
||||||
rb_fdset_t *fds;
|
|
||||||
{
|
|
||||||
rb_fd_resize(n, fds);
|
|
||||||
FD_SET(n, fds->fdset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
rb_fd_clr(n, fds)
|
|
||||||
int n;
|
|
||||||
rb_fdset_t *fds;
|
|
||||||
{
|
|
||||||
if (n >= fds->maxfd)
|
|
||||||
return;
|
|
||||||
FD_CLR(n, fds->fdset);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
rb_fd_isset(n, fds)
|
|
||||||
int n;
|
|
||||||
const rb_fdset_t *fds;
|
|
||||||
{
|
|
||||||
if (n >= fds->maxfd)
|
|
||||||
return 0;
|
|
||||||
return FD_ISSET(n, fds->fdset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
rb_fd_copy(dst, src, max)
|
|
||||||
rb_fdset_t *dst;
|
|
||||||
const fd_set *src;
|
|
||||||
int max;
|
|
||||||
{
|
|
||||||
int size = howmany(max, NFDBITS) * sizeof(fd_mask);
|
|
||||||
|
|
||||||
if (size < sizeof(fd_set))
|
|
||||||
size = sizeof(fd_set);
|
|
||||||
dst->maxfd = max;
|
|
||||||
dst->fdset = realloc(dst->fdset, size);
|
|
||||||
memcpy(dst->fdset, src, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
rb_fd_select(n, readfds, writefds, exceptfds, timeout)
|
|
||||||
int n;
|
|
||||||
rb_fdset_t *readfds, *writefds, *exceptfds;
|
|
||||||
struct timeval *timeout;
|
|
||||||
{
|
|
||||||
rb_fd_resize(n - 1, readfds);
|
|
||||||
rb_fd_resize(n - 1, writefds);
|
|
||||||
rb_fd_resize(n - 1, exceptfds);
|
|
||||||
return select(n, rb_fd_ptr(readfds), rb_fd_ptr(writefds),
|
|
||||||
rb_fd_ptr(exceptfds), timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef FD_ZERO
|
|
||||||
#undef FD_SET
|
|
||||||
#undef FD_CLR
|
|
||||||
#undef FD_ISSET
|
|
||||||
|
|
||||||
#define FD_ZERO(f) rb_fd_zero(f)
|
|
||||||
#define FD_SET(i, f) rb_fd_set(i, f)
|
|
||||||
#define FD_CLR(i, f) rb_fd_clr(i, f)
|
|
||||||
#define FD_ISSET(i, f) rb_fd_isset(i, f)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* typedef struct thread * rb_thread_t; */
|
|
||||||
|
|
||||||
struct thread {
|
|
||||||
/* obsolete */
|
|
||||||
struct thread *next, *prev;
|
|
||||||
rb_jmpbuf_t context;
|
|
||||||
#ifdef SAVE_WIN32_EXCEPTION_LIST
|
|
||||||
DWORD win32_exception_list;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
VALUE result;
|
|
||||||
|
|
||||||
long stk_len;
|
|
||||||
long stk_max;
|
|
||||||
VALUE *stk_ptr;
|
|
||||||
VALUE *stk_pos;
|
|
||||||
#ifdef __ia64__
|
|
||||||
VALUE *bstr_ptr;
|
|
||||||
long bstr_len;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct FRAME *frame;
|
|
||||||
struct SCOPE *scope;
|
|
||||||
struct RVarmap *dyna_vars;
|
|
||||||
struct BLOCK *block;
|
|
||||||
struct iter *iter;
|
|
||||||
struct tag *tag;
|
|
||||||
VALUE klass;
|
|
||||||
VALUE wrapper;
|
|
||||||
NODE *cref;
|
|
||||||
struct ruby_env *anchor;
|
|
||||||
|
|
||||||
int flags; /* misc. states (vmode/rb_trap_immediate/raised) */
|
|
||||||
|
|
||||||
NODE *node;
|
|
||||||
|
|
||||||
int tracing;
|
|
||||||
VALUE errinfo;
|
|
||||||
VALUE last_status;
|
|
||||||
VALUE last_line;
|
|
||||||
VALUE last_match;
|
|
||||||
|
|
||||||
int safe;
|
|
||||||
|
|
||||||
enum yarv_thread_status status;
|
|
||||||
int wait_for;
|
|
||||||
int fd;
|
|
||||||
rb_fdset_t readfds;
|
|
||||||
rb_fdset_t writefds;
|
|
||||||
rb_fdset_t exceptfds;
|
|
||||||
int select_value;
|
|
||||||
double delay;
|
|
||||||
rb_thread_t join;
|
|
||||||
|
|
||||||
int abort;
|
|
||||||
int priority;
|
|
||||||
VALUE thgroup;
|
|
||||||
|
|
||||||
st_table *locals;
|
|
||||||
|
|
||||||
VALUE thread;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define THREAD_RAISED 0x200 /* temporary flag */
|
|
||||||
#define THREAD_TERMINATING 0x400 /* persistent flag */
|
|
||||||
#define THREAD_FLAGS_MASK 0x400 /* mask for persistent flags */
|
|
||||||
|
|
||||||
#define FOREACH_THREAD_FROM(f,x) x = f; do { x = x->next;
|
|
||||||
#define END_FOREACH_FROM(f,x) } while (x != f)
|
|
||||||
|
|
||||||
#define FOREACH_THREAD(x) FOREACH_THREAD_FROM(curr_thread,x)
|
|
||||||
#define END_FOREACH(x) END_FOREACH_FROM(curr_thread,x)
|
|
||||||
|
|
||||||
struct thread_status_t {
|
|
||||||
NODE *node;
|
|
||||||
|
|
||||||
int tracing;
|
|
||||||
VALUE errinfo;
|
|
||||||
VALUE last_status;
|
|
||||||
VALUE last_line;
|
|
||||||
VALUE last_match;
|
|
||||||
|
|
||||||
int safe;
|
|
||||||
|
|
||||||
enum yarv_thread_status status;
|
|
||||||
int wait_for;
|
|
||||||
int fd;
|
|
||||||
rb_fdset_t readfds;
|
|
||||||
rb_fdset_t writefds;
|
|
||||||
rb_fdset_t exceptfds;
|
|
||||||
int select_value;
|
|
||||||
double delay;
|
|
||||||
rb_thread_t join;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define THREAD_COPY_STATUS(src, dst) (void)( \
|
|
||||||
(dst)->node = (src)->node, \
|
|
||||||
\
|
|
||||||
(dst)->tracing = (src)->tracing, \
|
|
||||||
(dst)->errinfo = (src)->errinfo, \
|
|
||||||
(dst)->last_status = (src)->last_status, \
|
|
||||||
(dst)->last_line = (src)->last_line, \
|
|
||||||
(dst)->last_match = (src)->last_match, \
|
|
||||||
\
|
|
||||||
(dst)->safe = (src)->safe, \
|
|
||||||
\
|
|
||||||
(dst)->status = (src)->status, \
|
|
||||||
(dst)->wait_for = (src)->wait_for, \
|
|
||||||
(dst)->fd = (src)->fd, \
|
|
||||||
(dst)->readfds = (src)->readfds, \
|
|
||||||
(dst)->writefds = (src)->writefds, \
|
|
||||||
(dst)->exceptfds = (src)->exceptfds, \
|
|
||||||
rb_fd_init(&(src)->readfds), \
|
|
||||||
rb_fd_init(&(src)->writefds), \
|
|
||||||
rb_fd_init(&(src)->exceptfds), \
|
|
||||||
(dst)->select_value = (src)->select_value, \
|
|
||||||
(dst)->delay = (src)->delay, \
|
|
||||||
(dst)->join = (src)->join, \
|
|
||||||
0)
|
|
||||||
|
|
||||||
int
|
|
||||||
thread_set_raised(yarv_thread_t *th)
|
|
||||||
{
|
|
||||||
if (th->raised_flag) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
th->raised_flag = 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
thread_reset_raised(yarv_thread_t *th)
|
|
||||||
{
|
|
||||||
if (th->raised_flag == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
th->raised_flag = 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
rb_thread_fd_close(fd)
|
|
||||||
int fd;
|
|
||||||
{
|
|
||||||
/* TODO: fix me */
|
|
||||||
}
|
|
||||||
|
|
||||||
VALUE
|
|
||||||
rb_thread_current()
|
|
||||||
{
|
|
||||||
return GET_THREAD()->self;
|
|
||||||
}
|
|
||||||
|
|
||||||
static rb_thread_t
|
|
||||||
rb_thread_alloc(klass)
|
|
||||||
VALUE klass;
|
|
||||||
{
|
|
||||||
UNSUPPORTED(rb_thread_alloc);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static VALUE
|
|
||||||
rb_thread_start_0(fn, arg, th)
|
|
||||||
VALUE (*fn) ();
|
|
||||||
void *arg;
|
|
||||||
rb_thread_t th;
|
|
||||||
{
|
|
||||||
rb_bug("unsupported: rb_thread_start_0");
|
|
||||||
return 0; /* not reached */
|
|
||||||
}
|
|
||||||
|
|
||||||
VALUE
|
|
||||||
rb_thread_create(VALUE (*fn) (), void *arg)
|
|
||||||
{
|
|
||||||
Init_stack((VALUE *)&arg);
|
|
||||||
return rb_thread_start_0(fn, arg, rb_thread_alloc(rb_cThread));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* call-seq:
|
|
||||||
* Thread.new([arg]*) {|args| block } => thread
|
|
||||||
*
|
|
||||||
* Creates and runs a new thread to execute the instructions given in
|
|
||||||
* <i>block</i>. Any arguments passed to <code>Thread::new</code> are passed
|
|
||||||
* into the block.
|
|
||||||
*
|
|
||||||
* x = Thread.new { sleep 0.1; print "x"; print "y"; print "z" }
|
|
||||||
* a = Thread.new { print "a"; print "b"; sleep 0.2; print "c" }
|
|
||||||
* x.join # Let the threads finish before
|
|
||||||
* a.join # main thread exits...
|
|
||||||
*
|
|
||||||
* <em>produces:</em>
|
|
||||||
*
|
|
||||||
* abxyzc
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* call-seq:
|
|
||||||
* Thread.new([arg]*) {|args| block } => thread
|
|
||||||
*
|
|
||||||
* Creates and runs a new thread to execute the instructions given in
|
|
||||||
* <i>block</i>. Any arguments passed to <code>Thread::new</code> are passed
|
|
||||||
* into the block.
|
|
||||||
*
|
|
||||||
* x = Thread.new { sleep 0.1; print "x"; print "y"; print "z" }
|
|
||||||
* a = Thread.new { print "a"; print "b"; sleep 0.2; print "c" }
|
|
||||||
* x.join # Let the threads finish before
|
|
||||||
* a.join # main thread exits...
|
|
||||||
*
|
|
||||||
* <em>produces:</em>
|
|
||||||
*
|
|
||||||
* abxyzc
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* call-seq:
|
|
||||||
* Thread.start([args]*) {|args| block } => thread
|
|
||||||
* Thread.fork([args]*) {|args| block } => thread
|
|
||||||
*
|
|
||||||
* Basically the same as <code>Thread::new</code>. However, if class
|
|
||||||
* <code>Thread</code> is subclassed, then calling <code>start</code> in that
|
|
||||||
* subclass will not invoke the subclass's <code>initialize</code> method.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int rb_thread_critical;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* call-seq:
|
|
||||||
* Thread.critical => true or false
|
|
||||||
*
|
|
||||||
* Returns the status of the global ``thread critical'' condition.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* call-seq:
|
|
||||||
* Thread.critical= boolean => true or false
|
|
||||||
*
|
|
||||||
* Sets the status of the global ``thread critical'' condition and returns
|
|
||||||
* it. When set to <code>true</code>, prohibits scheduling of any existing
|
|
||||||
* thread. Does not block new threads from being created and run. Certain
|
|
||||||
* thread operations (such as stopping or killing a thread, sleeping in the
|
|
||||||
* current thread, and raising an exception) may cause a thread to be scheduled
|
|
||||||
* even when in a critical section. <code>Thread::critical</code> is not
|
|
||||||
* intended for daily use: it is primarily there to support folks writing
|
|
||||||
* threading libraries.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Document-class: Continuation
|
|
||||||
*
|
|
||||||
* Continuation objects are generated by
|
|
||||||
* <code>Kernel#callcc</code>. They hold a return address and execution
|
|
||||||
* context, allowing a nonlocal return to the end of the
|
|
||||||
* <code>callcc</code> block from anywhere within a program.
|
|
||||||
* Continuations are somewhat analogous to a structured version of C's
|
|
||||||
* <code>setjmp/longjmp</code> (although they contain more state, so
|
|
||||||
* you might consider them closer to threads).
|
|
||||||
*
|
|
||||||
* For instance:
|
|
||||||
*
|
|
||||||
* arr = [ "Freddie", "Herbie", "Ron", "Max", "Ringo" ]
|
|
||||||
* callcc{|$cc|}
|
|
||||||
* puts(message = arr.shift)
|
|
||||||
* $cc.call unless message =~ /Max/
|
|
||||||
*
|
|
||||||
* <em>produces:</em>
|
|
||||||
*
|
|
||||||
* Freddie
|
|
||||||
* Herbie
|
|
||||||
* Ron
|
|
||||||
* Max
|
|
||||||
*
|
|
||||||
* This (somewhat contrived) example allows the inner loop to abandon
|
|
||||||
* processing early:
|
|
||||||
*
|
|
||||||
* callcc {|cont|
|
|
||||||
* for i in 0..4
|
|
||||||
* print "\n#{i}: "
|
|
||||||
* for j in i*5...(i+1)*5
|
|
||||||
* cont.call() if j == 17
|
|
||||||
* printf "%3d", j
|
|
||||||
* end
|
|
||||||
* end
|
|
||||||
* }
|
|
||||||
* print "\n"
|
|
||||||
*
|
|
||||||
* <em>produces:</em>
|
|
||||||
*
|
|
||||||
* 0: 0 1 2 3 4
|
|
||||||
* 1: 5 6 7 8 9
|
|
||||||
* 2: 10 11 12 13 14
|
|
||||||
* 3: 15 16
|
|
||||||
*/
|
|
||||||
|
|
||||||
VALUE rb_cCont;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* call-seq:
|
|
||||||
* callcc {|cont| block } => obj
|
|
||||||
*
|
|
||||||
* Generates a <code>Continuation</code> object, which it passes to the
|
|
||||||
* associated block. Performing a <em>cont</em><code>.call</code> will
|
|
||||||
* cause the <code>callcc</code> to return (as will falling through the
|
|
||||||
* end of the block). The value returned by the <code>callcc</code> is
|
|
||||||
* the value of the block, or the value passed to
|
|
||||||
* <em>cont</em><code>.call</code>. See class <code>Continuation</code>
|
|
||||||
* for more details. Also see <code>Kernel::throw</code> for
|
|
||||||
* an alternative mechanism for unwinding a call stack.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static VALUE
|
|
||||||
rb_callcc(self)
|
|
||||||
VALUE self;
|
|
||||||
{
|
|
||||||
UNSUPPORTED(rb_callcc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* call-seq:
|
|
||||||
* cont.call(args, ...)
|
|
||||||
* cont[args, ...]
|
|
||||||
*
|
|
||||||
* Invokes the continuation. The program continues from the end of the
|
|
||||||
* <code>callcc</code> block. If no arguments are given, the original
|
|
||||||
* <code>callcc</code> returns <code>nil</code>. If one argument is
|
|
||||||
* given, <code>callcc</code> returns it. Otherwise, an array
|
|
||||||
* containing <i>args</i> is returned.
|
|
||||||
*
|
|
||||||
* 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(argc, argv, cont)
|
|
||||||
int argc;
|
|
||||||
VALUE *argv;
|
|
||||||
VALUE cont;
|
|
||||||
{
|
|
||||||
UNSUPPORTED(rb_cont_call);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* variables for recursive traversals */
|
|
||||||
static ID recursive_key;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* +Thread+ encapsulates the behavior of a thread of
|
|
||||||
* execution, including the main thread of the Ruby script.
|
|
||||||
*
|
|
||||||
* In the descriptions of the methods in this class, the parameter _sym_
|
|
||||||
* refers to a symbol, which is either a quoted string or a
|
|
||||||
* +Symbol+ (such as <code>:name</code>).
|
|
||||||
*/
|
|
||||||
|
|
||||||
void
|
|
||||||
Init_Thread()
|
|
||||||
{
|
|
||||||
recursive_key = rb_intern("__recursive_key__");
|
|
||||||
rb_eThreadError = rb_define_class("ThreadError", rb_eStandardError);
|
|
||||||
rb_cCont = rb_define_class("Continuation", rb_cObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
static VALUE
|
|
||||||
recursive_check(obj)
|
|
||||||
VALUE obj;
|
|
||||||
{
|
|
||||||
VALUE hash = rb_thread_local_aref(rb_thread_current(), recursive_key);
|
|
||||||
|
|
||||||
if (NIL_P(hash) || TYPE(hash) != T_HASH) {
|
|
||||||
return Qfalse;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
VALUE list = rb_hash_aref(hash, ID2SYM(rb_frame_this_func()));
|
|
||||||
|
|
||||||
if (NIL_P(list) || TYPE(list) != T_ARRAY)
|
|
||||||
return Qfalse;
|
|
||||||
return rb_ary_includes(list, rb_obj_id(obj));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
recursive_push(obj)
|
|
||||||
VALUE obj;
|
|
||||||
{
|
|
||||||
VALUE hash = rb_thread_local_aref(rb_thread_current(), recursive_key);
|
|
||||||
VALUE list, sym;
|
|
||||||
|
|
||||||
sym = ID2SYM(rb_frame_this_func());
|
|
||||||
if (NIL_P(hash) || TYPE(hash) != T_HASH) {
|
|
||||||
hash = rb_hash_new();
|
|
||||||
rb_thread_local_aset(rb_thread_current(), recursive_key, hash);
|
|
||||||
list = Qnil;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
list = rb_hash_aref(hash, sym);
|
|
||||||
}
|
|
||||||
if (NIL_P(list) || TYPE(list) != T_ARRAY) {
|
|
||||||
list = rb_ary_new();
|
|
||||||
rb_hash_aset(hash, sym, list);
|
|
||||||
}
|
|
||||||
rb_ary_push(list, rb_obj_id(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
recursive_pop()
|
|
||||||
{
|
|
||||||
VALUE hash = rb_thread_local_aref(rb_thread_current(), recursive_key);
|
|
||||||
VALUE list, sym;
|
|
||||||
|
|
||||||
sym = ID2SYM(rb_frame_this_func());
|
|
||||||
if (NIL_P(hash) || TYPE(hash) != T_HASH) {
|
|
||||||
VALUE symname;
|
|
||||||
VALUE thrname;
|
|
||||||
symname = rb_inspect(sym);
|
|
||||||
thrname = rb_inspect(rb_thread_current());
|
|
||||||
|
|
||||||
rb_raise(rb_eTypeError, "invalid inspect_tbl hash for %s in %s",
|
|
||||||
StringValuePtr(symname), StringValuePtr(thrname));
|
|
||||||
}
|
|
||||||
list = rb_hash_aref(hash, sym);
|
|
||||||
if (NIL_P(list) || TYPE(list) != T_ARRAY) {
|
|
||||||
VALUE symname = rb_inspect(sym);
|
|
||||||
VALUE thrname = rb_inspect(rb_thread_current());
|
|
||||||
rb_raise(rb_eTypeError, "invalid inspect_tbl list for %s in %s",
|
|
||||||
StringValuePtr(symname), StringValuePtr(thrname));
|
|
||||||
}
|
|
||||||
rb_ary_pop(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
VALUE
|
|
||||||
rb_exec_recursive(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE arg)
|
|
||||||
{
|
|
||||||
if (recursive_check(obj)) {
|
|
||||||
return (*func) (obj, arg, Qtrue);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
VALUE result = Qundef;
|
|
||||||
int state;
|
|
||||||
|
|
||||||
recursive_push(obj);
|
|
||||||
PUSH_TAG(PROT_NONE);
|
|
||||||
if ((state = EXEC_TAG()) == 0) {
|
|
||||||
result = (*func) (obj, arg, Qfalse);
|
|
||||||
}
|
|
||||||
POP_TAG();
|
|
||||||
recursive_pop();
|
|
||||||
if (state)
|
|
||||||
JUMP_TAG(state);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* flush_register_windows must not be inlined because flushrs doesn't flush
|
|
||||||
* current frame in register stack. */
|
|
||||||
#ifdef __ia64__
|
|
||||||
void
|
|
||||||
flush_register_windows(void)
|
|
||||||
{
|
|
||||||
__asm__("flushrs");
|
|
||||||
}
|
|
||||||
#endif
|
|
12
gc.c
12
gc.c
@ -539,9 +539,7 @@ rb_data_object_alloc(VALUE klass, void *datap, RUBY_DATA_FUNC dmark, RUBY_DATA_F
|
|||||||
return (VALUE)data;
|
return (VALUE)data;
|
||||||
}
|
}
|
||||||
|
|
||||||
NOINLINE(void yarv_set_stack_end(VALUE **stack_end_p));
|
#define SET_STACK_END rb_gc_set_stack_end(&th->machine_stack_end)
|
||||||
|
|
||||||
#define YARV_SET_STACK_END yarv_set_stack_end(&th->machine_stack_end)
|
|
||||||
#define STACK_START (th->machine_stack_start)
|
#define STACK_START (th->machine_stack_start)
|
||||||
#define STACK_END (th->machine_stack_end)
|
#define STACK_END (th->machine_stack_end)
|
||||||
|
|
||||||
@ -565,7 +563,7 @@ static int
|
|||||||
stack_grow_direction(VALUE *addr)
|
stack_grow_direction(VALUE *addr)
|
||||||
{
|
{
|
||||||
yarv_thread_t *th = GET_THREAD();
|
yarv_thread_t *th = GET_THREAD();
|
||||||
YARV_SET_STACK_END;
|
SET_STACK_END;
|
||||||
|
|
||||||
if (STACK_END > addr) return grow_direction = 1;
|
if (STACK_END > addr) return grow_direction = 1;
|
||||||
return grow_direction = -1;
|
return grow_direction = -1;
|
||||||
@ -577,7 +575,7 @@ stack_grow_direction(VALUE *addr)
|
|||||||
#define GC_WATER_MARK 512
|
#define GC_WATER_MARK 512
|
||||||
|
|
||||||
#define CHECK_STACK(ret) do {\
|
#define CHECK_STACK(ret) do {\
|
||||||
YARV_SET_STACK_END;\
|
SET_STACK_END;\
|
||||||
(ret) = (STACK_LENGTH > STACK_LEVEL_MAX + GC_WATER_MARK);\
|
(ret) = (STACK_LENGTH > STACK_LEVEL_MAX + GC_WATER_MARK);\
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
@ -585,7 +583,7 @@ int
|
|||||||
ruby_stack_length(VALUE **p)
|
ruby_stack_length(VALUE **p)
|
||||||
{
|
{
|
||||||
yarv_thread_t *th = GET_THREAD();
|
yarv_thread_t *th = GET_THREAD();
|
||||||
YARV_SET_STACK_END;
|
SET_STACK_END;
|
||||||
if (p) *p = STACK_UPPER(STACK_END, STACK_START, STACK_END);
|
if (p) *p = STACK_UPPER(STACK_END, STACK_START, STACK_END);
|
||||||
return STACK_LENGTH;
|
return STACK_LENGTH;
|
||||||
}
|
}
|
||||||
@ -1355,7 +1353,7 @@ garbage_collect(void)
|
|||||||
}
|
}
|
||||||
during_gc++;
|
during_gc++;
|
||||||
|
|
||||||
YARV_SET_STACK_END;
|
SET_STACK_END;
|
||||||
|
|
||||||
init_mark_stack();
|
init_mark_stack();
|
||||||
|
|
||||||
|
9
gc.h
9
gc.h
@ -1,4 +1,11 @@
|
|||||||
|
|
||||||
|
#ifndef RUBY_GC_H
|
||||||
|
#define RUBY_GC_H 1
|
||||||
|
|
||||||
|
NOINLINE(void rb_gc_set_stack_end(VALUE **stack_end_p));
|
||||||
|
|
||||||
|
/* for GC debug */
|
||||||
|
|
||||||
#ifndef MARK_FREE_DEBUG
|
#ifndef MARK_FREE_DEBUG
|
||||||
#define MARK_FREE_DEBUG 0
|
#define MARK_FREE_DEBUG 0
|
||||||
#endif
|
#endif
|
||||||
@ -46,3 +53,5 @@ rb_gc_debug_body(char *mode, char *msg, int st, void *ptr)
|
|||||||
|
|
||||||
#define MARK_UNLESS_NULL(ptr) if(ptr){rb_gc_mark(ptr);}
|
#define MARK_UNLESS_NULL(ptr) if(ptr){rb_gc_mark(ptr);}
|
||||||
#define FREE_UNLESS_NULL(ptr) if(ptr){ruby_xfree(ptr);}
|
#define FREE_UNLESS_NULL(ptr) if(ptr){ruby_xfree(ptr);}
|
||||||
|
#endif /* RUBY_GC_H */
|
||||||
|
|
||||||
|
78
inits.c
78
inits.c
@ -12,43 +12,42 @@
|
|||||||
|
|
||||||
#include "ruby.h"
|
#include "ruby.h"
|
||||||
|
|
||||||
void Init_Array _((void));
|
void Init_Array(void);
|
||||||
void Init_Bignum _((void));
|
void Init_Bignum(void);
|
||||||
void Init_Binding _((void));
|
void Init_Binding(void);
|
||||||
void Init_Comparable _((void));
|
void Init_Comparable(void);
|
||||||
void Init_Dir _((void));
|
void Init_Dir(void);
|
||||||
void Init_Enumerable _((void));
|
void Init_Enumerable(void);
|
||||||
void Init_Enumerator _((void));
|
void Init_Enumerator(void);
|
||||||
void Init_Exception _((void));
|
void Init_Exception(void);
|
||||||
void Init_syserr _((void));
|
void Init_syserr(void);
|
||||||
void Init_eval _((void));
|
void Init_eval(void);
|
||||||
void Init_load _((void));
|
void Init_load(void);
|
||||||
void Init_Proc _((void));
|
void Init_Proc(void);
|
||||||
void Init_Thread _((void));
|
void Init_File(void);
|
||||||
void Init_File _((void));
|
void Init_GC(void);
|
||||||
void Init_GC _((void));
|
void Init_Hash(void);
|
||||||
void Init_Hash _((void));
|
void Init_IO(void);
|
||||||
void Init_IO _((void));
|
void Init_Math(void);
|
||||||
void Init_Math _((void));
|
void Init_marshal(void);
|
||||||
void Init_marshal _((void));
|
void Init_Numeric(void);
|
||||||
void Init_Numeric _((void));
|
void Init_Object(void);
|
||||||
void Init_Object _((void));
|
void Init_pack(void);
|
||||||
void Init_pack _((void));
|
void Init_Precision(void);
|
||||||
void Init_Precision _((void));
|
void Init_sym(void);
|
||||||
void Init_sym _((void));
|
void Init_process(void);
|
||||||
void Init_process _((void));
|
void Init_Random(void);
|
||||||
void Init_Random _((void));
|
void Init_Range(void);
|
||||||
void Init_Range _((void));
|
void Init_Regexp(void);
|
||||||
void Init_Regexp _((void));
|
void Init_signal(void);
|
||||||
void Init_signal _((void));
|
void Init_String(void);
|
||||||
void Init_String _((void));
|
void Init_Struct(void);
|
||||||
void Init_Struct _((void));
|
void Init_Time(void);
|
||||||
void Init_Time _((void));
|
void Init_var_tables(void);
|
||||||
void Init_var_tables _((void));
|
void Init_version(void);
|
||||||
void Init_version _((void));
|
void Init_ISeq(void);
|
||||||
void Init_jump _((void));
|
void Init_VM(void);
|
||||||
void Init_vm _((void));
|
void Init_Thread(void);
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
rb_call_inits()
|
rb_call_inits()
|
||||||
@ -63,7 +62,6 @@ rb_call_inits()
|
|||||||
Init_jump();
|
Init_jump();
|
||||||
Init_String();
|
Init_String();
|
||||||
Init_Exception();
|
Init_Exception();
|
||||||
Init_Thread();
|
|
||||||
Init_Numeric();
|
Init_Numeric();
|
||||||
Init_Bignum();
|
Init_Bignum();
|
||||||
Init_syserr();
|
Init_syserr();
|
||||||
@ -86,6 +84,8 @@ rb_call_inits()
|
|||||||
Init_GC();
|
Init_GC();
|
||||||
Init_marshal();
|
Init_marshal();
|
||||||
Init_Enumerator();
|
Init_Enumerator();
|
||||||
Init_vm();
|
Init_ISeq();
|
||||||
|
Init_VM();
|
||||||
|
Init_Thread();
|
||||||
Init_version();
|
Init_version();
|
||||||
}
|
}
|
||||||
|
3
io.c
3
io.c
@ -2970,7 +2970,6 @@ static void
|
|||||||
pipe_finalize(OpenFile *fptr, int noraise)
|
pipe_finalize(OpenFile *fptr, int noraise)
|
||||||
{
|
{
|
||||||
#if !defined(HAVE_FORK) && !defined(_WIN32)
|
#if !defined(HAVE_FORK) && !defined(_WIN32)
|
||||||
extern VALUE rb_last_status;
|
|
||||||
int status;
|
int status;
|
||||||
if (fptr->stdio_file) {
|
if (fptr->stdio_file) {
|
||||||
status = pclose(fptr->stdio_file);
|
status = pclose(fptr->stdio_file);
|
||||||
@ -2980,7 +2979,7 @@ pipe_finalize(OpenFile *fptr, int noraise)
|
|||||||
#if defined DJGPP
|
#if defined DJGPP
|
||||||
status <<= 8;
|
status <<= 8;
|
||||||
#endif
|
#endif
|
||||||
rb_last_status = INT2FIX(status);
|
/* TODO: need it? -> rb_last_status = INT2FIX(status); */
|
||||||
#else
|
#else
|
||||||
fptr_finalize(fptr, noraise);
|
fptr_finalize(fptr, noraise);
|
||||||
#endif
|
#endif
|
||||||
|
33
process.c
33
process.c
@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
#include "ruby.h"
|
#include "ruby.h"
|
||||||
#include "rubysig.h"
|
#include "rubysig.h"
|
||||||
|
#include "yarvcore.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
@ -194,16 +196,21 @@ get_ppid(void)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static VALUE rb_cProcStatus;
|
static VALUE rb_cProcStatus;
|
||||||
VALUE rb_last_status = Qnil;
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
last_status_set(int status, int pid)
|
last_status_set(int status, int pid)
|
||||||
{
|
{
|
||||||
rb_last_status = rb_obj_alloc(rb_cProcStatus);
|
yarv_vm_t *vm = GET_VM();
|
||||||
rb_iv_set(rb_last_status, "status", INT2FIX(status));
|
vm->last_status = rb_obj_alloc(rb_cProcStatus);
|
||||||
rb_iv_set(rb_last_status, "pid", INT2FIX(pid));
|
rb_iv_set(vm->last_status, "status", INT2FIX(status));
|
||||||
|
rb_iv_set(vm->last_status, "pid", INT2FIX(pid));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
last_status_get(void)
|
||||||
|
{
|
||||||
|
return GET_VM()->last_status;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
@ -636,7 +643,7 @@ static int
|
|||||||
waitall_each(int pid, int status, VALUE ary)
|
waitall_each(int pid, int status, VALUE ary)
|
||||||
{
|
{
|
||||||
last_status_set(status, pid);
|
last_status_set(status, pid);
|
||||||
rb_ary_push(ary, rb_assoc_new(INT2NUM(pid), rb_last_status));
|
rb_ary_push(ary, rb_assoc_new(INT2NUM(pid), GET_VM()->last_status));
|
||||||
return ST_DELETE;
|
return ST_DELETE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -721,7 +728,7 @@ proc_wait(int argc, VALUE *argv)
|
|||||||
if ((pid = rb_waitpid(pid, &status, flags)) < 0)
|
if ((pid = rb_waitpid(pid, &status, flags)) < 0)
|
||||||
rb_sys_fail(0);
|
rb_sys_fail(0);
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
return rb_last_status = Qnil;
|
return GET_VM()->last_status = Qnil;
|
||||||
}
|
}
|
||||||
return INT2FIX(pid);
|
return INT2FIX(pid);
|
||||||
}
|
}
|
||||||
@ -749,7 +756,7 @@ proc_wait2(int argc, VALUE *argv)
|
|||||||
{
|
{
|
||||||
VALUE pid = proc_wait(argc, argv);
|
VALUE pid = proc_wait(argc, argv);
|
||||||
if (NIL_P(pid)) return Qnil;
|
if (NIL_P(pid)) return Qnil;
|
||||||
return rb_assoc_new(pid, rb_last_status);
|
return rb_assoc_new(pid, GET_VM()->last_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -798,10 +805,10 @@ proc_waitall(void)
|
|||||||
rb_sys_fail(0);
|
rb_sys_fail(0);
|
||||||
}
|
}
|
||||||
last_status_set(status, pid);
|
last_status_set(status, pid);
|
||||||
rb_ary_push(result, rb_assoc_new(INT2NUM(pid), rb_last_status));
|
rb_ary_push(result, rb_assoc_new(INT2NUM(pid), GET_VM()->last_status));
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
rb_last_status = Qnil;
|
GET_VM()->last_status = Qnil;
|
||||||
for (pid = -1;;) {
|
for (pid = -1;;) {
|
||||||
pid = rb_waitpid(-1, &status, 0);
|
pid = rb_waitpid(-1, &status, 0);
|
||||||
if (pid == -1) {
|
if (pid == -1) {
|
||||||
@ -809,7 +816,7 @@ proc_waitall(void)
|
|||||||
break;
|
break;
|
||||||
rb_sys_fail(0);
|
rb_sys_fail(0);
|
||||||
}
|
}
|
||||||
rb_ary_push(result, rb_assoc_new(INT2NUM(pid), rb_last_status));
|
rb_ary_push(result, rb_assoc_new(INT2NUM(pid), GET_VM()->last_status));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return result;
|
return result;
|
||||||
@ -822,7 +829,7 @@ detach_process_watcher(int *pid_p)
|
|||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
cpid = rb_waitpid(*pid_p, &status, WNOHANG);
|
cpid = rb_waitpid(*pid_p, &status, WNOHANG);
|
||||||
if (cpid != 0) return rb_last_status;
|
if (cpid != 0) return GET_VM()->last_status;
|
||||||
rb_thread_sleep(1);
|
rb_thread_sleep(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1601,7 +1608,7 @@ rb_f_system(int argc, VALUE *argv)
|
|||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
rb_sys_fail(RSTRING_PTR(argv[0]));
|
rb_sys_fail(RSTRING_PTR(argv[0]));
|
||||||
}
|
}
|
||||||
status = NUM2INT(rb_last_status);
|
status = NUM2INT(GET_VM()->last_status);
|
||||||
if (status == EXIT_SUCCESS) return Qtrue;
|
if (status == EXIT_SUCCESS) return Qtrue;
|
||||||
return Qfalse;
|
return Qfalse;
|
||||||
}
|
}
|
||||||
@ -3593,8 +3600,8 @@ VALUE rb_mProcID_Syscall;
|
|||||||
void
|
void
|
||||||
Init_process(void)
|
Init_process(void)
|
||||||
{
|
{
|
||||||
|
rb_define_virtual_variable("$?", last_status_get, 0);
|
||||||
rb_define_virtual_variable("$$", get_pid, 0);
|
rb_define_virtual_variable("$$", get_pid, 0);
|
||||||
rb_define_readonly_variable("$?", &rb_last_status);
|
|
||||||
rb_define_global_function("exec", rb_f_exec, -1);
|
rb_define_global_function("exec", rb_f_exec, -1);
|
||||||
rb_define_global_function("fork", rb_f_fork, 0);
|
rb_define_global_function("fork", rb_f_fork, 0);
|
||||||
rb_define_global_function("exit!", rb_f_exit_bang, -1);
|
rb_define_global_function("exit!", rb_f_exit_bang, -1);
|
||||||
|
2
ruby.h
2
ruby.h
@ -709,6 +709,8 @@ RUBY_EXTERN VALUE rb_cThread;
|
|||||||
RUBY_EXTERN VALUE rb_cTime;
|
RUBY_EXTERN VALUE rb_cTime;
|
||||||
RUBY_EXTERN VALUE rb_cTrueClass;
|
RUBY_EXTERN VALUE rb_cTrueClass;
|
||||||
RUBY_EXTERN VALUE rb_cUnboundMethod;
|
RUBY_EXTERN VALUE rb_cUnboundMethod;
|
||||||
|
RUBY_EXTERN VALUE rb_cISeq;
|
||||||
|
RUBY_EXTERN VALUE rb_cVM;
|
||||||
|
|
||||||
RUBY_EXTERN VALUE rb_eException;
|
RUBY_EXTERN VALUE rb_eException;
|
||||||
RUBY_EXTERN VALUE rb_eStandardError;
|
RUBY_EXTERN VALUE rb_eStandardError;
|
||||||
|
541
thread.c
541
thread.c
@ -47,6 +47,7 @@
|
|||||||
|
|
||||||
#include "eval_intern.h"
|
#include "eval_intern.h"
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
|
#include "gc.h"
|
||||||
|
|
||||||
#define THREAD_DEBUG 0
|
#define THREAD_DEBUG 0
|
||||||
|
|
||||||
@ -61,8 +62,6 @@ static int rb_thread_dead(yarv_thread_t *th);
|
|||||||
void rb_signal_exec(yarv_thread_t *th, int sig);
|
void rb_signal_exec(yarv_thread_t *th, int sig);
|
||||||
void rb_disable_interrupt();
|
void rb_disable_interrupt();
|
||||||
|
|
||||||
NOINLINE(void yarv_set_stack_end(VALUE **stack_end_p));
|
|
||||||
|
|
||||||
static VALUE eKillSignal = INT2FIX(0);
|
static VALUE eKillSignal = INT2FIX(0);
|
||||||
static VALUE eTerminateSignal = INT2FIX(1);
|
static VALUE eTerminateSignal = INT2FIX(1);
|
||||||
static volatile int system_working = 1;
|
static volatile int system_working = 1;
|
||||||
@ -261,12 +260,17 @@ thread_start_func_2(yarv_thread_t *th, VALUE *stack_start)
|
|||||||
|
|
||||||
TH_PUSH_TAG(th);
|
TH_PUSH_TAG(th);
|
||||||
if ((state = EXEC_TAG()) == 0) {
|
if ((state = EXEC_TAG()) == 0) {
|
||||||
GetProcPtr(th->first_proc, proc);
|
if (th->first_proc) {
|
||||||
th->errinfo = Qnil;
|
GetProcPtr(th->first_proc, proc);
|
||||||
th->local_lfp = proc->block.lfp;
|
th->errinfo = Qnil;
|
||||||
th->local_svar = Qnil;
|
th->local_lfp = proc->block.lfp;
|
||||||
th->value = th_invoke_proc(th, proc, proc->block.self,
|
th->local_svar = Qnil;
|
||||||
RARRAY_LEN(args), RARRAY_PTR(args));
|
th->value = th_invoke_proc(th, proc, proc->block.self,
|
||||||
|
RARRAY_LEN(args), RARRAY_PTR(args));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
(*th->first_func)(th->first_func_arg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
th->value = Qnil;
|
th->value = Qnil;
|
||||||
@ -292,19 +296,21 @@ thread_start_func_2(yarv_thread_t *th, VALUE *stack_start)
|
|||||||
VALUE yarv_thread_alloc(VALUE klass);
|
VALUE yarv_thread_alloc(VALUE klass);
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
yarv_thread_s_new(VALUE klass, VALUE args)
|
thread_create_core(VALUE klass, VALUE args, VALUE (*fn)(ANYARGS), void *arg)
|
||||||
{
|
{
|
||||||
yarv_thread_t *th;
|
yarv_thread_t *th;
|
||||||
VALUE thval;
|
VALUE thval;
|
||||||
|
|
||||||
/* create thread object */
|
/* create thread object */
|
||||||
thval = yarv_thread_alloc(cYarvThread);
|
thval = yarv_thread_alloc(klass);
|
||||||
GetThreadPtr(thval, th);
|
GetThreadPtr(thval, th);
|
||||||
|
|
||||||
/* setup thread environment */
|
/* setup thread environment */
|
||||||
th->first_args = args;
|
th->first_args = args;
|
||||||
th->first_proc = rb_block_proc();
|
th->first_proc = rb_block_proc();
|
||||||
|
th->first_func = fn;
|
||||||
|
th->first_func_arg = arg;
|
||||||
|
|
||||||
native_mutex_initialize(&th->interrupt_lock);
|
native_mutex_initialize(&th->interrupt_lock);
|
||||||
|
|
||||||
/* kick thread */
|
/* kick thread */
|
||||||
@ -313,18 +319,41 @@ yarv_thread_s_new(VALUE klass, VALUE args)
|
|||||||
return thval;
|
return thval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* Thread.start([args]*) {|args| block } => thread
|
||||||
|
* Thread.fork([args]*) {|args| block } => thread
|
||||||
|
*
|
||||||
|
* Basically the same as <code>Thread::new</code>. However, if class
|
||||||
|
* <code>Thread</code> is subclassed, then calling <code>start</code> in that
|
||||||
|
* subclass will not invoke the subclass's <code>initialize</code> method.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
thread_s_new(VALUE klass, VALUE args)
|
||||||
|
{
|
||||||
|
return thread_create_core(klass, args, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE
|
||||||
|
rb_thread_create(VALUE (*fn)(ANYARGS), void *arg)
|
||||||
|
{
|
||||||
|
return thread_create_core(rb_cThread, 0, fn, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* +infty, for this purpose */
|
/* +infty, for this purpose */
|
||||||
#define DELAY_INFTY 1E30
|
#define DELAY_INFTY 1E30
|
||||||
|
|
||||||
VALUE th_make_jump_tag_but_local_jump(int state, VALUE val);
|
VALUE th_make_jump_tag_but_local_jump(int state, VALUE val);
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
yarv_thread_join(yarv_thread_t *target_th, double delay)
|
thread_join(yarv_thread_t *target_th, double delay)
|
||||||
{
|
{
|
||||||
yarv_thread_t *th = GET_THREAD();
|
yarv_thread_t *th = GET_THREAD();
|
||||||
double now, limit = timeofday() + delay;
|
double now, limit = timeofday() + delay;
|
||||||
|
|
||||||
thread_debug("yarv_thread_join (thid: %p)\n", target_th->thread_id);
|
thread_debug("thread_join (thid: %p)\n", target_th->thread_id);
|
||||||
|
|
||||||
if (target_th->status != THREAD_KILLED) {
|
if (target_th->status != THREAD_KILLED) {
|
||||||
th->join_list_next = target_th->join_list_head;
|
th->join_list_next = target_th->join_list_head;
|
||||||
@ -338,17 +367,17 @@ yarv_thread_join(yarv_thread_t *target_th, double delay)
|
|||||||
else {
|
else {
|
||||||
now = timeofday();
|
now = timeofday();
|
||||||
if (now > limit) {
|
if (now > limit) {
|
||||||
thread_debug("yarv_thread_join: timeout (thid: %p)\n",
|
thread_debug("thread_join: timeout (thid: %p)\n",
|
||||||
target_th->thread_id);
|
target_th->thread_id);
|
||||||
return Qnil;
|
return Qnil;
|
||||||
}
|
}
|
||||||
sleep_wait_for_interrupt(th, limit - now);
|
sleep_wait_for_interrupt(th, limit - now);
|
||||||
}
|
}
|
||||||
thread_debug("yarv_thread_join: interrupted (thid: %p)\n",
|
thread_debug("thread_join: interrupted (thid: %p)\n",
|
||||||
target_th->thread_id);
|
target_th->thread_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
thread_debug("yarv_thread_join: success (thid: %p)\n",
|
thread_debug("thread_join: success (thid: %p)\n",
|
||||||
target_th->thread_id);
|
target_th->thread_id);
|
||||||
|
|
||||||
if (target_th->errinfo != Qnil) {
|
if (target_th->errinfo != Qnil) {
|
||||||
@ -409,7 +438,7 @@ yarv_thread_join(yarv_thread_t *target_th, double delay)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
yarv_thread_join_m(int argc, VALUE *argv, VALUE self)
|
thread_join_m(int argc, VALUE *argv, VALUE self)
|
||||||
{
|
{
|
||||||
yarv_thread_t *target_th;
|
yarv_thread_t *target_th;
|
||||||
double delay = DELAY_INFTY;
|
double delay = DELAY_INFTY;
|
||||||
@ -421,7 +450,7 @@ yarv_thread_join_m(int argc, VALUE *argv, VALUE self)
|
|||||||
if (!NIL_P(limit)) {
|
if (!NIL_P(limit)) {
|
||||||
delay = rb_num2dbl(limit);
|
delay = rb_num2dbl(limit);
|
||||||
}
|
}
|
||||||
return yarv_thread_join(target_th, delay);
|
return thread_join(target_th, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -436,11 +465,11 @@ yarv_thread_join_m(int argc, VALUE *argv, VALUE self)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
yarv_thread_value(VALUE self)
|
thread_value(VALUE self)
|
||||||
{
|
{
|
||||||
yarv_thread_t *th;
|
yarv_thread_t *th;
|
||||||
GetThreadPtr(self, th);
|
GetThreadPtr(self, th);
|
||||||
yarv_thread_join(th, DELAY_INFTY);
|
thread_join(th, DELAY_INFTY);
|
||||||
return th->value;
|
return th->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -538,7 +567,7 @@ rb_thread_schedule()
|
|||||||
|
|
||||||
thread_debug("rb_thread_schedule/switch start\n");
|
thread_debug("rb_thread_schedule/switch start\n");
|
||||||
|
|
||||||
yarv_save_machine_context(th);
|
rb_gc_save_machine_context(th);
|
||||||
native_mutex_unlock(&th->vm->global_interpreter_lock);
|
native_mutex_unlock(&th->vm->global_interpreter_lock);
|
||||||
{
|
{
|
||||||
native_thread_yield();
|
native_thread_yield();
|
||||||
@ -552,6 +581,7 @@ rb_thread_schedule()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int rb_thread_critical; /* TODO: dummy variable */
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
rb_thread_s_critical(VALUE self)
|
rb_thread_s_critical(VALUE self)
|
||||||
@ -596,7 +626,7 @@ rb_thread_run_parallel(VALUE(*func)(yarv_thread_t *th, void *), void *data)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
yarv_thread_s_pass(VALUE klass)
|
thread_s_pass(VALUE klass)
|
||||||
{
|
{
|
||||||
rb_thread_schedule();
|
rb_thread_schedule();
|
||||||
return Qnil;
|
return Qnil;
|
||||||
@ -712,6 +742,31 @@ rb_thread_signal_exit(void *thptr)
|
|||||||
yarv_thread_raise(1, argv, th->vm->main_thread);
|
yarv_thread_raise(1, argv, th->vm->main_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
thread_set_raised(yarv_thread_t *th)
|
||||||
|
{
|
||||||
|
if (th->raised_flag) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
th->raised_flag = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
thread_reset_raised(yarv_thread_t *th)
|
||||||
|
{
|
||||||
|
if (th->raised_flag == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
th->raised_flag = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_thread_fd_close(int fd)
|
||||||
|
{
|
||||||
|
/* TODO: fix me */
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
@ -733,7 +788,7 @@ rb_thread_signal_exit(void *thptr)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
yarv_thread_raise_m(int argc, VALUE *argv, VALUE self)
|
thread_raise_m(int argc, VALUE *argv, VALUE self)
|
||||||
{
|
{
|
||||||
yarv_thread_t *th;
|
yarv_thread_t *th;
|
||||||
GetThreadPtr(self, th);
|
GetThreadPtr(self, th);
|
||||||
@ -956,6 +1011,12 @@ rb_thread_list(void)
|
|||||||
return ary;
|
return ary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VALUE
|
||||||
|
rb_thread_current(void)
|
||||||
|
{
|
||||||
|
return GET_THREAD()->self;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
* Thread.current => thread
|
* Thread.current => thread
|
||||||
@ -966,9 +1027,9 @@ rb_thread_list(void)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
yarv_thread_s_current(VALUE klass)
|
thread_s_current(VALUE klass)
|
||||||
{
|
{
|
||||||
return GET_THREAD()->self;
|
return rb_thread_current();
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
@ -1468,35 +1529,132 @@ rb_thread_priority_set(VALUE thread, VALUE prio)
|
|||||||
|
|
||||||
/* for IO */
|
/* for IO */
|
||||||
|
|
||||||
|
#if defined(NFDBITS) && defined(HAVE_RB_FD_INIT)
|
||||||
|
void
|
||||||
|
rb_fd_init(volatile rb_fdset_t *fds)
|
||||||
|
{
|
||||||
|
fds->maxfd = 0;
|
||||||
|
fds->fdset = ALLOC(fd_set);
|
||||||
|
FD_ZERO(fds->fdset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_fd_term(rb_fdset_t *fds)
|
||||||
|
{
|
||||||
|
if (fds->fdset) free(fds->fdset);
|
||||||
|
fds->maxfd = 0;
|
||||||
|
fds->fdset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_fd_zero(rb_fdset_t *fds)
|
||||||
|
{
|
||||||
|
if (fds->fdset) {
|
||||||
|
MEMZERO(fds->fdset, fd_mask, howmany(fds->maxfd, NFDBITS));
|
||||||
|
FD_ZERO(fds->fdset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rb_fd_resize(int n, rb_fdset_t *fds)
|
||||||
|
{
|
||||||
|
int m = howmany(n + 1, NFDBITS) * sizeof(fd_mask);
|
||||||
|
int o = howmany(fds->maxfd, NFDBITS) * sizeof(fd_mask);
|
||||||
|
|
||||||
|
if (m < sizeof(fd_set)) m = sizeof(fd_set);
|
||||||
|
if (o < sizeof(fd_set)) o = sizeof(fd_set);
|
||||||
|
|
||||||
|
if (m > o) {
|
||||||
|
fds->fdset = realloc(fds->fdset, m);
|
||||||
|
memset((char *)fds->fdset + o, 0, m - o);
|
||||||
|
}
|
||||||
|
if (n >= fds->maxfd) fds->maxfd = n + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_fd_set(int n, rb_fdset_t *fds)
|
||||||
|
{
|
||||||
|
rb_fd_resize(n, fds);
|
||||||
|
FD_SET(n, fds->fdset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_fd_clr(int n, rb_fdset_t *fds)
|
||||||
|
{
|
||||||
|
if (n >= fds->maxfd) return;
|
||||||
|
FD_CLR(n, fds->fdset);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rb_fd_isset(int n, const rb_fdset_t *fds)
|
||||||
|
{
|
||||||
|
if (n >= fds->maxfd) return 0;
|
||||||
|
return FD_ISSET(n, fds->fdset) != 0; /* "!= 0" avoids FreeBSD PR 91421 */
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rb_fd_copy(rb_fdset_t *dst, const fd_set *src, int max)
|
||||||
|
{
|
||||||
|
int size = howmany(max, NFDBITS) * sizeof(fd_mask);
|
||||||
|
|
||||||
|
if (size < sizeof(fd_set)) size = sizeof(fd_set);
|
||||||
|
dst->maxfd = max;
|
||||||
|
dst->fdset = realloc(dst->fdset, size);
|
||||||
|
memcpy(dst->fdset, src, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef FD_ZERO
|
||||||
|
#undef FD_SET
|
||||||
|
#undef FD_CLR
|
||||||
|
#undef FD_ISSET
|
||||||
|
|
||||||
|
#define FD_ZERO(f) rb_fd_zero(f)
|
||||||
|
#define FD_SET(i, f) rb_fd_set(i, f)
|
||||||
|
#define FD_CLR(i, f) rb_fd_clr(i, f)
|
||||||
|
#define FD_ISSET(i, f) rb_fd_isset(i, f)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* c:
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
rb_thread_wait_fd_rw(int fd, char c)
|
||||||
|
{
|
||||||
|
rb_fdset_t set;
|
||||||
|
int result = 0;
|
||||||
|
rb_fd_init(&set);
|
||||||
|
FD_SET(fd, &set);
|
||||||
|
|
||||||
|
thread_debug("rb_thread_wait_fd_rw (%d, %c)\n", fd, c);
|
||||||
|
|
||||||
|
while (result <= 0) {
|
||||||
|
switch(c) {
|
||||||
|
case 'r':
|
||||||
|
GVL_UNLOCK_RANGE(result = select(fd + 1, rb_fd_ptr(&set), 0, 0, 0));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case'w':
|
||||||
|
GVL_UNLOCK_RANGE(result = select(fd + 1, 0, rb_fd_ptr(&set), 0, 0));
|
||||||
|
break;
|
||||||
|
defaut:
|
||||||
|
rb_bug("unknown wait type: %c", c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_debug("rb_thread_wait_fd_rw (%d, %c): done\n", fd, c);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rb_thread_wait_fd(int fd)
|
rb_thread_wait_fd(int fd)
|
||||||
{
|
{
|
||||||
fd_set set;
|
rb_thread_wait_fd_rw(fd, 'r');
|
||||||
int result = 0;
|
|
||||||
|
|
||||||
FD_ZERO(&set);
|
|
||||||
FD_SET(fd, &set);
|
|
||||||
thread_debug("rb_thread_wait_fd (%d)\n", fd);
|
|
||||||
while (result <= 0) {
|
|
||||||
GVL_UNLOCK_RANGE(result = select(fd + 1, &set, 0, 0, 0));
|
|
||||||
}
|
|
||||||
thread_debug("rb_thread_wait_fd done\n", fd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
rb_thread_fd_writable(int fd)
|
rb_thread_fd_writable(int fd)
|
||||||
{
|
{
|
||||||
fd_set set;
|
rb_thread_wait_fd_rw(fd, 'w');
|
||||||
int result = 0;
|
|
||||||
|
|
||||||
FD_ZERO(&set);
|
|
||||||
FD_SET(fd, &set);
|
|
||||||
|
|
||||||
thread_debug("rb_thread_fd_writable (%d)\n", fd);
|
|
||||||
while (result <= 0) {
|
|
||||||
GVL_UNLOCK_RANGE(result = select(fd + 1, 0, &set, 0, 0));
|
|
||||||
}
|
|
||||||
thread_debug("rb_thread_fd_writable done\n");
|
|
||||||
return Qtrue;
|
return Qtrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1569,16 +1727,16 @@ rb_thread_select(int max, fd_set * read, fd_set * write, fd_set * except,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
yarv_set_stack_end(VALUE **stack_end_p)
|
rb_gc_set_stack_end(VALUE **stack_end_p)
|
||||||
{
|
{
|
||||||
VALUE stack_end;
|
VALUE stack_end;
|
||||||
*stack_end_p = &stack_end;
|
*stack_end_p = &stack_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
yarv_save_machine_context(yarv_thread_t *th)
|
rb_gc_save_machine_context(yarv_thread_t *th)
|
||||||
{
|
{
|
||||||
yarv_set_stack_end(&th->machine_stack_end);
|
rb_gc_set_stack_end(&th->machine_stack_end);
|
||||||
setjmp(th->machine_regs);
|
setjmp(th->machine_regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1971,53 +2129,243 @@ mutex_sleep(int argc, VALUE *argv, VALUE self)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Document-class: Continuation
|
||||||
|
*
|
||||||
|
* Continuation objects are generated by
|
||||||
|
* <code>Kernel#callcc</code>. They hold a return address and execution
|
||||||
|
* context, allowing a nonlocal return to the end of the
|
||||||
|
* <code>callcc</code> block from anywhere within a program.
|
||||||
|
* Continuations are somewhat analogous to a structured version of C's
|
||||||
|
* <code>setjmp/longjmp</code> (although they contain more state, so
|
||||||
|
* you might consider them closer to threads).
|
||||||
|
*
|
||||||
|
* For instance:
|
||||||
|
*
|
||||||
|
* arr = [ "Freddie", "Herbie", "Ron", "Max", "Ringo" ]
|
||||||
|
* callcc{|$cc|}
|
||||||
|
* puts(message = arr.shift)
|
||||||
|
* $cc.call unless message =~ /Max/
|
||||||
|
*
|
||||||
|
* <em>produces:</em>
|
||||||
|
*
|
||||||
|
* Freddie
|
||||||
|
* Herbie
|
||||||
|
* Ron
|
||||||
|
* Max
|
||||||
|
*
|
||||||
|
* This (somewhat contrived) example allows the inner loop to abandon
|
||||||
|
* processing early:
|
||||||
|
*
|
||||||
|
* callcc {|cont|
|
||||||
|
* for i in 0..4
|
||||||
|
* print "\n#{i}: "
|
||||||
|
* for j in i*5...(i+1)*5
|
||||||
|
* cont.call() if j == 17
|
||||||
|
* printf "%3d", j
|
||||||
|
* end
|
||||||
|
* end
|
||||||
|
* }
|
||||||
|
* print "\n"
|
||||||
|
*
|
||||||
|
* <em>produces:</em>
|
||||||
|
*
|
||||||
|
* 0: 0 1 2 3 4
|
||||||
|
* 1: 5 6 7 8 9
|
||||||
|
* 2: 10 11 12 13 14
|
||||||
|
* 3: 15 16
|
||||||
|
*/
|
||||||
|
|
||||||
|
VALUE rb_cCont;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* callcc {|cont| block } => obj
|
||||||
|
*
|
||||||
|
* Generates a <code>Continuation</code> object, which it passes to the
|
||||||
|
* associated block. Performing a <em>cont</em><code>.call</code> will
|
||||||
|
* cause the <code>callcc</code> to return (as will falling through the
|
||||||
|
* end of the block). The value returned by the <code>callcc</code> is
|
||||||
|
* the value of the block, or the value passed to
|
||||||
|
* <em>cont</em><code>.call</code>. See class <code>Continuation</code>
|
||||||
|
* for more details. Also see <code>Kernel::throw</code> for
|
||||||
|
* an alternative mechanism for unwinding a call stack.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
rb_callcc(VALUE self)
|
||||||
|
{
|
||||||
|
UNSUPPORTED(rb_callcc);
|
||||||
|
return Qnil;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* cont.call(args, ...)
|
||||||
|
* cont[args, ...]
|
||||||
|
*
|
||||||
|
* Invokes the continuation. The program continues from the end of the
|
||||||
|
* <code>callcc</code> block. If no arguments are given, the original
|
||||||
|
* <code>callcc</code> returns <code>nil</code>. If one argument is
|
||||||
|
* given, <code>callcc</code> returns it. Otherwise, an array
|
||||||
|
* containing <i>args</i> is returned.
|
||||||
|
*
|
||||||
|
* 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 cont)
|
||||||
|
{
|
||||||
|
UNSUPPORTED(rb_cont_call);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* variables for recursive traversals */
|
||||||
|
static ID recursive_key;
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
recursive_check(VALUE obj)
|
||||||
|
{
|
||||||
|
VALUE hash = rb_thread_local_aref(rb_thread_current(), recursive_key);
|
||||||
|
|
||||||
|
if (NIL_P(hash) || TYPE(hash) != T_HASH) {
|
||||||
|
return Qfalse;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
VALUE list = rb_hash_aref(hash, ID2SYM(rb_frame_this_func()));
|
||||||
|
|
||||||
|
if (NIL_P(list) || TYPE(list) != T_ARRAY)
|
||||||
|
return Qfalse;
|
||||||
|
return rb_ary_includes(list, rb_obj_id(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
recursive_push(VALUE obj)
|
||||||
|
{
|
||||||
|
VALUE hash = rb_thread_local_aref(rb_thread_current(), recursive_key);
|
||||||
|
VALUE list, sym;
|
||||||
|
|
||||||
|
sym = ID2SYM(rb_frame_this_func());
|
||||||
|
if (NIL_P(hash) || TYPE(hash) != T_HASH) {
|
||||||
|
hash = rb_hash_new();
|
||||||
|
rb_thread_local_aset(rb_thread_current(), recursive_key, hash);
|
||||||
|
list = Qnil;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
list = rb_hash_aref(hash, sym);
|
||||||
|
}
|
||||||
|
if (NIL_P(list) || TYPE(list) != T_ARRAY) {
|
||||||
|
list = rb_ary_new();
|
||||||
|
rb_hash_aset(hash, sym, list);
|
||||||
|
}
|
||||||
|
rb_ary_push(list, rb_obj_id(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
recursive_pop(void)
|
||||||
|
{
|
||||||
|
VALUE hash = rb_thread_local_aref(rb_thread_current(), recursive_key);
|
||||||
|
VALUE list, sym;
|
||||||
|
|
||||||
|
sym = ID2SYM(rb_frame_this_func());
|
||||||
|
if (NIL_P(hash) || TYPE(hash) != T_HASH) {
|
||||||
|
VALUE symname;
|
||||||
|
VALUE thrname;
|
||||||
|
symname = rb_inspect(sym);
|
||||||
|
thrname = rb_inspect(rb_thread_current());
|
||||||
|
|
||||||
|
rb_raise(rb_eTypeError, "invalid inspect_tbl hash for %s in %s",
|
||||||
|
StringValuePtr(symname), StringValuePtr(thrname));
|
||||||
|
}
|
||||||
|
list = rb_hash_aref(hash, sym);
|
||||||
|
if (NIL_P(list) || TYPE(list) != T_ARRAY) {
|
||||||
|
VALUE symname = rb_inspect(sym);
|
||||||
|
VALUE thrname = rb_inspect(rb_thread_current());
|
||||||
|
rb_raise(rb_eTypeError, "invalid inspect_tbl list for %s in %s",
|
||||||
|
StringValuePtr(symname), StringValuePtr(thrname));
|
||||||
|
}
|
||||||
|
rb_ary_pop(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
VALUE
|
||||||
|
rb_exec_recursive(VALUE (*func) (VALUE, VALUE, int), VALUE obj, VALUE arg)
|
||||||
|
{
|
||||||
|
if (recursive_check(obj)) {
|
||||||
|
return (*func) (obj, arg, Qtrue);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
VALUE result = Qundef;
|
||||||
|
int state;
|
||||||
|
|
||||||
|
recursive_push(obj);
|
||||||
|
PUSH_TAG(PROT_NONE);
|
||||||
|
if ((state = EXEC_TAG()) == 0) {
|
||||||
|
result = (*func) (obj, arg, Qfalse);
|
||||||
|
}
|
||||||
|
POP_TAG();
|
||||||
|
recursive_pop();
|
||||||
|
if (state)
|
||||||
|
JUMP_TAG(state);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* +Thread+ encapsulates the behavior of a thread of
|
||||||
|
* execution, including the main thread of the Ruby script.
|
||||||
|
*
|
||||||
|
* In the descriptions of the methods in this class, the parameter _sym_
|
||||||
|
* refers to a symbol, which is either a quoted string or a
|
||||||
|
* +Symbol+ (such as <code>:name</code>).
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
Init_yarvthread()
|
Init_Thread(void)
|
||||||
{
|
{
|
||||||
VALUE cThGroup;
|
VALUE cThGroup;
|
||||||
VALUE thgroup_default;
|
|
||||||
VALUE cMutex;
|
VALUE cMutex;
|
||||||
|
|
||||||
rb_define_global_function("raw_gets", raw_gets, 0);
|
rb_define_singleton_method(rb_cThread, "new", thread_s_new, -2);
|
||||||
|
rb_define_singleton_method(rb_cThread, "start", thread_s_new, -2);
|
||||||
|
rb_define_singleton_method(rb_cThread, "fork", thread_s_new, -2);
|
||||||
|
rb_define_singleton_method(rb_cThread, "main", rb_thread_s_main, 0);
|
||||||
|
rb_define_singleton_method(rb_cThread, "current", thread_s_current, 0);
|
||||||
|
rb_define_singleton_method(rb_cThread, "stop", rb_thread_stop, 0);
|
||||||
|
rb_define_singleton_method(rb_cThread, "kill", rb_thread_s_kill, 1);
|
||||||
|
rb_define_singleton_method(rb_cThread, "exit", rb_thread_exit, 0);
|
||||||
|
rb_define_singleton_method(rb_cThread, "pass", thread_s_pass, 0);
|
||||||
|
rb_define_singleton_method(rb_cThread, "list", rb_thread_list, 0);
|
||||||
|
rb_define_singleton_method(rb_cThread, "critical", rb_thread_s_critical, 0);
|
||||||
|
rb_define_singleton_method(rb_cThread, "critical=", rb_thread_s_critical, 1);
|
||||||
|
rb_define_singleton_method(rb_cThread, "abort_on_exception", rb_thread_s_abort_exc, 0);
|
||||||
|
rb_define_singleton_method(rb_cThread, "abort_on_exception=", rb_thread_s_abort_exc_set, 1);
|
||||||
|
|
||||||
rb_define_singleton_method(cYarvThread, "new", yarv_thread_s_new, -2);
|
rb_define_method(rb_cThread, "raise", thread_raise_m, -1);
|
||||||
rb_define_singleton_method(cYarvThread, "start", yarv_thread_s_new, -2);
|
rb_define_method(rb_cThread, "join", thread_join_m, -1);
|
||||||
rb_define_singleton_method(cYarvThread, "fork", yarv_thread_s_new, -2);
|
rb_define_method(rb_cThread, "value", thread_value, 0);
|
||||||
rb_define_singleton_method(cYarvThread, "main", rb_thread_s_main, 0);
|
rb_define_method(rb_cThread, "kill", rb_thread_kill, 0);
|
||||||
rb_define_singleton_method(cYarvThread, "current", yarv_thread_s_current, 0);
|
rb_define_method(rb_cThread, "terminate", rb_thread_kill, 0);
|
||||||
rb_define_singleton_method(cYarvThread, "stop", rb_thread_stop, 0);
|
rb_define_method(rb_cThread, "exit", rb_thread_kill, 0);
|
||||||
rb_define_singleton_method(cYarvThread, "kill", rb_thread_s_kill, 1);
|
rb_define_method(rb_cThread, "run", rb_thread_run, 0);
|
||||||
rb_define_singleton_method(cYarvThread, "exit", rb_thread_exit, 0);
|
rb_define_method(rb_cThread, "wakeup", rb_thread_wakeup, 0);
|
||||||
rb_define_singleton_method(cYarvThread, "pass", yarv_thread_s_pass, 0);
|
rb_define_method(rb_cThread, "[]", rb_thread_aref, 1);
|
||||||
rb_define_singleton_method(cYarvThread, "list", rb_thread_list, 0);
|
rb_define_method(rb_cThread, "[]=", rb_thread_aset, 2);
|
||||||
rb_define_singleton_method(cYarvThread, "critical", rb_thread_s_critical, 0);
|
rb_define_method(rb_cThread, "key?", rb_thread_key_p, 1);
|
||||||
rb_define_singleton_method(cYarvThread, "critical=", rb_thread_s_critical, 1);
|
rb_define_method(rb_cThread, "keys", rb_thread_keys, 0);
|
||||||
rb_define_singleton_method(cYarvThread, "abort_on_exception", rb_thread_s_abort_exc, 0);
|
rb_define_method(rb_cThread, "priority", rb_thread_priority, 0);
|
||||||
rb_define_singleton_method(cYarvThread, "abort_on_exception=", rb_thread_s_abort_exc_set, 1);
|
rb_define_method(rb_cThread, "priority=", rb_thread_priority_set, 1);
|
||||||
|
rb_define_method(rb_cThread, "status", rb_thread_status, 0);
|
||||||
|
rb_define_method(rb_cThread, "alive?", rb_thread_alive_p, 0);
|
||||||
|
rb_define_method(rb_cThread, "stop?", rb_thread_stop_p, 0);
|
||||||
|
rb_define_method(rb_cThread, "abort_on_exception", rb_thread_abort_exc, 0);
|
||||||
|
rb_define_method(rb_cThread, "abort_on_exception=", rb_thread_abort_exc_set, 1);
|
||||||
|
rb_define_method(rb_cThread, "safe_level", rb_thread_safe_level, 0);
|
||||||
|
rb_define_method(rb_cThread, "group", rb_thread_group, 0);
|
||||||
|
|
||||||
rb_define_method(cYarvThread, "raise", yarv_thread_raise_m, -1);
|
rb_define_method(rb_cThread, "inspect", rb_thread_inspect, 0);
|
||||||
rb_define_method(cYarvThread, "join", yarv_thread_join_m, -1);
|
|
||||||
rb_define_method(cYarvThread, "value", yarv_thread_value, 0);
|
|
||||||
rb_define_method(cYarvThread, "kill", rb_thread_kill, 0);
|
|
||||||
rb_define_method(cYarvThread, "terminate", rb_thread_kill, 0);
|
|
||||||
rb_define_method(cYarvThread, "exit", rb_thread_kill, 0);
|
|
||||||
rb_define_method(cYarvThread, "run", rb_thread_run, 0);
|
|
||||||
rb_define_method(cYarvThread, "wakeup", rb_thread_wakeup, 0);
|
|
||||||
rb_define_method(cYarvThread, "[]", rb_thread_aref, 1);
|
|
||||||
rb_define_method(cYarvThread, "[]=", rb_thread_aset, 2);
|
|
||||||
rb_define_method(cYarvThread, "key?", rb_thread_key_p, 1);
|
|
||||||
rb_define_method(cYarvThread, "keys", rb_thread_keys, 0);
|
|
||||||
rb_define_method(cYarvThread, "priority", rb_thread_priority, 0);
|
|
||||||
rb_define_method(cYarvThread, "priority=", rb_thread_priority_set, 1);
|
|
||||||
rb_define_method(cYarvThread, "status", rb_thread_status, 0);
|
|
||||||
rb_define_method(cYarvThread, "alive?", rb_thread_alive_p, 0);
|
|
||||||
rb_define_method(cYarvThread, "stop?", rb_thread_stop_p, 0);
|
|
||||||
rb_define_method(cYarvThread, "abort_on_exception", rb_thread_abort_exc, 0);
|
|
||||||
rb_define_method(cYarvThread, "abort_on_exception=", rb_thread_abort_exc_set, 1);
|
|
||||||
rb_define_method(cYarvThread, "safe_level", rb_thread_safe_level, 0);
|
|
||||||
rb_define_method(cYarvThread, "group", rb_thread_group, 0);
|
|
||||||
|
|
||||||
rb_define_method(cYarvThread, "inspect", rb_thread_inspect, 0);
|
|
||||||
|
|
||||||
cThGroup = rb_define_class("ThreadGroup", rb_cObject);
|
cThGroup = rb_define_class("ThreadGroup", rb_cObject);
|
||||||
rb_define_alloc_func(cThGroup, thgroup_s_alloc);
|
rb_define_alloc_func(cThGroup, thgroup_s_alloc);
|
||||||
@ -2025,8 +2373,12 @@ Init_yarvthread()
|
|||||||
rb_define_method(cThGroup, "enclose", thgroup_enclose, 0);
|
rb_define_method(cThGroup, "enclose", thgroup_enclose, 0);
|
||||||
rb_define_method(cThGroup, "enclosed?", thgroup_enclosed_p, 0);
|
rb_define_method(cThGroup, "enclosed?", thgroup_enclosed_p, 0);
|
||||||
rb_define_method(cThGroup, "add", thgroup_add, 1);
|
rb_define_method(cThGroup, "add", thgroup_add, 1);
|
||||||
GET_THREAD()->vm->thgroup_default = thgroup_default = rb_obj_alloc(cThGroup);
|
|
||||||
rb_define_const(cThGroup, "Default", thgroup_default);
|
{
|
||||||
|
yarv_thread_t *th = GET_THREAD();
|
||||||
|
th->thgroup = th->vm->thgroup_default = rb_obj_alloc(cThGroup);
|
||||||
|
rb_define_const(cThGroup, "Default", th->thgroup);
|
||||||
|
}
|
||||||
|
|
||||||
cMutex = rb_define_class("Mutex", rb_cObject);
|
cMutex = rb_define_class("Mutex", rb_cObject);
|
||||||
rb_define_alloc_func(cMutex, mutex_alloc);
|
rb_define_alloc_func(cMutex, mutex_alloc);
|
||||||
@ -2040,6 +2392,11 @@ Init_yarvthread()
|
|||||||
"class Mutex;"
|
"class Mutex;"
|
||||||
" def synchronize; self.lock; yield; ensure; self.unlock; end;"
|
" def synchronize; self.lock; yield; ensure; self.unlock; end;"
|
||||||
"end;") , rb_str_new2("<preload>"), INT2FIX(1));
|
"end;") , rb_str_new2("<preload>"), INT2FIX(1));
|
||||||
|
|
||||||
|
recursive_key = rb_intern("__recursive_key__");
|
||||||
|
rb_eThreadError = rb_define_class("ThreadError", rb_eStandardError);
|
||||||
|
rb_cCont = rb_define_class("Continuation", rb_cObject);
|
||||||
|
|
||||||
Init_native_thread();
|
Init_native_thread();
|
||||||
{
|
{
|
||||||
/* main thread setting */
|
/* main thread setting */
|
||||||
|
4
vm.c
4
vm.c
@ -5,7 +5,7 @@
|
|||||||
$Author$
|
$Author$
|
||||||
$Date$
|
$Date$
|
||||||
|
|
||||||
Copyright (C) 2004-2006 Koichi Sasada
|
Copyright (C) 2004-2007 Koichi Sasada
|
||||||
|
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
|
||||||
@ -1488,7 +1488,7 @@ yarv_init_redefined_flag()
|
|||||||
VALUE *dfp; // lfp
|
VALUE *dfp; // lfp
|
||||||
yarv_iseq_t * block_iseq; // 0
|
yarv_iseq_t * block_iseq; // 0
|
||||||
};
|
};
|
||||||
|
|
||||||
struct C_METHDO_FRAME{
|
struct C_METHDO_FRAME{
|
||||||
VALUE block_ptr;
|
VALUE block_ptr;
|
||||||
VALUE special;
|
VALUE special;
|
||||||
|
37
yarvcore.c
37
yarvcore.c
@ -17,8 +17,8 @@
|
|||||||
#include "yarv.h"
|
#include "yarv.h"
|
||||||
#include "gc.h"
|
#include "gc.h"
|
||||||
|
|
||||||
VALUE cYarvThread;
|
|
||||||
VALUE rb_cVM;
|
VALUE rb_cVM;
|
||||||
|
VALUE rb_cThread;
|
||||||
|
|
||||||
VALUE symIFUNC;
|
VALUE symIFUNC;
|
||||||
VALUE symCFUNC;
|
VALUE symCFUNC;
|
||||||
@ -257,6 +257,7 @@ vm_mark(void *ptr)
|
|||||||
}
|
}
|
||||||
MARK_UNLESS_NULL(vm->thgroup_default);
|
MARK_UNLESS_NULL(vm->thgroup_default);
|
||||||
MARK_UNLESS_NULL(vm->mark_object_ary);
|
MARK_UNLESS_NULL(vm->mark_object_ary);
|
||||||
|
MARK_UNLESS_NULL(vm->last_status);
|
||||||
}
|
}
|
||||||
MARK_REPORT_LEAVE("vm");
|
MARK_REPORT_LEAVE("vm");
|
||||||
}
|
}
|
||||||
@ -279,7 +280,6 @@ vm_init2(yarv_vm_t *vm)
|
|||||||
MEMZERO(vm, yarv_vm_t, 1);
|
MEMZERO(vm, yarv_vm_t, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**********/
|
/**********/
|
||||||
/* Thread */
|
/* Thread */
|
||||||
/**********/
|
/**********/
|
||||||
@ -402,7 +402,7 @@ th_init2(yarv_thread_t *th)
|
|||||||
th->cfp->iseq = 0;
|
th->cfp->iseq = 0;
|
||||||
th->cfp->proc = 0;
|
th->cfp->proc = 0;
|
||||||
th->cfp->block_iseq = 0;
|
th->cfp->block_iseq = 0;
|
||||||
|
|
||||||
th->status = THREAD_RUNNABLE;
|
th->status = THREAD_RUNNABLE;
|
||||||
th->errinfo = Qnil;
|
th->errinfo = Qnil;
|
||||||
|
|
||||||
@ -467,7 +467,6 @@ yarv_th_eval(yarv_thread_t *th, VALUE iseqval)
|
|||||||
/********************************************************************/
|
/********************************************************************/
|
||||||
|
|
||||||
VALUE insns_name_array(void);
|
VALUE insns_name_array(void);
|
||||||
VALUE Init_yarvthread(void);
|
|
||||||
extern VALUE *rb_gc_stack_start;
|
extern VALUE *rb_gc_stack_start;
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
@ -531,17 +530,18 @@ char *yarv_options = ""
|
|||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
void Init_ISeq(void);
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Init_vm(void)
|
Init_VM(void)
|
||||||
{
|
{
|
||||||
Init_ISeq();
|
|
||||||
|
|
||||||
/* ::VM */
|
/* ::VM */
|
||||||
rb_cVM = rb_define_class("VM", rb_cObject);
|
rb_cVM = rb_define_class("VM", rb_cObject);
|
||||||
rb_undef_alloc_func(rb_cVM);
|
rb_undef_alloc_func(rb_cVM);
|
||||||
|
|
||||||
|
/* ::Thread */
|
||||||
|
rb_cThread = rb_define_class("Thread", rb_cObject);
|
||||||
|
rb_undef_alloc_func(rb_cThread);
|
||||||
|
rb_define_method(rb_cThread, "initialize", thread_init, 0);
|
||||||
|
|
||||||
/* ::VM::USAGE_ANALISYS_* */
|
/* ::VM::USAGE_ANALISYS_* */
|
||||||
rb_define_const(rb_cVM, "USAGE_ANALISYS_INSN", rb_hash_new());
|
rb_define_const(rb_cVM, "USAGE_ANALISYS_INSN", rb_hash_new());
|
||||||
rb_define_const(rb_cVM, "USAGE_ANALISYS_REGS", rb_hash_new());
|
rb_define_const(rb_cVM, "USAGE_ANALISYS_REGS", rb_hash_new());
|
||||||
@ -554,13 +554,7 @@ Init_vm(void)
|
|||||||
/* ::VM::eval() */
|
/* ::VM::eval() */
|
||||||
rb_define_singleton_method(rb_cVM, "eval", yarvcore_eval, 3);
|
rb_define_singleton_method(rb_cVM, "eval", yarvcore_eval, 3);
|
||||||
|
|
||||||
/* ::VM::Thread */
|
/* debug functions ::VM::SDR(), ::VM::NSDR() */
|
||||||
cYarvThread = rb_define_class_under(rb_cVM, "Thread", rb_cObject);
|
|
||||||
rb_define_global_const("Thread", cYarvThread);
|
|
||||||
rb_undef_alloc_func(cYarvThread);
|
|
||||||
rb_define_method(cYarvThread, "initialize", thread_init, 0);
|
|
||||||
|
|
||||||
/* debug functions */
|
|
||||||
rb_define_singleton_method(rb_cVM, "SDR", sdr, 0);
|
rb_define_singleton_method(rb_cVM, "SDR", sdr, 0);
|
||||||
rb_define_singleton_method(rb_cVM, "NSDR", sdr, 0);
|
rb_define_singleton_method(rb_cVM, "NSDR", sdr, 0);
|
||||||
|
|
||||||
@ -610,10 +604,7 @@ Init_vm(void)
|
|||||||
idFuncall = rb_intern("funcall");
|
idFuncall = rb_intern("funcall");
|
||||||
id__send_bang = rb_intern("__send!");
|
id__send_bang = rb_intern("__send!");
|
||||||
|
|
||||||
#if TEST_AOT_COMPILE
|
/* VM bootstrap: phase 2 */
|
||||||
Init_compiled();
|
|
||||||
#endif
|
|
||||||
/* VM bootstrap: phase 1 */
|
|
||||||
{
|
{
|
||||||
/* create vm object */
|
/* create vm object */
|
||||||
VALUE vmval = vm_alloc(rb_cVM);
|
VALUE vmval = vm_alloc(rb_cVM);
|
||||||
@ -632,7 +623,7 @@ Init_vm(void)
|
|||||||
rb_ary_push(yarvVMArray, vm->self);
|
rb_ary_push(yarvVMArray, vm->self);
|
||||||
|
|
||||||
/* create main thread */
|
/* create main thread */
|
||||||
thval = yarv_thread_alloc(cYarvThread);
|
thval = yarv_thread_alloc(rb_cThread);
|
||||||
GetThreadPtr(thval, th);
|
GetThreadPtr(thval, th);
|
||||||
|
|
||||||
vm->main_thread = th;
|
vm->main_thread = th;
|
||||||
@ -645,9 +636,6 @@ Init_vm(void)
|
|||||||
th->machine_stack_start = rb_gc_stack_start;
|
th->machine_stack_start = rb_gc_stack_start;
|
||||||
vm->living_threads = st_init_numtable();
|
vm->living_threads = st_init_numtable();
|
||||||
st_insert(vm->living_threads, th->self, (st_data_t) th->thread_id);
|
st_insert(vm->living_threads, th->self, (st_data_t) th->thread_id);
|
||||||
|
|
||||||
Init_yarvthread();
|
|
||||||
th->thgroup = th->vm->thgroup_default;
|
|
||||||
}
|
}
|
||||||
yarv_init_redefined_flag();
|
yarv_init_redefined_flag();
|
||||||
}
|
}
|
||||||
@ -667,3 +655,4 @@ Init_yarv(void)
|
|||||||
th->machine_stack_start = rb_gc_stack_start;
|
th->machine_stack_start = rb_gc_stack_start;
|
||||||
yarv_set_current_running_thread_raw(th);
|
yarv_set_current_running_thread_raw(th);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
yarvcore.h
20
yarvcore.h
@ -23,6 +23,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#include "ruby.h"
|
#include "ruby.h"
|
||||||
#include "st.h"
|
#include "st.h"
|
||||||
|
#include "node.h"
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "vm_opts.h"
|
#include "vm_opts.h"
|
||||||
@ -97,13 +98,7 @@
|
|||||||
#define GCDEBUG 0
|
#define GCDEBUG 0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* classes and modules */
|
/* classes and modules */
|
||||||
extern VALUE cYarvVM;
|
|
||||||
extern VALUE cYarvThread;
|
|
||||||
extern VALUE rb_cISeq;
|
|
||||||
extern VALUE rb_cVM;
|
|
||||||
|
|
||||||
extern VALUE symIFUNC;
|
extern VALUE symIFUNC;
|
||||||
extern VALUE symCFUNC;
|
extern VALUE symCFUNC;
|
||||||
@ -326,10 +321,11 @@ typedef struct yarv_vm_struct {
|
|||||||
|
|
||||||
st_table *living_threads;
|
st_table *living_threads;
|
||||||
VALUE thgroup_default;
|
VALUE thgroup_default;
|
||||||
|
VALUE last_status; /* $? */
|
||||||
|
|
||||||
int thread_abort_on_exception;
|
int thread_abort_on_exception;
|
||||||
int exit_code;
|
|
||||||
unsigned long trace_flag;
|
unsigned long trace_flag;
|
||||||
|
int exit_code;
|
||||||
|
|
||||||
/* object management */
|
/* object management */
|
||||||
VALUE mark_object_ary;
|
VALUE mark_object_ary;
|
||||||
@ -457,6 +453,8 @@ typedef struct yarv_thread_struct
|
|||||||
|
|
||||||
VALUE first_proc;
|
VALUE first_proc;
|
||||||
VALUE first_args;
|
VALUE first_args;
|
||||||
|
VALUE (*first_func)(ANYARGS);
|
||||||
|
void *first_func_arg;
|
||||||
|
|
||||||
/* for GC */
|
/* for GC */
|
||||||
VALUE *machine_stack_start;
|
VALUE *machine_stack_start;
|
||||||
@ -612,7 +610,7 @@ extern void vm_stack_dump_raw(yarv_thread_t *, yarv_control_frame_t *);
|
|||||||
|
|
||||||
#define GVL_UNLOCK_BEGIN() do { \
|
#define GVL_UNLOCK_BEGIN() do { \
|
||||||
yarv_thread_t *_th_stored = GET_THREAD(); \
|
yarv_thread_t *_th_stored = GET_THREAD(); \
|
||||||
yarv_save_machine_context(_th_stored); \
|
rb_gc_save_machine_context(_th_stored); \
|
||||||
native_mutex_unlock(&_th_stored->vm->global_interpreter_lock)
|
native_mutex_unlock(&_th_stored->vm->global_interpreter_lock)
|
||||||
|
|
||||||
#define GVL_UNLOCK_END() \
|
#define GVL_UNLOCK_END() \
|
||||||
@ -620,10 +618,8 @@ extern void vm_stack_dump_raw(yarv_thread_t *, yarv_control_frame_t *);
|
|||||||
yarv_set_current_running_thread(_th_stored); \
|
yarv_set_current_running_thread(_th_stored); \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
NOINLINE(void yarv_set_stack_end(VALUE **stack_end_p));
|
NOINLINE(void rb_gc_set_stack_end(VALUE **stack_end_p));
|
||||||
NOINLINE(void yarv_save_machine_context(yarv_thread_t *));
|
NOINLINE(void rb_gc_save_machine_context(yarv_thread_t *));
|
||||||
|
|
||||||
extern int rb_thread_pending;
|
|
||||||
|
|
||||||
void yarv_thread_execute_interrupts(yarv_thread_t *);
|
void yarv_thread_execute_interrupts(yarv_thread_t *);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user