summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-01-09 06:20:20 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-01-09 06:20:20 +0000
commitf1ef16986158cc8ec7f95e9f0e49a9ffa5e5ce77 (patch)
tree3755b0bab633a13e62bf1d11152f43c9cd767b85
parent98aaad53dad1d4a259a1143c86834ed942709765 (diff)
* 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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@21407 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog26
-rw-r--r--eval.c245
-rw-r--r--node.h2
-rw-r--r--version.h6
4 files changed, 244 insertions, 35 deletions
diff --git a/ChangeLog b/ChangeLog
index 2e1984962e..5ab4963edd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
+Fri Jan 9 15:20:17 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * 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@mbf.nifty.com>
* configure.in: fix SEGV on Mac OS X 10.5.3 with --enable-shared.
diff --git a/eval.c b/eval.c
index 1e0cca11ac..0052afd46c 100644
--- a/eval.c
+++ b/eval.c
@@ -1051,6 +1051,7 @@ static struct tag *prot_tag;
#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 @@ static void scope_dup _((struct SCOPE *));
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 @@ ruby_native_thread_kill(sig)
# endif
#endif
+NORETURN(static void rb_thread_start_1 _((void)));
+
void
ruby_init()
{
@@ -1531,16 +1556,19 @@ ruby_options(argc, argv)
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 @@ ruby_cleanup(ex)
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_cleanup(ex)
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 @@ ruby_exec_internal()
{
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 @@ rb_protect(proc, data, state)
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 @@ rb_load_protect(fname, wrap, state)
{
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 @@ proc_alloc(klass, proc)
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 @@ proc_binding(proc)
}
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 @@ block_pass(self, node)
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 @@ block_pass(self, node)
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 @@ block_pass(self, node)
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 @@ block_pass(self, node)
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 @@ thread_mark(th)
}
}
+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_threads()
}
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 @@ rb_thread_group(thread)
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 @@ rb_thread_stop_timer()
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 @@ rb_thread_start_0(fn, arg, th)
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 @@ rb_thread_start_0(fn, arg, th)
}
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 @@ rb_thread_start_0(fn, arg, th)
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,7 +12490,56 @@ rb_thread_start_0(fn, arg, th)
}
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
diff --git a/node.h b/node.h
index edc24b23d7..604bc837d0 100644
--- a/node.h
+++ b/node.h
@@ -461,6 +461,8 @@ struct rb_thread {
VALUE thread;
VALUE sandbox;
+
+ struct ruby_env *anchor;
};
extern VALUE (*ruby_sandbox_save)_((rb_thread_t));
diff --git a/version.h b/version.h
index 2815e96d12..2ba29e9fe9 100644
--- a/version.h
+++ b/version.h
@@ -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[];