ruby-changes:9866
From: nobu <ko1@a...>
Date: Fri, 9 Jan 2009 15:20:38 +0900 (JST)
Subject: [ruby-changes:9866] Ruby:r21407 (ruby_1_8): * eval.c (TAG_THREAD): to start a new thread.
nobu 2009-01-09 15:20:20 +0900 (Fri, 09 Jan 2009) New Revision: 21407 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=21407 Log: * eval.c (TAG_THREAD): to start a new thread. * eval.c (ruby_init, ruby_options, ruby_cleanup, rb_protect, rb_load_protect, rb_thread_start_0): make thread anchor. * eval.c (proc_alloc): clone proc object if klass is not Proc or created in different thread. * eval.c (rb_block_pass): call a function with a block. [new] * eval.c (rb_thread_start_0): restore prot_tag before rewinding. * eval.c (rb_thread_start_0): update curr_thread before raising TAG_THREAD. [ruby-dev:25712] * eval.c (rb_thread_start_1): outer block variables wasn't linked to threads. fixed: [ruby-dev:25700] * eval.c (rb_thread_start_1): initialize newly pushed frame. fixed: [ruby-dev:25707] * node.h (struct rb_thread): added anchor. backported r7954, r7964, r7980, r7992, r8014 from trunk. Modified files: branches/ruby_1_8/ChangeLog branches/ruby_1_8/eval.c branches/ruby_1_8/node.h branches/ruby_1_8/version.h Index: ruby_1_8/ChangeLog =================================================================== --- ruby_1_8/ChangeLog (revision 21406) +++ ruby_1_8/ChangeLog (revision 21407) @@ -1,3 +1,29 @@ +Fri Jan 9 15:20:17 2009 Nobuyoshi Nakada <nobu@r...> + + * eval.c (TAG_THREAD): to start a new thread. + + * eval.c (ruby_init, ruby_options, ruby_cleanup, rb_protect, + rb_load_protect, rb_thread_start_0): make thread anchor. + + * eval.c (proc_alloc): clone proc object if klass is not Proc or + created in different thread. + + * eval.c (rb_block_pass): call a function with a block. [new] + + * eval.c (rb_thread_start_0): restore prot_tag before rewinding. + + * eval.c (rb_thread_start_0): update curr_thread before raising + TAG_THREAD. [ruby-dev:25712] + + * eval.c (rb_thread_start_1): outer block variables wasn't linked to + threads. fixed: [ruby-dev:25700] + + * eval.c (rb_thread_start_1): initialize newly pushed frame. + fixed: [ruby-dev:25707] + + * node.h (struct rb_thread): added anchor. backported r7954, + r7964, r7980, r7992, r8014 from trunk. + Wed Jan 7 18:14:16 2009 Kazuhiro NISHIYAMA <zn@m...> * configure.in: fix SEGV on Mac OS X 10.5.3 with --enable-shared. Index: ruby_1_8/version.h =================================================================== --- ruby_1_8/version.h (revision 21406) +++ ruby_1_8/version.h (revision 21407) @@ -1,7 +1,7 @@ #define RUBY_VERSION "1.8.7" -#define RUBY_RELEASE_DATE "2009-01-07" +#define RUBY_RELEASE_DATE "2009-01-09" #define RUBY_VERSION_CODE 187 -#define RUBY_RELEASE_CODE 20090107 +#define RUBY_RELEASE_CODE 20090109 #define RUBY_PATCHLEVEL 5000 #define RUBY_VERSION_MAJOR 1 @@ -9,7 +9,7 @@ #define RUBY_VERSION_TEENY 7 #define RUBY_RELEASE_YEAR 2009 #define RUBY_RELEASE_MONTH 1 -#define RUBY_RELEASE_DAY 7 +#define RUBY_RELEASE_DAY 9 #ifdef RUBY_EXTERN RUBY_EXTERN const char ruby_version[]; Index: ruby_1_8/eval.c =================================================================== --- ruby_1_8/eval.c (revision 21406) +++ ruby_1_8/eval.c (revision 21407) @@ -1051,6 +1051,7 @@ #define TAG_RAISE 0x6 #define TAG_THROW 0x7 #define TAG_FATAL 0x8 +#define TAG_THREAD 0xa #define TAG_MASK 0xf VALUE ruby_class; @@ -1104,6 +1105,28 @@ scope_vmode = _vmode; \ } while (0) +struct ruby_env { + struct ruby_env *prev; + struct FRAME *frame; + struct SCOPE *scope; + struct BLOCK *block; + struct iter *iter; + struct tag *tag; + NODE *cref; +}; + +static void push_thread_anchor _((struct ruby_env *)); +static void pop_thread_anchor _((struct ruby_env *)); + +#define PUSH_THREAD_TAG() PUSH_TAG(PROT_THREAD); \ + do { \ + struct ruby_env _interp; \ + push_thread_anchor(&_interp); +#define POP_THREAD_TAG() \ + pop_thread_anchor(&_interp); \ + } while (0); \ + POP_TAG() + static VALUE rb_eval _((VALUE,NODE*)); static VALUE eval _((VALUE,VALUE,VALUE,const char*,int)); static NODE *compile _((VALUE, const char*, int)); @@ -1362,6 +1385,8 @@ # endif #endif +NORETURN(static void rb_thread_start_1 _((void))); + void ruby_init() { @@ -1531,16 +1556,19 @@ int state; Init_stack((void*)&state); - PUSH_TAG(PROT_NONE); + PUSH_THREAD_TAG(); if ((state = EXEC_TAG()) == 0) { ruby_process_options(argc, argv); } else { + if (state == TAG_THREAD) { + rb_thread_start_1(); + } trace_func = 0; tracing = 0; exit(error_handle(state)); } - POP_TAG(); + POP_THREAD_TAG(); } void rb_exec_end_proc _((void)); @@ -1584,14 +1612,17 @@ errs[1] = ruby_errinfo; ruby_safe_level = 0; Init_stack((void *)&state); - ruby_finalize_0(); - errs[0] = ruby_errinfo; - PUSH_TAG(PROT_NONE); + PUSH_THREAD_TAG(); PUSH_ITER(ITER_NOT); if ((state = EXEC_TAG()) == 0) { + ruby_finalize_0(); + errs[0] = ruby_errinfo; rb_thread_cleanup(); rb_thread_wait_other_threads(); } + else if (state == TAG_THREAD) { + rb_thread_start_1(); + } else if (ex == 0) { ex = state; } @@ -1599,7 +1630,7 @@ ruby_errinfo = errs[1]; ex = error_handle(ex); ruby_finalize_1(); - POP_TAG(); + POP_THREAD_TAG(); for (nerr = 0; nerr < sizeof(errs) / sizeof(errs[0]); ++nerr) { VALUE err = errs[nerr]; @@ -1637,15 +1668,18 @@ { int state; - PUSH_TAG(PROT_NONE); + PUSH_THREAD_TAG(); PUSH_ITER(ITER_NOT); /* default visibility is private at toplevel */ SCOPE_SET(SCOPE_PRIVATE); if ((state = EXEC_TAG()) == 0) { eval_node(ruby_top_self, ruby_eval_tree); } + else if (state == TAG_THREAD) { + rb_thread_start_1(); + } POP_ITER(); - POP_TAG(); + POP_THREAD_TAG(); return state; } @@ -5524,13 +5558,16 @@ VALUE result = Qnil; /* OK */ int status; - PUSH_TAG(PROT_NONE); + PUSH_THREAD_TAG(); cont_protect = (VALUE)rb_node_newnode(NODE_MEMO, cont_protect, 0, 0); if ((status = EXEC_TAG()) == 0) { result = (*proc)(data); } + else if (status == TAG_THREAD) { + rb_thread_start_1(); + } cont_protect = ((NODE *)cont_protect)->u1.value; - POP_TAG(); + POP_THREAD_TAG(); if (state) { *state = status; } @@ -7072,11 +7109,14 @@ { int status; - PUSH_TAG(PROT_NONE); + PUSH_THREAD_TAG(); if ((status = EXEC_TAG()) == 0) { rb_load(fname, wrap); } - POP_TAG(); + else if (status == TAG_THREAD) { + rb_thread_start_1(); + } + POP_THREAD_TAG(); if (state) *state = status; } @@ -8698,8 +8738,13 @@ rb_warn("tried to create Proc object without a block"); } - if (!proc && ruby_block->block_obj && CLASS_OF(ruby_block->block_obj) == klass) { - return ruby_block->block_obj; + if (!proc && ruby_block->block_obj) { + VALUE obj = ruby_block->block_obj; + if (CLASS_OF(obj) != klass) { + obj = proc_clone(obj); + RBASIC(obj)->klass = klass; + } + return obj; } block = Data_Make_Struct(klass, struct BLOCK, blk_mark, blk_free, data); *data = *ruby_block; @@ -9122,11 +9167,11 @@ } static VALUE -block_pass(self, node) - VALUE self; - NODE *node; +rb_block_pass(func, arg, proc) + VALUE (*func) _((VALUE)); + VALUE arg; + VALUE proc; { - VALUE proc = rb_eval(self, node->nd_body); /* OK */ VALUE b; struct BLOCK * volatile old_block; struct BLOCK _block; @@ -9138,7 +9183,7 @@ if (NIL_P(proc)) { PUSH_ITER(ITER_NOT); - result = rb_eval(self, node->nd_iter); + result = (*func)(arg); POP_ITER(); return result; } @@ -9158,7 +9203,7 @@ if (ruby_block && ruby_block->block_obj == proc) { PUSH_ITER(ITER_PAS); - result = rb_eval(self, node->nd_iter); + result = (*func)(arg); POP_ITER(); return result; } @@ -9183,7 +9228,7 @@ proc_set_safe_level(proc); if (safe > ruby_safe_level) ruby_safe_level = safe; - result = rb_eval(self, node->nd_iter); + result = (*func)(arg); } else if (state == TAG_BREAK && TAG_DST()) { result = prot_tag->retval; @@ -9212,6 +9257,30 @@ return result; } +struct block_arg { + VALUE self; + NODE *iter; +}; + +static VALUE +call_block(arg) + struct block_arg *arg; +{ + return rb_eval(arg->self, arg->iter); +} + +static VALUE +block_pass(self, node) + VALUE self; + NODE *node; +{ + struct block_arg arg; + arg.self = self; + arg.iter = node->nd_iter; + return rb_block_pass((VALUE (*)_((VALUE)))call_block, + (VALUE)&arg, rb_eval(self, node->nd_body)); +} + struct METHOD { VALUE klass, rklass; VALUE recv; @@ -10462,6 +10531,11 @@ } } +static struct { + rb_thread_t thread; + VALUE proc, arg; +} new_thread; + static int mark_loading_thread(key, value, lev) ID key; @@ -10495,6 +10569,11 @@ } rb_gc_mark(th->thread); } END_FOREACH_FROM(main_thread, th); + if (new_thread.thread) { + rb_gc_mark(new_thread.thread->thread); + rb_gc_mark(new_thread.proc); + rb_gc_mark(new_thread.arg); + } if (loading_tbl) st_foreach(loading_tbl, mark_loading_thread, 0); } @@ -12129,6 +12208,7 @@ th->thgroup = thgroup_default;\ th->locals = 0;\ th->thread = 0;\ + th->anchor = 0;\ if (curr_thread == 0) {\ th->sandbox = Qnil;\ } else {\ @@ -12249,6 +12329,45 @@ int rb_thread_tick = THREAD_TICK; #endif +NORETURN(static void rb_thread_terminated _((rb_thread_t, int, enum rb_thread_status))); +static VALUE rb_thread_yield _((VALUE, rb_thread_t)); + +static void +push_thread_anchor(ip) + struct ruby_env *ip; +{ + ip->tag = prot_tag; + ip->frame = ruby_frame; + ip->block = ruby_block; + ip->scope = ruby_scope; + ip->iter = ruby_iter; + ip->cref = ruby_cref; + ip->prev = curr_thread->anchor; + curr_thread->anchor = ip; +} + +static void +pop_thread_anchor(ip) + struct ruby_env *ip; +{ + curr_thread->anchor = ip->prev; +} + +static void +thread_insert(th) + rb_thread_t th; +{ + if (!th->next) { + /* merge in thread list */ + th->prev = curr_thread; + curr_thread->next->prev = th; + th->next = curr_thread->next; + curr_thread->next = th; + th->priority = curr_thread->priority; + th->thgroup = curr_thread->thgroup; + } +} + static VALUE rb_thread_start_0(fn, arg, th) VALUE (*fn)(); @@ -12287,6 +12406,17 @@ return thread; } + if (fn == rb_thread_yield && curr_thread->anchor) { + struct ruby_env *ip = curr_thread->anchor; + new_thread.thread = th; + new_thread.proc = rb_block_proc(); + new_thread.arg = (VALUE)arg; + th->anchor = ip; + thread_insert(th); + curr_thread = th; + longjmp((prot_tag = ip->tag)->buf, TAG_THREAD); + } + if (ruby_block) { /* should nail down higher blocks */ struct BLOCK dummy; @@ -12296,17 +12426,9 @@ } scope_dup(ruby_scope); - if (!th->next) { - /* merge in thread list */ - th->prev = curr_thread; - curr_thread->next->prev = th; - th->next = curr_thread->next; - curr_thread->next = th; - th->priority = curr_thread->priority; - th->thgroup = curr_thread->thgroup; - } + thread_insert(th); - PUSH_TAG(PROT_THREAD); + PUSH_TAG(PROT_NONE); if ((state = EXEC_TAG()) == 0) { if (THREAD_SAVE_CONTEXT(th) == 0) { curr_thread = th; @@ -12328,6 +12450,16 @@ blk_free(saved_block); } + rb_thread_terminated(th, state, status); + return 0; /* not reached */ +} + +static void +rb_thread_terminated(th, state, status) + rb_thread_t th; + int state; + enum rb_thread_status status; +{ if (state && status != THREAD_TO_KILL && !NIL_P(ruby_errinfo)) { th->flags |= RAISED_EXCEPTION; if (state == TAG_FATAL) { @@ -12358,9 +12490,58 @@ } rb_thread_schedule(); ruby_stop(0); /* last thread termination */ - return 0; /* not reached */ } +static VALUE +rb_thread_yield_0(arg) + VALUE arg; +{ + return rb_thread_yield(arg, curr_thread); +} + +static void +rb_thread_start_1() +{ + rb_thread_t th = new_thread.thread; + volatile rb_thread_t th_save = th; + VALUE proc = new_thread.proc; + VALUE arg = new_thread.arg; + struct ruby_env *ip = th->anchor; + enum rb_thread_status status; + int state; + + ruby_frame = ip->frame; + ruby_block = ip->block; + ruby_scope = ip->scope; + ruby_iter = ip->iter; + ruby_cref = ip->cref; + ruby_dyna_vars = ((struct BLOCK *)DATA_PTR(proc))->dyna_vars; + PUSH_FRAME(); + *ruby_frame = *ip->frame; + ruby_frame->prev = ip->frame; + ruby_frame->iter = ITER_CUR; + PUSH_TAG(PROT_NONE); + if ((state = EXEC_TAG()) == 0) { + if (THREAD_SAVE_CONTEXT(th) == 0) { + new_thread.thread = 0; + curr_thread = th; + th->result = rb_block_pass(rb_thread_yield_0, arg, proc); + } + th = th_save; + } + else if (TAG_DST()) { + th = th_save; + th->result = prot_tag->retval; + } + POP_TAG(); + POP_FRAME(); + status = th->status; + + if (th == main_thread) ruby_stop(state); + rb_thread_remove(th); + rb_thread_terminated(th, state, status); +} + VALUE rb_thread_create(fn, arg) VALUE (*fn)(); Index: ruby_1_8/node.h =================================================================== --- ruby_1_8/node.h (revision 21406) +++ ruby_1_8/node.h (revision 21407) @@ -461,6 +461,8 @@ VALUE thread; VALUE sandbox; + + struct ruby_env *anchor; }; extern VALUE (*ruby_sandbox_save)_((rb_thread_t)); -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/