[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]