summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog31
-rw-r--r--common.mk6
-rw-r--r--eval_thread.c683
-rw-r--r--gc.c12
-rw-r--r--gc.h9
-rw-r--r--inits.c78
-rw-r--r--io.c3
-rw-r--r--process.c33
-rw-r--r--ruby.h2
-rw-r--r--thread.c535
-rw-r--r--vm.c4
-rw-r--r--yarvcore.c37
-rw-r--r--yarvcore.h20
13 files changed, 576 insertions, 877 deletions
diff --git a/ChangeLog b/ChangeLog
index ec4e9acdce..2334dbcdb4 100644
--- a/ChangeLog
+++ b/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>
* eval.c (rb_frame_callee): check if prev_cfp can be accessible.
diff --git a/common.mk b/common.mk
index 7a63492083..293f58e946 100644
--- a/common.mk
+++ b/common.mk
@@ -32,7 +32,6 @@ OBJS = array.$(OBJEXT) \
eval.$(OBJEXT) \
eval_load.$(OBJEXT) \
proc.$(OBJEXT) \
- eval_thread.$(OBJEXT) \
file.$(OBJEXT) \
gc.$(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)}node.h {$(VPATH)}util.h {$(VPATH)}yarvcore.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 \
{$(VPATH)}ruby.h config.h {$(VPATH)}yarvcore.h \
{$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
diff --git a/eval_thread.c b/eval_thread.c
deleted file mode 100644
index 5e29fc814a..0000000000
--- a/eval_thread.c
+++ /dev/null
@@ -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
diff --git a/gc.c b/gc.c
index bf8e29def2..8b6aab0fcb 100644
--- a/gc.c
+++ b/gc.c
@@ -539,9 +539,7 @@ rb_data_object_alloc(VALUE klass, void *datap, RUBY_DATA_FUNC dmark, RUBY_DATA_F
return (VALUE)data;
}
-NOINLINE(void yarv_set_stack_end(VALUE **stack_end_p));
-
-#define YARV_SET_STACK_END yarv_set_stack_end(&th->machine_stack_end)
+#define SET_STACK_END rb_gc_set_stack_end(&th->machine_stack_end)
#define STACK_START (th->machine_stack_start)
#define STACK_END (th->machine_stack_end)
@@ -565,7 +563,7 @@ static int
stack_grow_direction(VALUE *addr)
{
yarv_thread_t *th = GET_THREAD();
- YARV_SET_STACK_END;
+ SET_STACK_END;
if (STACK_END > addr) return grow_direction = 1;
return grow_direction = -1;
@@ -577,7 +575,7 @@ stack_grow_direction(VALUE *addr)
#define GC_WATER_MARK 512
#define CHECK_STACK(ret) do {\
- YARV_SET_STACK_END;\
+ SET_STACK_END;\
(ret) = (STACK_LENGTH > STACK_LEVEL_MAX + GC_WATER_MARK);\
} while (0)
@@ -585,7 +583,7 @@ int
ruby_stack_length(VALUE **p)
{
yarv_thread_t *th = GET_THREAD();
- YARV_SET_STACK_END;
+ SET_STACK_END;
if (p) *p = STACK_UPPER(STACK_END, STACK_START, STACK_END);
return STACK_LENGTH;
}
@@ -1355,7 +1353,7 @@ garbage_collect(void)
}
during_gc++;
- YARV_SET_STACK_END;
+ SET_STACK_END;
init_mark_stack();
diff --git a/gc.h b/gc.h
index 3b2272bf64..b9b1eb4ece 100644
--- a/gc.h
+++ b/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
#define MARK_FREE_DEBUG 0
#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 FREE_UNLESS_NULL(ptr) if(ptr){ruby_xfree(ptr);}
+#endif /* RUBY_GC_H */
+
diff --git a/inits.c b/inits.c
index 5087f7c9cf..568d450dbb 100644
--- a/inits.c
+++ b/inits.c
@@ -12,43 +12,42 @@
#include "ruby.h"
-void Init_Array _((void));
-void Init_Bignum _((void));
-void Init_Binding _((void));
-void Init_Comparable _((void));
-void Init_Dir _((void));
-void Init_Enumerable _((void));
-void Init_Enumerator _((void));
-void Init_Exception _((void));
-void Init_syserr _((void));
-void Init_eval _((void));
-void Init_load _((void));
-void Init_Proc _((void));
-void Init_Thread _((void));
-void Init_File _((void));
-void Init_GC _((void));
-void Init_Hash _((void));
-void Init_IO _((void));
-void Init_Math _((void));
-void Init_marshal _((void));
-void Init_Numeric _((void));
-void Init_Object _((void));
-void Init_pack _((void));
-void Init_Precision _((void));
-void Init_sym _((void));
-void Init_process _((void));
-void Init_Random _((void));
-void Init_Range _((void));
-void Init_Regexp _((void));
-void Init_signal _((void));
-void Init_String _((void));
-void Init_Struct _((void));
-void Init_Time _((void));
-void Init_var_tables _((void));
-void Init_version _((void));
-void Init_jump _((void));
-void Init_vm _((void));
-
+void Init_Array(void);
+void Init_Bignum(void);
+void Init_Binding(void);
+void Init_Comparable(void);
+void Init_Dir(void);
+void Init_Enumerable(void);
+void Init_Enumerator(void);
+void Init_Exception(void);
+void Init_syserr(void);
+void Init_eval(void);
+void Init_load(void);
+void Init_Proc(void);
+void Init_File(void);
+void Init_GC(void);
+void Init_Hash(void);
+void Init_IO(void);
+void Init_Math(void);
+void Init_marshal(void);
+void Init_Numeric(void);
+void Init_Object(void);
+void Init_pack(void);
+void Init_Precision(void);
+void Init_sym(void);
+void Init_process(void);
+void Init_Random(void);
+void Init_Range(void);
+void Init_Regexp(void);
+void Init_signal(void);
+void Init_String(void);
+void Init_Struct(void);
+void Init_Time(void);
+void Init_var_tables(void);
+void Init_version(void);
+void Init_ISeq(void);
+void Init_VM(void);
+void Init_Thread(void);
void
rb_call_inits()
@@ -63,7 +62,6 @@ rb_call_inits()
Init_jump();
Init_String();
Init_Exception();
- Init_Thread();
Init_Numeric();
Init_Bignum();
Init_syserr();
@@ -86,6 +84,8 @@ rb_call_inits()
Init_GC();
Init_marshal();
Init_Enumerator();
- Init_vm();
+ Init_ISeq();
+ Init_VM();
+ Init_Thread();
Init_version();
}
diff --git a/io.c b/io.c
index 709623d8c0..66203cdbbf 100644
--- a/io.c
+++ b/io.c
@@ -2970,7 +2970,6 @@ static void
pipe_finalize(OpenFile *fptr, int noraise)
{
#if !defined(HAVE_FORK) && !defined(_WIN32)
- extern VALUE rb_last_status;
int status;
if (fptr->stdio_file) {
status = pclose(fptr->stdio_file);
@@ -2980,7 +2979,7 @@ pipe_finalize(OpenFile *fptr, int noraise)
#if defined DJGPP
status <<= 8;
#endif
- rb_last_status = INT2FIX(status);
+ /* TODO: need it? -> rb_last_status = INT2FIX(status); */
#else
fptr_finalize(fptr, noraise);
#endif
diff --git a/process.c b/process.c
index 25f62a6327..ed975dbbb1 100644
--- a/process.c
+++ b/process.c
@@ -14,6 +14,8 @@
#include "ruby.h"
#include "rubysig.h"
+#include "yarvcore.h"
+
#include <stdio.h>
#include <errno.h>
#include <signal.h>
@@ -194,16 +196,21 @@ get_ppid(void)
*/
static VALUE rb_cProcStatus;
-VALUE rb_last_status = Qnil;
static void
last_status_set(int status, int pid)
{
- rb_last_status = rb_obj_alloc(rb_cProcStatus);
- rb_iv_set(rb_last_status, "status", INT2FIX(status));
- rb_iv_set(rb_last_status, "pid", INT2FIX(pid));
+ yarv_vm_t *vm = GET_VM();
+ vm->last_status = rb_obj_alloc(rb_cProcStatus);
+ 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:
@@ -636,7 +643,7 @@ static int
waitall_each(int pid, int status, VALUE ary)
{
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;
}
#endif
@@ -721,7 +728,7 @@ proc_wait(int argc, VALUE *argv)
if ((pid = rb_waitpid(pid, &status, flags)) < 0)
rb_sys_fail(0);
if (pid == 0) {
- return rb_last_status = Qnil;
+ return GET_VM()->last_status = Qnil;
}
return INT2FIX(pid);
}
@@ -749,7 +756,7 @@ proc_wait2(int argc, VALUE *argv)
{
VALUE pid = proc_wait(argc, argv);
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);
}
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
- rb_last_status = Qnil;
+ GET_VM()->last_status = Qnil;
for (pid = -1;;) {
pid = rb_waitpid(-1, &status, 0);
if (pid == -1) {
@@ -809,7 +816,7 @@ proc_waitall(void)
break;
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
return result;
@@ -822,7 +829,7 @@ detach_process_watcher(int *pid_p)
for (;;) {
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);
}
}
@@ -1601,7 +1608,7 @@ rb_f_system(int argc, VALUE *argv)
if (status < 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;
return Qfalse;
}
@@ -3593,8 +3600,8 @@ VALUE rb_mProcID_Syscall;
void
Init_process(void)
{
+ rb_define_virtual_variable("$?", last_status_get, 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("fork", rb_f_fork, 0);
rb_define_global_function("exit!", rb_f_exit_bang, -1);
diff --git a/ruby.h b/ruby.h
index f7ce7a48f3..6c76c70a79 100644
--- a/ruby.h
+++ b/ruby.h
@@ -709,6 +709,8 @@ RUBY_EXTERN VALUE rb_cThread;
RUBY_EXTERN VALUE rb_cTime;
RUBY_EXTERN VALUE rb_cTrueClass;
RUBY_EXTERN VALUE rb_cUnboundMethod;
+RUBY_EXTERN VALUE rb_cISeq;
+RUBY_EXTERN VALUE rb_cVM;
RUBY_EXTERN VALUE rb_eException;
RUBY_EXTERN VALUE rb_eStandardError;
diff --git a/thread.c b/thread.c
index ff9bf9ceb8..f2a0589b91 100644
--- a/thread.c
+++ b/thread.c
@@ -47,6 +47,7 @@
#include "eval_intern.h"
#include "vm.h"
+#include "gc.h"
#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_disable_interrupt();
-NOINLINE(void yarv_set_stack_end(VALUE **stack_end_p));
-
static VALUE eKillSignal = INT2FIX(0);
static VALUE eTerminateSignal = INT2FIX(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);
if ((state = EXEC_TAG()) == 0) {
- GetProcPtr(th->first_proc, proc);
- th->errinfo = Qnil;
- th->local_lfp = proc->block.lfp;
- th->local_svar = Qnil;
- th->value = th_invoke_proc(th, proc, proc->block.self,
- RARRAY_LEN(args), RARRAY_PTR(args));
+ if (th->first_proc) {
+ GetProcPtr(th->first_proc, proc);
+ th->errinfo = Qnil;
+ th->local_lfp = proc->block.lfp;
+ th->local_svar = Qnil;
+ 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 {
th->value = Qnil;
@@ -292,19 +296,21 @@ thread_start_func_2(yarv_thread_t *th, VALUE *stack_start)
VALUE yarv_thread_alloc(VALUE klass);
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;
VALUE thval;
/* create thread object */
- thval = yarv_thread_alloc(cYarvThread);
+ thval = yarv_thread_alloc(klass);
GetThreadPtr(thval, th);
-
+
/* setup thread environment */
th->first_args = args;
th->first_proc = rb_block_proc();
-
+ th->first_func = fn;
+ th->first_func_arg = arg;
+
native_mutex_initialize(&th->interrupt_lock);
/* kick thread */
@@ -313,18 +319,41 @@ yarv_thread_s_new(VALUE klass, VALUE args)
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 */
#define DELAY_INFTY 1E30
VALUE th_make_jump_tag_but_local_jump(int state, VALUE val);
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();
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) {
th->join_list_next = target_th->join_list_head;
@@ -338,17 +367,17 @@ yarv_thread_join(yarv_thread_t *target_th, double delay)
else {
now = timeofday();
if (now > limit) {
- thread_debug("yarv_thread_join: timeout (thid: %p)\n",
+ thread_debug("thread_join: timeout (thid: %p)\n",
target_th->thread_id);
return Qnil;
}
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);
}
- thread_debug("yarv_thread_join: success (thid: %p)\n",
+ thread_debug("thread_join: success (thid: %p)\n",
target_th->thread_id);
if (target_th->errinfo != Qnil) {
@@ -409,7 +438,7 @@ yarv_thread_join(yarv_thread_t *target_th, double delay)
*/
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;
double delay = DELAY_INFTY;
@@ -421,7 +450,7 @@ yarv_thread_join_m(int argc, VALUE *argv, VALUE self)
if (!NIL_P(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
-yarv_thread_value(VALUE self)
+thread_value(VALUE self)
{
yarv_thread_t *th;
GetThreadPtr(self, th);
- yarv_thread_join(th, DELAY_INFTY);
+ thread_join(th, DELAY_INFTY);
return th->value;
}
@@ -538,7 +567,7 @@ rb_thread_schedule()
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_thread_yield();
@@ -552,6 +581,7 @@ rb_thread_schedule()
}
}
+int rb_thread_critical; /* TODO: dummy variable */
static VALUE
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
-yarv_thread_s_pass(VALUE klass)
+thread_s_pass(VALUE klass)
{
rb_thread_schedule();
return Qnil;
@@ -712,6 +742,31 @@ rb_thread_signal_exit(void *thptr)
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:
@@ -733,7 +788,7 @@ rb_thread_signal_exit(void *thptr)
*/
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;
GetThreadPtr(self, th);
@@ -956,6 +1011,12 @@ rb_thread_list(void)
return ary;
}
+VALUE
+rb_thread_current(void)
+{
+ return GET_THREAD()->self;
+}
+
/*
* call-seq:
* Thread.current => thread
@@ -966,9 +1027,9 @@ rb_thread_list(void)
*/
static VALUE
-yarv_thread_s_current(VALUE klass)
+thread_s_current(VALUE klass)
{
- return GET_THREAD()->self;
+ return rb_thread_current();
}
VALUE
@@ -1468,35 +1529,132 @@ rb_thread_priority_set(VALUE thread, VALUE prio)
/* for IO */
+#if defined(NFDBITS) && defined(HAVE_RB_FD_INIT)
void
-rb_thread_wait_fd(int fd)
+rb_fd_init(volatile rb_fdset_t *fds)
{
- fd_set set;
- int result = 0;
+ fds->maxfd = 0;
+ fds->fdset = ALLOC(fd_set);
+ FD_ZERO(fds->fdset);
+}
- 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));
+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);
}
- thread_debug("rb_thread_wait_fd done\n", fd);
+}
+
+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_thread_fd_writable(int fd)
+rb_fd_isset(int n, const rb_fdset_t *fds)
{
- fd_set set;
- int result = 0;
+ 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
- FD_ZERO(&set);
+/*
+ * 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_fd_writable (%d)\n", fd);
+ thread_debug("rb_thread_wait_fd_rw (%d, %c)\n", fd, c);
+
while (result <= 0) {
- GVL_UNLOCK_RANGE(result = select(fd + 1, 0, &set, 0, 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_fd_writable done\n");
+
+ thread_debug("rb_thread_wait_fd_rw (%d, %c): done\n", fd, c);
+}
+
+void
+rb_thread_wait_fd(int fd)
+{
+ rb_thread_wait_fd_rw(fd, 'r');
+}
+
+int
+rb_thread_fd_writable(int fd)
+{
+ rb_thread_wait_fd_rw(fd, 'w');
return Qtrue;
}
@@ -1569,16 +1727,16 @@ rb_thread_select(int max, fd_set * read, fd_set * write, fd_set * except,
*/
void
-yarv_set_stack_end(VALUE **stack_end_p)
+rb_gc_set_stack_end(VALUE **stack_end_p)
{
VALUE stack_end;
*stack_end_p = &stack_end;
}
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);
}
@@ -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
-Init_yarvthread()
+Init_Thread(void)
{
VALUE cThGroup;
- VALUE thgroup_default;
VALUE cMutex;
- rb_define_global_function("raw_gets", raw_gets, 0);
-
- rb_define_singleton_method(cYarvThread, "new", yarv_thread_s_new, -2);
- rb_define_singleton_method(cYarvThread, "start", yarv_thread_s_new, -2);
- rb_define_singleton_method(cYarvThread, "fork", yarv_thread_s_new, -2);
- rb_define_singleton_method(cYarvThread, "main", rb_thread_s_main, 0);
- rb_define_singleton_method(cYarvThread, "current", yarv_thread_s_current, 0);
- rb_define_singleton_method(cYarvThread, "stop", rb_thread_stop, 0);
- rb_define_singleton_method(cYarvThread, "kill", rb_thread_s_kill, 1);
- rb_define_singleton_method(cYarvThread, "exit", rb_thread_exit, 0);
- rb_define_singleton_method(cYarvThread, "pass", yarv_thread_s_pass, 0);
- rb_define_singleton_method(cYarvThread, "list", rb_thread_list, 0);
- rb_define_singleton_method(cYarvThread, "critical", rb_thread_s_critical, 0);
- rb_define_singleton_method(cYarvThread, "critical=", rb_thread_s_critical, 1);
- rb_define_singleton_method(cYarvThread, "abort_on_exception", rb_thread_s_abort_exc, 0);
- rb_define_singleton_method(cYarvThread, "abort_on_exception=", rb_thread_s_abort_exc_set, 1);
-
- rb_define_method(cYarvThread, "raise", yarv_thread_raise_m, -1);
- 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);
+ 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_method(rb_cThread, "raise", thread_raise_m, -1);
+ rb_define_method(rb_cThread, "join", thread_join_m, -1);
+ rb_define_method(rb_cThread, "value", thread_value, 0);
+ rb_define_method(rb_cThread, "kill", rb_thread_kill, 0);
+ rb_define_method(rb_cThread, "terminate", rb_thread_kill, 0);
+ rb_define_method(rb_cThread, "exit", rb_thread_kill, 0);
+ rb_define_method(rb_cThread, "run", rb_thread_run, 0);
+ rb_define_method(rb_cThread, "wakeup", rb_thread_wakeup, 0);
+ rb_define_method(rb_cThread, "[]", rb_thread_aref, 1);
+ rb_define_method(rb_cThread, "[]=", rb_thread_aset, 2);
+ rb_define_method(rb_cThread, "key?", rb_thread_key_p, 1);
+ rb_define_method(rb_cThread, "keys", rb_thread_keys, 0);
+ rb_define_method(rb_cThread, "priority", rb_thread_priority, 0);
+ 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(rb_cThread, "inspect", rb_thread_inspect, 0);
cThGroup = rb_define_class("ThreadGroup", rb_cObject);
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, "enclosed?", thgroup_enclosed_p, 0);
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);
rb_define_alloc_func(cMutex, mutex_alloc);
@@ -2040,6 +2392,11 @@ Init_yarvthread()
"class Mutex;"
" def synchronize; self.lock; yield; ensure; self.unlock; end;"
"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();
{
/* main thread setting */
diff --git a/vm.c b/vm.c
index 720aefe79b..45dfedb6db 100644
--- a/vm.c
+++ b/vm.c
@@ -5,7 +5,7 @@
$Author$
$Date$
- Copyright (C) 2004-2006 Koichi Sasada
+ Copyright (C) 2004-2007 Koichi Sasada
**********************************************************************/
@@ -1488,7 +1488,7 @@ yarv_init_redefined_flag()
VALUE *dfp; // lfp
yarv_iseq_t * block_iseq; // 0
};
-
+
struct C_METHDO_FRAME{
VALUE block_ptr;
VALUE special;
diff --git a/yarvcore.c b/yarvcore.c
index 230d5382c6..32b136737c 100644
--- a/yarvcore.c
+++ b/yarvcore.c
@@ -17,8 +17,8 @@
#include "yarv.h"
#include "gc.h"
-VALUE cYarvThread;
VALUE rb_cVM;
+VALUE rb_cThread;
VALUE symIFUNC;
VALUE symCFUNC;
@@ -257,6 +257,7 @@ vm_mark(void *ptr)
}
MARK_UNLESS_NULL(vm->thgroup_default);
MARK_UNLESS_NULL(vm->mark_object_ary);
+ MARK_UNLESS_NULL(vm->last_status);
}
MARK_REPORT_LEAVE("vm");
}
@@ -279,7 +280,6 @@ vm_init2(yarv_vm_t *vm)
MEMZERO(vm, yarv_vm_t, 1);
}
-
/**********/
/* Thread */
/**********/
@@ -402,7 +402,7 @@ th_init2(yarv_thread_t *th)
th->cfp->iseq = 0;
th->cfp->proc = 0;
th->cfp->block_iseq = 0;
-
+
th->status = THREAD_RUNNABLE;
th->errinfo = Qnil;
@@ -467,7 +467,6 @@ yarv_th_eval(yarv_thread_t *th, VALUE iseqval)
/********************************************************************/
VALUE insns_name_array(void);
-VALUE Init_yarvthread(void);
extern VALUE *rb_gc_stack_start;
VALUE
@@ -531,17 +530,18 @@ char *yarv_options = ""
#endif
;
-void Init_ISeq(void);
-
void
-Init_vm(void)
+Init_VM(void)
{
- Init_ISeq();
-
/* ::VM */
rb_cVM = rb_define_class("VM", rb_cObject);
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_* */
rb_define_const(rb_cVM, "USAGE_ANALISYS_INSN", rb_hash_new());
rb_define_const(rb_cVM, "USAGE_ANALISYS_REGS", rb_hash_new());
@@ -554,13 +554,7 @@ Init_vm(void)
/* ::VM::eval() */
rb_define_singleton_method(rb_cVM, "eval", yarvcore_eval, 3);
- /* ::VM::Thread */
- 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 */
+ /* debug functions ::VM::SDR(), ::VM::NSDR() */
rb_define_singleton_method(rb_cVM, "SDR", sdr, 0);
rb_define_singleton_method(rb_cVM, "NSDR", sdr, 0);
@@ -610,10 +604,7 @@ Init_vm(void)
idFuncall = rb_intern("funcall");
id__send_bang = rb_intern("__send!");
-#if TEST_AOT_COMPILE
- Init_compiled();
-#endif
- /* VM bootstrap: phase 1 */
+ /* VM bootstrap: phase 2 */
{
/* create vm object */
VALUE vmval = vm_alloc(rb_cVM);
@@ -632,7 +623,7 @@ Init_vm(void)
rb_ary_push(yarvVMArray, vm->self);
/* create main thread */
- thval = yarv_thread_alloc(cYarvThread);
+ thval = yarv_thread_alloc(rb_cThread);
GetThreadPtr(thval, th);
vm->main_thread = th;
@@ -645,9 +636,6 @@ Init_vm(void)
th->machine_stack_start = rb_gc_stack_start;
vm->living_threads = st_init_numtable();
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();
}
@@ -667,3 +655,4 @@ Init_yarv(void)
th->machine_stack_start = rb_gc_stack_start;
yarv_set_current_running_thread_raw(th);
}
+
diff --git a/yarvcore.h b/yarvcore.h
index f2c76b2f68..06b563ba2a 100644
--- a/yarvcore.h
+++ b/yarvcore.h
@@ -23,6 +23,7 @@
#endif
#include "ruby.h"
#include "st.h"
+#include "node.h"
#include "debug.h"
#include "vm_opts.h"
@@ -97,13 +98,7 @@
#define GCDEBUG 0
-
-
/* classes and modules */
-extern VALUE cYarvVM;
-extern VALUE cYarvThread;
-extern VALUE rb_cISeq;
-extern VALUE rb_cVM;
extern VALUE symIFUNC;
extern VALUE symCFUNC;
@@ -326,10 +321,11 @@ typedef struct yarv_vm_struct {
st_table *living_threads;
VALUE thgroup_default;
+ VALUE last_status; /* $? */
int thread_abort_on_exception;
- int exit_code;
unsigned long trace_flag;
+ int exit_code;
/* object management */
VALUE mark_object_ary;
@@ -457,6 +453,8 @@ typedef struct yarv_thread_struct
VALUE first_proc;
VALUE first_args;
+ VALUE (*first_func)(ANYARGS);
+ void *first_func_arg;
/* for GC */
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 { \
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)
#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); \
} while(0)
-NOINLINE(void yarv_set_stack_end(VALUE **stack_end_p));
-NOINLINE(void yarv_save_machine_context(yarv_thread_t *));
-
-extern int rb_thread_pending;
+NOINLINE(void rb_gc_set_stack_end(VALUE **stack_end_p));
+NOINLINE(void rb_gc_save_machine_context(yarv_thread_t *));
void yarv_thread_execute_interrupts(yarv_thread_t *);