From 025cfde57d14b12504595130cb1b222372881143 Mon Sep 17 00:00:00 2001 From: ko1 Date: Mon, 5 Feb 2007 12:21:01 +0000 Subject: * 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 --- ChangeLog | 31 +++ common.mk | 6 - eval_thread.c | 683 ---------------------------------------------------------- gc.c | 12 +- gc.h | 9 + inits.c | 78 +++---- io.c | 3 +- process.c | 33 +-- ruby.h | 2 + thread.c | 535 +++++++++++++++++++++++++++++++++++++-------- vm.c | 4 +- yarvcore.c | 37 ++-- yarvcore.h | 20 +- 13 files changed, 576 insertions(+), 877 deletions(-) delete mode 100644 eval_thread.c 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 + + * 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 * 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 -#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 - * block. Any arguments passed to Thread::new 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... - * - * produces: - * - * abxyzc - */ - -/* - * call-seq: - * Thread.new([arg]*) {|args| block } => thread - * - * Creates and runs a new thread to execute the instructions given in - * block. Any arguments passed to Thread::new 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... - * - * produces: - * - * abxyzc - */ - -/* - * call-seq: - * Thread.start([args]*) {|args| block } => thread - * Thread.fork([args]*) {|args| block } => thread - * - * Basically the same as Thread::new. However, if class - * Thread is subclassed, then calling start in that - * subclass will not invoke the subclass's initialize 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 true, 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. Thread::critical is not - * intended for daily use: it is primarily there to support folks writing - * threading libraries. - */ - - -/* - * Document-class: Continuation - * - * Continuation objects are generated by - * Kernel#callcc. They hold a return address and execution - * context, allowing a nonlocal return to the end of the - * callcc block from anywhere within a program. - * Continuations are somewhat analogous to a structured version of C's - * setjmp/longjmp (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/ - * - * produces: - * - * 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" - * - * produces: - * - * 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 Continuation object, which it passes to the - * associated block. Performing a cont.call will - * cause the callcc to return (as will falling through the - * end of the block). The value returned by the callcc is - * the value of the block, or the value passed to - * cont.call. See class Continuation - * for more details. Also see Kernel::throw 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 - * callcc block. If no arguments are given, the original - * callcc returns nil. If one argument is - * given, callcc returns it. Otherwise, an array - * containing args 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 :name). - */ - -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 #include #include @@ -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 Thread::new. However, if class + * Thread is subclassed, then calling start in that + * subclass will not invoke the subclass's initialize 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 + * Kernel#callcc. They hold a return address and execution + * context, allowing a nonlocal return to the end of the + * callcc block from anywhere within a program. + * Continuations are somewhat analogous to a structured version of C's + * setjmp/longjmp (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/ + * + * produces: + * + * 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" + * + * produces: + * + * 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 Continuation object, which it passes to the + * associated block. Performing a cont.call will + * cause the callcc to return (as will falling through the + * end of the block). The value returned by the callcc is + * the value of the block, or the value passed to + * cont.call. See class Continuation + * for more details. Also see Kernel::throw 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 + * callcc block. If no arguments are given, the original + * callcc returns nil. If one argument is + * given, callcc returns it. Otherwise, an array + * containing args 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 :name). + */ + 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(""), 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 *); -- cgit v1.2.3