yarv-diff:210
From: ko1 atdot.net
Date: 7 Feb 2006 05:44:52 -0000
Subject: [yarv-diff:210] r368 - in trunk: . benchmark test/ruby yarvtest
Author: ko1
Date: 2006-02-07 14:44:51 +0900 (Tue, 07 Feb 2006)
New Revision: 368
Modified:
trunk/ChangeLog
trunk/benchmark/bmx_temp.rb
trunk/eval.c
trunk/eval_load.c
trunk/eval_thread.c
trunk/gc.c
trunk/ruby.h
trunk/signal.c
trunk/test.rb
trunk/test/ruby/test_gc.rb
trunk/thread.c
trunk/vm.c
trunk/yarvcore.c
trunk/yarvcore.h
trunk/yarvtest/test_thread.rb
Log:
* eval.c, eval_load.c : remove rb_thread_start_1()
* eval.c : fix some prototypes and indents
* eval_thread.c, thread.c : move some functions
from eval_thread.c to thread.c
* signal.c (sighandler) : add line braek in error message
* yarvcore.c, yarvcore.h, thread.c : support ThreadGroup
* ruby.h, gc.c, vm.c : make new basic type RValue and T_VALUE.
RValue includes three values in itself. RValue is used as
svar
Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog 2006-02-06 14:52:06 UTC (rev 367)
+++ trunk/ChangeLog 2006-02-07 05:44:51 UTC (rev 368)
@@ -4,6 +4,24 @@
# from Mon, 03 May 2004 01:24:19 +0900
#
+2006-02-07(Tue) 14:42:25 +0900 Koichi Sasada <ko1 atdot.net>
+
+ * eval.c, eval_load.c : remove rb_thread_start_1()
+
+ * eval.c : fix some prototypes and indents
+
+ * eval_thread.c, thread.c : move some functions
+ from eval_thread.c to thread.c
+
+ * signal.c (sighandler) : add line braek in error message
+
+ * yarvcore.c, yarvcore.h, thread.c : support ThreadGroup
+
+ * ruby.h, gc.c, vm.c : make new basic type RValue and T_VALUE.
+ RValue includes three values in itself. RValue is used as
+ svar
+
+
2006-02-06(Mon) 23:51:41 +0900 Minero Aoki <aamine loveruby.net>
* test/ruby/test_hash.rb: import many tests from rubicon.
Modified: trunk/benchmark/bmx_temp.rb
===================================================================
--- trunk/benchmark/bmx_temp.rb 2006-02-06 14:52:06 UTC (rev 367)
+++ trunk/benchmark/bmx_temp.rb 2006-02-07 05:44:51 UTC (rev 368)
@@ -1,4 +1,18 @@
+1000000.times{
+}
+__END__
+ths = (1..10).map{
+ Thread.new{
+ 1000000.times{
+ }
+ }
+}
+ths.each{|e|
+ e.join
+}
+
+__END__
$pr = proc{}
def m
$pr.call
Modified: trunk/eval.c
===================================================================
--- trunk/eval.c 2006-02-06 14:52:06 UTC (rev 367)
+++ trunk/eval.c 2006-02-07 05:44:51 UTC (rev 368)
@@ -109,7 +109,6 @@
# endif
#endif
-NORETURN(void rb_thread_start_1(void));
void Init_yarv(void);
void
@@ -173,9 +172,6 @@
ruby_process_options(argc, argv);
}
else {
- if (state == TAG_THREAD) {
- rb_thread_start_1();
- }
trace_func = 0;
tracing = 0;
exit(error_handle(state));
@@ -239,9 +235,6 @@
rb_thread_cleanup();
rb_thread_wait_other_threads();
}
- else if (state == TAG_THREAD) {
- rb_thread_start_1();
- }
else if (ex == 0) {
ex = state;
}
@@ -510,28 +503,27 @@
}
int
-rb_remove_event_hook(func)
- rb_event_hook_func_t func;
+rb_remove_event_hook(rb_event_hook_func_t func)
{
- rb_event_hook_t *prev, *hook;
+ rb_event_hook_t *prev, *hook;
- prev = NULL;
- hook = event_hooks;
- while (hook) {
- if (hook->func == func) {
- if (prev) {
- prev->next = hook->next;
- }
- else {
- event_hooks = hook->next;
- }
- xfree(hook);
- return 0;
- }
- prev = hook;
- hook = hook->next;
+ prev = NULL;
+ hook = event_hooks;
+ while (hook) {
+ if (hook->func == func) {
+ if (prev) {
+ prev->next = hook->next;
+ }
+ else {
+ event_hooks = hook->next;
+ }
+ xfree(hook);
+ return 0;
}
- return -1;
+ prev = hook;
+ hook = hook->next;
+ }
+ return -1;
}
/*
@@ -1409,9 +1401,6 @@
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_THREAD_TAG();
if (state) {
@@ -1660,18 +1649,15 @@
}
VALUE
-rb_apply(recv, mid, args)
- VALUE recv;
- ID mid;
- VALUE args;
+rb_apply(VALUE recv, ID mid, VALUE args)
{
- int argc;
- VALUE *argv;
+ int argc;
+ VALUE *argv;
- argc = RARRAY(args)->len; /* Assigns LONG, but argc is INT */
- argv = ALLOCA_N(VALUE, argc);
- MEMCPY(argv, RARRAY(args)->ptr, VALUE, argc);
- return rb_call(CLASS_OF(recv), recv, mid, argc, argv, NOEX_NOSUPER);
+ argc = RARRAY(args)->len; /* Assigns LONG, but argc is INT */
+ argv = ALLOCA_N(VALUE, argc);
+ MEMCPY(argv, RARRAY(args)->ptr, VALUE, argc);
+ return rb_call(CLASS_OF(recv), recv, mid, argc, argv, NOEX_NOSUPER);
}
/*
@@ -1791,38 +1777,36 @@
*/
static VALUE
-rb_f_caller(argc, argv)
- int argc;
- VALUE *argv;
+rb_f_caller(int argc, VALUE *argv)
{
- VALUE level;
- int lev;
+ VALUE level;
+ int lev;
- rb_scan_args(argc, argv, "01", &level);
+ rb_scan_args(argc, argv, "01", &level);
- if (NIL_P(level)) lev = 1;
- else lev = NUM2INT(level);
- if (lev < 0) rb_raise(rb_eArgError, "negative level (%d)", lev);
+ if (NIL_P(level)) lev = 1;
+ else lev = NUM2INT(level);
+ if (lev < 0) rb_raise(rb_eArgError, "negative level (%d)", lev);
- return backtrace(lev);
+ return backtrace(lev);
}
void
-rb_backtrace()
+rb_backtrace(void)
{
- long i;
- VALUE ary;
+ long i;
+ VALUE ary;
- ary = backtrace(-1);
- for (i=0; i<RARRAY(ary)->len; i++) {
- printf("\tfrom %s\n", RSTRING(RARRAY(ary)->ptr[i])->ptr);
- }
+ ary = backtrace(-1);
+ for (i=0; i<RARRAY(ary)->len; i++) {
+ printf("\tfrom %s\n", RSTRING(RARRAY(ary)->ptr[i])->ptr);
+ }
}
static VALUE
-make_backtrace()
+make_backtrace(void)
{
- return backtrace(-1);
+ return backtrace(-1);
}
static ID
@@ -1907,7 +1891,6 @@
file = ruby_sourcefile;
line = ruby_sourceline;
}
-
PUSH_TAG(PROT_NONE);
if((state = EXEC_TAG()) == 0){
yarv_iseq_t *iseq;
@@ -2072,6 +2055,7 @@
}
pcref = th_cfp_svar(cfp, -1);
stored_cref = *pcref;
+ /* this cause GC error */
*pcref = rb_ary_dup(th->cref_stack);
}
@@ -2267,19 +2251,16 @@
*/
static VALUE
-rb_mod_public(argc, argv, module)
- int argc;
- VALUE *argv;
- VALUE module;
+rb_mod_public(int argc, VALUE *argv, VALUE module)
{
- secure_visibility(module);
- if (argc == 0) {
- SCOPE_SET(NOEX_PUBLIC);
- }
- else {
- set_method_visibility(module, argc, argv, NOEX_PUBLIC);
- }
- return module;
+ secure_visibility(module);
+ if (argc == 0) {
+ SCOPE_SET(NOEX_PUBLIC);
+ }
+ else {
+ set_method_visibility(module, argc, argv, NOEX_PUBLIC);
+ }
+ return module;
}
/*
@@ -2293,19 +2274,16 @@
*/
static VALUE
-rb_mod_protected(argc, argv, module)
- int argc;
- VALUE *argv;
- VALUE module;
+rb_mod_protected(int argc, VALUE *argv, VALUE module)
{
- secure_visibility(module);
- if (argc == 0) {
- SCOPE_SET(NOEX_PROTECTED);
- }
- else {
- set_method_visibility(module, argc, argv, NOEX_PROTECTED);
- }
- return module;
+ secure_visibility(module);
+ if (argc == 0) {
+ SCOPE_SET(NOEX_PROTECTED);
+ }
+ else {
+ set_method_visibility(module, argc, argv, NOEX_PROTECTED);
+ }
+ return module;
}
/*
@@ -2330,14 +2308,14 @@
static VALUE
rb_mod_private(int argc, VALUE *argv, VALUE module)
{
- secure_visibility(module);
- if (argc == 0) {
- SCOPE_SET(NOEX_PRIVATE);
- }
- else {
- set_method_visibility(module, argc, argv, NOEX_PRIVATE);
- }
- return module;
+ secure_visibility(module);
+ if (argc == 0) {
+ SCOPE_SET(NOEX_PRIVATE);
+ }
+ else {
+ set_method_visibility(module, argc, argv, NOEX_PRIVATE);
+ }
+ return module;
}
/*
@@ -2348,13 +2326,10 @@
*/
static VALUE
-rb_mod_public_method(argc, argv, obj)
- int argc;
- VALUE *argv;
- VALUE obj;
+rb_mod_public_method(int argc, VALUE *argv, VALUE obj)
{
- set_method_visibility(CLASS_OF(obj), argc, argv, NOEX_PUBLIC);
- return obj;
+ set_method_visibility(CLASS_OF(obj), argc, argv, NOEX_PUBLIC);
+ return obj;
}
/*
@@ -2374,13 +2349,10 @@
*/
static VALUE
-rb_mod_private_method(argc, argv, obj)
- int argc;
- VALUE *argv;
- VALUE obj;
+rb_mod_private_method(int argc, VALUE *argv, VALUE obj)
{
- set_method_visibility(CLASS_OF(obj), argc, argv, NOEX_PRIVATE);
- return obj;
+ set_method_visibility(CLASS_OF(obj), argc, argv, NOEX_PRIVATE);
+ return obj;
}
/*
@@ -2394,19 +2366,15 @@
*/
static VALUE
-top_public(argc, argv)
- int argc;
- VALUE *argv;
+top_public(int argc, VALUE *argv)
{
- return rb_mod_public(argc, argv, rb_cObject);
+ return rb_mod_public(argc, argv, rb_cObject);
}
static VALUE
-top_private(argc, argv)
- int argc;
- VALUE *argv;
+top_private(int argc, VALUE *argv)
{
- return rb_mod_private(argc, argv, rb_cObject);
+ return rb_mod_private(argc, argv, rb_cObject);
}
/*
@@ -2500,20 +2468,19 @@
*/
static VALUE
-rb_mod_append_features(module, include)
- VALUE module, include;
+rb_mod_append_features(VALUE module, VALUE include)
{
- switch (TYPE(include)) {
- case T_CLASS:
- case T_MODULE:
- break;
- default:
- Check_Type(include, T_CLASS);
- break;
- }
- rb_include_module(include, module);
+ switch (TYPE(include)) {
+ case T_CLASS:
+ case T_MODULE:
+ break;
+ default:
+ Check_Type(include, T_CLASS);
+ break;
+ }
+ rb_include_module(include, module);
- return module;
+ return module;
}
/*
@@ -2524,19 +2491,16 @@
*/
static VALUE
-rb_mod_include(argc, argv, module)
- int argc;
- VALUE *argv;
- VALUE module;
+rb_mod_include(int argc, VALUE *argv, VALUE module)
{
- int i;
+ int i;
- for (i=0; i<argc; i++) Check_Type(argv[i], T_MODULE);
- while (argc--) {
- rb_funcall(argv[argc], rb_intern("append_features"), 1, module);
- rb_funcall(argv[argc], rb_intern("included"), 1, module);
- }
- return module;
+ for (i=0; i<argc; i++) Check_Type(argv[i], T_MODULE);
+ while (argc--) {
+ rb_funcall(argv[argc], rb_intern("append_features"), 1, module);
+ rb_funcall(argv[argc], rb_intern("included"), 1, module);
+ }
+ return module;
}
void
@@ -2547,10 +2511,9 @@
}
void
-rb_extend_object(obj, module)
- VALUE obj, module;
+rb_extend_object(VALUE obj, VALUE module)
{
- rb_include_module(rb_singleton_class(obj), module);
+ rb_include_module(rb_singleton_class(obj), module);
}
/*
@@ -2581,11 +2544,10 @@
*/
static VALUE
-rb_mod_extend_object(mod, obj)
- VALUE mod, obj;
+rb_mod_extend_object(VALUE mod, VALUE obj)
{
- rb_extend_object(obj, mod);
- return obj;
+ rb_extend_object(obj, mod);
+ return obj;
}
/*
@@ -2614,22 +2576,19 @@
*/
static VALUE
-rb_obj_extend(argc, argv, obj)
- int argc;
- VALUE *argv;
- VALUE obj;
+rb_obj_extend(int argc, VALUE *argv, VALUE obj)
{
- int i;
+ int i;
- if (argc == 0) {
- rb_raise(rb_eArgError, "wrong number of arguments (0 for 1)");
- }
- for (i=0; i<argc; i++) Check_Type(argv[i], T_MODULE);
- while (argc--) {
- rb_funcall(argv[argc], rb_intern("extend_object"), 1, obj);
- rb_funcall(argv[argc], rb_intern("extended"), 1, obj);
- }
- return obj;
+ if (argc == 0) {
+ rb_raise(rb_eArgError, "wrong number of arguments (0 for 1)");
+ }
+ for (i=0; i<argc; i++) Check_Type(argv[i], T_MODULE);
+ while (argc--) {
+ rb_funcall(argv[argc], rb_intern("extend_object"), 1, obj);
+ rb_funcall(argv[argc], rb_intern("extended"), 1, obj);
+ }
+ return obj;
}
/*
@@ -2642,17 +2601,14 @@
*/
static VALUE
-top_include(argc, argv, self)
- int argc;
- VALUE *argv;
- VALUE self;
+top_include(int argc, VALUE *argv, VALUE self)
{
- rb_secure(4);
- if (ruby_wrapper) {
- rb_warning("main#include in the wrapped load is effective only in wrapper module");
- return rb_mod_include(argc, argv, ruby_wrapper);
- }
- return rb_mod_include(argc, argv, rb_cObject);
+ rb_secure(4);
+ if (ruby_wrapper) {
+ rb_warning("main#include in the wrapped load is effective only in wrapper module");
+ return rb_mod_include(argc, argv, ruby_wrapper);
+ }
+ return rb_mod_include(argc, argv, rb_cObject);
}
VALUE rb_f_trace_var();
@@ -2732,7 +2688,7 @@
th_collect_local_variables_in_heap(yarv_thread_t *th, VALUE *dfp, VALUE ary);
static VALUE
-rb_f_local_variables()
+rb_f_local_variables(void)
{
VALUE ary = rb_ary_new();
yarv_thread_t *th = GET_THREAD();
@@ -2774,90 +2730,90 @@
void
Init_eval()
{
- init = rb_intern("initialize");
- eqq = rb_intern("===");
- each = rb_intern("each");
+ init = rb_intern("initialize");
+ eqq = rb_intern("===");
+ each = rb_intern("each");
- aref = rb_intern("[]");
- aset = rb_intern("[]=");
- match = rb_intern("=~");
- missing = rb_intern("method_missing");
- added = rb_intern("method_added");
- singleton_added = rb_intern("singleton_method_added");
- removed = rb_intern("method_removed");
- singleton_removed = rb_intern("singleton_method_removed");
- undefined = rb_intern("method_undefined");
- singleton_undefined = rb_intern("singleton_method_undefined");
+ aref = rb_intern("[]");
+ aset = rb_intern("[]=");
+ match = rb_intern("=~");
+ missing = rb_intern("method_missing");
+ added = rb_intern("method_added");
+ singleton_added = rb_intern("singleton_method_added");
+ removed = rb_intern("method_removed");
+ singleton_removed = rb_intern("singleton_method_removed");
+ undefined = rb_intern("method_undefined");
+ singleton_undefined = rb_intern("singleton_method_undefined");
- __id__ = rb_intern("__id__");
- __send__ = rb_intern("__send__");
+ __id__ = rb_intern("__id__");
+ __send__ = rb_intern("__send__");
- rb_global_variable((VALUE*)&ruby_eval_tree);
+ rb_global_variable((VALUE*)&ruby_eval_tree);
- rb_define_virtual_variable("$@", errat_getter, errat_setter);
- rb_define_virtual_variable("$!", errinfo_getter, errinfo_setter);
+ rb_define_virtual_variable("$@", errat_getter, errat_setter);
+ rb_define_virtual_variable("$!", errinfo_getter, errinfo_setter);
- rb_define_global_function("eval", rb_f_eval, -1);
- rb_define_global_function("iterator?", rb_f_block_given_p, 0);
- rb_define_global_function("block_given?", rb_f_block_given_p, 0);
- rb_define_global_function("method_missing", rb_method_missing, -1);
- rb_define_global_function("loop", rb_f_loop, 0);
+ rb_define_global_function("eval", rb_f_eval, -1);
+ rb_define_global_function("iterator?", rb_f_block_given_p, 0);
+ rb_define_global_function("block_given?", rb_f_block_given_p, 0);
+ rb_define_global_function("method_missing", rb_method_missing, -1);
+ rb_define_global_function("loop", rb_f_loop, 0);
- rb_define_method(rb_mKernel, "respond_to?", obj_respond_to, -1);
- respond_to = rb_intern("respond_to?");
- basic_respond_to = rb_method_node(rb_cObject, respond_to);
- rb_global_variable((VALUE*)&basic_respond_to);
-
- rb_define_global_function("raise", rb_f_raise, -1);
- rb_define_global_function("fail", rb_f_raise, -1);
+ rb_define_method(rb_mKernel, "respond_to?", obj_respond_to, -1);
+ respond_to = rb_intern("respond_to?");
+ basic_respond_to = rb_method_node(rb_cObject, respond_to);
+ rb_global_variable((VALUE*)&basic_respond_to);
- rb_define_global_function("caller", rb_f_caller, -1);
+ rb_define_global_function("raise", rb_f_raise, -1);
+ rb_define_global_function("fail", rb_f_raise, -1);
- rb_define_global_function("global_variables", rb_f_global_variables, 0); /* in variable.c */
- rb_define_global_function("local_variables", rb_f_local_variables, 0);
+ rb_define_global_function("caller", rb_f_caller, -1);
- rb_define_method(rb_mKernel, "send", rb_f_send, -1);
- rb_define_method(rb_mKernel, "__send__", rb_f_send, -1);
- rb_define_method(rb_mKernel, "instance_eval", rb_obj_instance_eval, -1);
+ rb_define_global_function("global_variables", rb_f_global_variables, 0); /* in variable.c */
+ rb_define_global_function("local_variables", rb_f_local_variables, 0);
- rb_define_private_method(rb_cModule, "append_features", rb_mod_append_features, 1);
- rb_define_private_method(rb_cModule, "extend_object", rb_mod_extend_object, 1);
- rb_define_private_method(rb_cModule, "include", rb_mod_include, -1);
- rb_define_private_method(rb_cModule, "public", rb_mod_public, -1);
- rb_define_private_method(rb_cModule, "protected", rb_mod_protected, -1);
- rb_define_private_method(rb_cModule, "private", rb_mod_private, -1);
- rb_define_private_method(rb_cModule, "module_function", rb_mod_modfunc, -1);
- rb_define_method(rb_cModule, "method_defined?", rb_mod_method_defined, 1);
- rb_define_method(rb_cModule, "public_method_defined?", rb_mod_public_method_defined, 1);
- rb_define_method(rb_cModule, "private_method_defined?", rb_mod_private_method_defined, 1);
- rb_define_method(rb_cModule, "protected_method_defined?", rb_mod_protected_method_defined, 1);
- rb_define_method(rb_cModule, "public_class_method", rb_mod_public_method, -1);
- rb_define_method(rb_cModule, "private_class_method", rb_mod_private_method, -1);
- rb_define_method(rb_cModule, "module_eval", rb_mod_module_eval, -1);
- rb_define_method(rb_cModule, "class_eval", rb_mod_module_eval, -1);
+ rb_define_method(rb_mKernel, "send", rb_f_send, -1);
+ rb_define_method(rb_mKernel, "__send__", rb_f_send, -1);
+ rb_define_method(rb_mKernel, "instance_eval", rb_obj_instance_eval, -1);
- rb_undef_method(rb_cClass, "module_function");
+ rb_define_private_method(rb_cModule, "append_features", rb_mod_append_features, 1);
+ rb_define_private_method(rb_cModule, "extend_object", rb_mod_extend_object, 1);
+ rb_define_private_method(rb_cModule, "include", rb_mod_include, -1);
+ rb_define_private_method(rb_cModule, "public", rb_mod_public, -1);
+ rb_define_private_method(rb_cModule, "protected", rb_mod_protected, -1);
+ rb_define_private_method(rb_cModule, "private", rb_mod_private, -1);
+ rb_define_private_method(rb_cModule, "module_function", rb_mod_modfunc, -1);
+ rb_define_method(rb_cModule, "method_defined?", rb_mod_method_defined, 1);
+ rb_define_method(rb_cModule, "public_method_defined?", rb_mod_public_method_defined, 1);
+ rb_define_method(rb_cModule, "private_method_defined?", rb_mod_private_method_defined, 1);
+ rb_define_method(rb_cModule, "protected_method_defined?", rb_mod_protected_method_defined, 1);
+ rb_define_method(rb_cModule, "public_class_method", rb_mod_public_method, -1);
+ rb_define_method(rb_cModule, "private_class_method", rb_mod_private_method, -1);
+ rb_define_method(rb_cModule, "module_eval", rb_mod_module_eval, -1);
+ rb_define_method(rb_cModule, "class_eval", rb_mod_module_eval, -1);
- rb_define_private_method(rb_cModule, "remove_method", rb_mod_remove_method, -1);
- rb_define_private_method(rb_cModule, "undef_method", rb_mod_undef_method, -1);
- rb_define_private_method(rb_cModule, "alias_method", rb_mod_alias_method, 2);
+ rb_undef_method(rb_cClass, "module_function");
- rb_define_singleton_method(rb_cModule, "nesting", rb_mod_nesting, 0);
- rb_define_singleton_method(rb_cModule, "constants", rb_mod_s_constants, 0);
+ rb_define_private_method(rb_cModule, "remove_method", rb_mod_remove_method, -1);
+ rb_define_private_method(rb_cModule, "undef_method", rb_mod_undef_method, -1);
+ rb_define_private_method(rb_cModule, "alias_method", rb_mod_alias_method, 2);
- rb_define_singleton_method(ruby_top_self, "include", top_include, -1);
- rb_define_singleton_method(ruby_top_self, "public", top_public, -1);
- rb_define_singleton_method(ruby_top_self, "private", top_private, -1);
+ rb_define_singleton_method(rb_cModule, "nesting", rb_mod_nesting, 0);
+ rb_define_singleton_method(rb_cModule, "constants", rb_mod_s_constants, 0);
- rb_define_method(rb_mKernel, "extend", rb_obj_extend, -1);
+ rb_define_singleton_method(ruby_top_self, "include", top_include, -1);
+ rb_define_singleton_method(ruby_top_self, "public", top_public, -1);
+ rb_define_singleton_method(ruby_top_self, "private", top_private, -1);
- rb_define_global_function("trace_var", rb_f_trace_var, -1); /* in variable.c */
- rb_define_global_function("untrace_var", rb_f_untrace_var, -1); /* in variable.c */
+ rb_define_method(rb_mKernel, "extend", rb_obj_extend, -1);
- rb_define_global_function("set_trace_func", set_trace_func, 1);
- rb_global_variable(&trace_func);
+ rb_define_global_function("trace_var", rb_f_trace_var, -1); /* in variable.c */
+ rb_define_global_function("untrace_var", rb_f_untrace_var, -1); /* in variable.c */
- rb_define_virtual_variable("$SAFE", safe_getter, safe_setter);
+ rb_define_global_function("set_trace_func", set_trace_func, 1);
+ rb_global_variable(&trace_func);
+
+ rb_define_virtual_variable("$SAFE", safe_getter, safe_setter);
}
Modified: trunk/eval_load.c
===================================================================
--- trunk/eval_load.c 2006-02-06 14:52:06 UTC (rev 367)
+++ trunk/eval_load.c 2006-02-07 05:44:51 UTC (rev 368)
@@ -179,9 +179,6 @@
if ((status = EXEC_TAG()) == 0) {
rb_load(fname, wrap);
}
- else if (status == TAG_THREAD) {
- rb_thread_start_1();
- }
POP_THREAD_TAG();
if (state) *state = status;
}
Modified: trunk/eval_thread.c
===================================================================
--- trunk/eval_thread.c 2006-02-06 14:52:06 UTC (rev 367)
+++ trunk/eval_thread.c 2006-02-07 05:44:51 UTC (rev 368)
@@ -807,145 +807,6 @@
}
-/*
- * call-seq:
- * thr.safe_level => integer
- *
- * Returns the safe level in effect for <i>thr</i>. Setting thread-local safe
- * levels can help when implementing sandboxes which run insecure code.
- *
- * thr = Thread.new { $SAFE = 3; sleep }
- * Thread.current.safe_level #=> 0
- * thr.safe_level #=> 3
- */
-
-static VALUE
-rb_thread_safe_level(thread)
- VALUE thread;
-{
- rb_thread_t th;
-
- th = rb_thread_check(thread);
- if (th == curr_thread) {
- return INT2NUM(ruby_safe_level);
- }
- return INT2NUM(th->safe);
-}
-
-static int ruby_thread_abort;
-static VALUE thgroup_default;
-
-
-/*
- * call-seq:
- * Thread.abort_on_exception => true or false
- *
- * Returns the status of the global ``abort on exception'' condition. The
- * default is <code>false</code>. When set to <code>true</code>, or if the
- * global <code>$DEBUG</code> flag is <code>true</code> (perhaps because the
- * command line option <code>-d</code> was specified) all threads will abort
- * (the process will <code>exit(0)</code>) if an exception is raised in any
- * thread. See also <code>Thread::abort_on_exception=</code>.
- */
-
-static VALUE
-rb_thread_s_abort_exc()
-{
- return ruby_thread_abort?Qtrue:Qfalse;
-}
-
-
-/*
- * call-seq:
- * Thread.abort_on_exception= boolean => true or false
- *
- * When set to <code>true</code>, all threads will abort if an exception is
- * raised. Returns the new state.
- *
- * Thread.abort_on_exception = true
- * t1 = Thread.new do
- * puts "In new thread"
- * raise "Exception from thread"
- * end
- * sleep(1)
- * puts "not reached"
- *
- * <em>produces:</em>
- *
- * In new thread
- * prog.rb:4: Exception from thread (RuntimeError)
- * from prog.rb:2:in `initialize'
- * from prog.rb:2:in `new'
- * from prog.rb:2
- */
-
-static VALUE
-rb_thread_s_abort_exc_set(self, val)
- VALUE self, val;
-{
- rb_secure(4);
- ruby_thread_abort = RTEST(val);
- return val;
-}
-
-
-/*
- * call-seq:
- * thr.abort_on_exception => true or false
- *
- * Returns the status of the thread-local ``abort on exception'' condition for
- * <i>thr</i>. The default is <code>false</code>. See also
- * <code>Thread::abort_on_exception=</code>.
- */
-
-static VALUE
-rb_thread_abort_exc(thread)
- VALUE thread;
-{
- return rb_thread_check(thread)->abort?Qtrue:Qfalse;
-}
-
-
-/*
- * call-seq:
- * thr.abort_on_exception= boolean => true or false
- *
- * When set to <code>true</code>, causes all threads (including the main
- * program) to abort if an exception is raised in <i>thr</i>. The process will
- * effectively <code>exit(0)</code>.
- */
-
-static VALUE
-rb_thread_abort_exc_set(thread, val)
- VALUE thread, val;
-{
- rb_secure(4);
- rb_thread_check(thread)->abort = RTEST(val);
- return val;
-}
-
-
-/*
- * call-seq:
- * thr.group => thgrp or nil
- *
- * Returns the <code>ThreadGroup</code> which contains <i>thr</i>, or nil if
- * the thread is not a member of any group.
- *
- * Thread.main.group #=> #<ThreadGroup:0x4029d914>
- */
-
-VALUE
-rb_thread_group(thread)
- VALUE thread;
-{
- VALUE group = rb_thread_check(thread)->thgroup;
- if (!group) {
- group = Qnil;
- }
- return group;
-}
-
#ifdef __ia64__
# define IA64_INIT(x) x
#else
@@ -1065,24 +926,6 @@
int rb_thread_tick = THREAD_TICK;
#endif
-NORETURN(static void rb_thread_terminated _((rb_thread_t, int, enum yarv_thread_status)));
-static VALUE rb_thread_yield _((VALUE, rb_thread_t));
-
-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)();
@@ -1093,75 +936,13 @@
return 0; /* not reached */
}
-static void
-rb_thread_terminated(th, state, status)
- rb_thread_t th;
- int state;
- enum yarv_thread_status status;
-{
- if (state && status != THREAD_TO_KILL && !NIL_P(GET_THREAD()->errinfo)) {
- th->flags |= THREAD_RAISED;
- if (state == TAG_FATAL) {
- /* fatal error within this thread, need to stop whole script */
- main_thread->errinfo = GET_THREAD()->errinfo;
- rb_thread_cleanup();
- }
- else if (rb_obj_is_kind_of(GET_THREAD()->errinfo, rb_eSystemExit)) {
- if (th->safe >= 4) {
- char buf[32];
-
- sprintf(buf, "Insecure exit at level %d", th->safe);
- th->errinfo = rb_exc_new2(rb_eSecurityError, buf);
- }
- else {
- /* delegate exception to main_thread */
- rb_thread_main_jump(GET_THREAD()->errinfo, RESTORE_RAISE);
- }
- }
- else if (th->safe < 4 && (ruby_thread_abort || th->abort || RTEST(ruby_debug))) {
- /* exit on main_thread */
- rb_thread_main_jump(GET_THREAD()->errinfo, RESTORE_EXIT);
- }
- else {
- th->errinfo = GET_THREAD()->errinfo;
- }
- }
- rb_thread_schedule();
- ruby_stop(0); /* last thread termination */
-}
-
-static VALUE
-rb_thread_yield_0(arg)
- VALUE arg;
-{
- return rb_thread_yield(arg, curr_thread);
-}
-
-void
-rb_thread_start_1()
-{
- // TODO
- rb_bug("unsupported: rb_thread_start_1");
-}
-
VALUE
-rb_thread_create(fn, arg)
- VALUE (*fn)();
- void *arg;
+rb_thread_create(VALUE (*fn)(), void *arg)
{
- Init_stack((VALUE*)&arg);
- return rb_thread_start_0(fn, arg, rb_thread_alloc(rb_cThread));
+ Init_stack((VALUE*)&arg);
+ return rb_thread_start_0(fn, arg, rb_thread_alloc(rb_cThread));
}
-static VALUE
-rb_thread_yield(arg, th)
- VALUE arg;
- rb_thread_t th;
-{
- const ID *tbl;
- UNSUPPORTED(rb_thread_yield);
-}
-
/*
* call-seq:
* Thread.new([arg]*) {|args| block } => thread
@@ -1219,24 +1000,10 @@
*/
static VALUE
-rb_thread_initialize(thread, args)
- VALUE thread, args;
+rb_thread_initialize(VALUE thread, VALUE args)
{
- rb_thread_t th;
-
- if (!rb_block_given_p()) {
- rb_raise(rb_eThreadError, "must be called with a block");
- }
- th = rb_thread_check(thread);
- if (th->stk_max) {
- NODE *node = th->node;
- if (!node) {
- rb_raise(rb_eThreadError, "already initialized thread");
- }
- rb_raise(rb_eThreadError, "already initialized thread - %s:%d",
- node->nd_file, nd_line(node));
- }
- return rb_thread_start_0(rb_thread_yield, args, th);
+ // TODO
+ return Qnil;
}
@@ -1251,13 +1018,10 @@
*/
static VALUE
-rb_thread_start(klass, args)
- VALUE klass, args;
+rb_thread_start(VALUE klass, VALUE args)
{
- if (!rb_block_given_p()) {
- rb_raise(rb_eThreadError, "must be called with a block");
- }
- return rb_thread_start_0(rb_thread_yield, args, rb_thread_alloc(klass));
+ // TODO
+ return Qnil;
}
@@ -1432,186 +1196,7 @@
UNSUPPORTED(rb_cont_call);
}
-struct thgroup {
- int enclosed;
- VALUE group;
-};
-
-/*
- * Document-class: ThreadGroup
- *
- * <code>ThreadGroup</code> provides a means of keeping track of a number of
- * threads as a group. A <code>Thread</code> can belong to only one
- * <code>ThreadGroup</code> at a time; adding a thread to a new group will
- * remove it from any previous group.
- *
- * Newly created threads belong to the same group as the thread from which they
- * were created.
- */
-
-static VALUE thgroup_s_alloc _((VALUE));
-static VALUE
-thgroup_s_alloc(klass)
- VALUE klass;
-{
- VALUE group;
- struct thgroup *data;
-
- group = Data_Make_Struct(klass, struct thgroup, 0, free, data);
- data->enclosed = 0;
- data->group = group;
-
- return group;
-}
-
-
-/*
- * call-seq:
- * thgrp.list => array
- *
- * Returns an array of all existing <code>Thread</code> objects that belong to
- * this group.
- *
- * ThreadGroup::Default.list #=> [#<Thread:0x401bdf4c run>]
- */
-
-static VALUE
-thgroup_list(group)
- VALUE group;
-{
- struct thgroup *data;
- rb_thread_t th;
- VALUE ary;
-
- Data_Get_Struct(group, struct thgroup, data);
- ary = rb_ary_new();
-
- FOREACH_THREAD(th) {
- if (th->thgroup == data->group) {
- rb_ary_push(ary, th->thread);
- }
- }
- END_FOREACH(th);
-
- return ary;
-}
-
-
-/*
- * call-seq:
- * thgrp.enclose => thgrp
- *
- * Prevents threads from being added to or removed from the receiving
- * <code>ThreadGroup</code>. New threads can still be started in an enclosed
- * <code>ThreadGroup</code>.
- *
- * ThreadGroup::Default.enclose #=> #<ThreadGroup:0x4029d914>
- * thr = Thread::new { Thread.stop } #=> #<Thread:0x402a7210 sleep>
- * tg = ThreadGroup::new #=> #<ThreadGroup:0x402752d4>
- * tg.add thr
- *
- * <em>produces:</em>
- *
- * ThreadError: can't move from the enclosed thread group
- */
-
-VALUE
-thgroup_enclose(group)
- VALUE group;
-{
- struct thgroup *data;
-
- Data_Get_Struct(group, struct thgroup, data);
- data->enclosed = 1;
-
- return group;
-}
-
-
-/*
- * call-seq:
- * thgrp.enclosed? => true or false
- *
- * Returns <code>true</code> if <em>thgrp</em> is enclosed. See also
- * ThreadGroup#enclose.
- */
-
-static VALUE
-thgroup_enclosed_p(group)
- VALUE group;
-{
- struct thgroup *data;
-
- Data_Get_Struct(group, struct thgroup, data);
- if (data->enclosed) return Qtrue;
- return Qfalse;
-}
-
-
-/*
- * call-seq:
- * thgrp.add(thread) => thgrp
- *
- * Adds the given <em>thread</em> to this group, removing it from any other
- * group to which it may have previously belonged.
- *
- * puts "Initial group is #{ThreadGroup::Default.list}"
- * tg = ThreadGroup.new
- * t1 = Thread.new { sleep }
- * t2 = Thread.new { sleep }
- * puts "t1 is #{t1}"
- * puts "t2 is #{t2}"
- * tg.add(t1)
- * puts "Initial group now #{ThreadGroup::Default.list}"
- * puts "tg group now #{tg.list}"
- *
- * <em>produces:</em>
- *
- * Initial group is #<Thread:0x401bdf4c>
- * t1 is #<Thread:0x401b3c90>
- * t2 is #<Thread:0x401b3c18>
- * Initial group now #<Thread:0x401b3c18>#<Thread:0x401bdf4c>
- * tg group now #<Thread:0x401b3c90>
- */
-
-static VALUE
-thgroup_add(group, thread)
- VALUE group, thread;
-{
- rb_thread_t th;
- struct thgroup *data;
-
- rb_secure(4);
- th = rb_thread_check(thread);
- if (!th->next || !th->prev) {
- rb_raise(rb_eTypeError, "wrong argument type %s (expected Thread)",
- rb_obj_classname(thread));
- }
-
- if (OBJ_FROZEN(group)) {
- rb_raise(rb_eThreadError, "can't move to the frozen thread group");
- }
- Data_Get_Struct(group, struct thgroup, data);
- if (data->enclosed) {
- rb_raise(rb_eThreadError, "can't move to the enclosed thread group");
- }
-
- if (!th->thgroup) {
- return Qnil;
- }
- if (OBJ_FROZEN(th->thgroup)) {
- rb_raise(rb_eThreadError, "can't move from the frozen thread group");
- }
- Data_Get_Struct(th->thgroup, struct thgroup, data);
- if (data->enclosed) {
- rb_raise(rb_eThreadError, "can't move from the enclosed thread group");
- }
-
- th->thgroup = group;
- return group;
-}
-
/* variables for recursive traversals */
static ID recursive_key;
@@ -1643,12 +1228,6 @@
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, "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_cCont = rb_define_class("Continuation", rb_cObject);
rb_undef_alloc_func(rb_cCont);
rb_undef_method(CLASS_OF(rb_cCont), "new");
@@ -1656,16 +1235,6 @@
rb_define_method(rb_cCont, "[]", rb_cont_call, -1);
rb_define_global_function("callcc", rb_callcc, 0);
- cThGroup = rb_define_class("ThreadGroup", rb_cObject);
- rb_define_alloc_func(cThGroup, thgroup_s_alloc);
- rb_define_method(cThGroup, "list", thgroup_list, 0);
- 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);
- thgroup_default = rb_obj_alloc(cThGroup);
- rb_define_const(cThGroup, "Default", thgroup_default);
- rb_global_variable(&thgroup_default);
-
*/
}
Modified: trunk/gc.c
===================================================================
--- trunk/gc.c 2006-02-06 14:52:06 UTC (rev 367)
+++ trunk/gc.c 2006-02-07 05:44:51 UTC (rev 368)
@@ -109,6 +109,11 @@
static int gc_debug_flag = 0;
static VALUE
+get_gc_debug_flag(VALUE self){
+ return gc_debug_flag ? Qtrue : Qfalse;
+}
+
+static VALUE
set_gc_debug_flag(VALUE self, VALUE v){
gc_debug_flag = (v == Qtrue);
return v;
@@ -971,6 +976,14 @@
}
break;
+ case T_VALUE:
+ {
+ rb_gc_mark(RVALUE(obj)->v1);
+ rb_gc_mark(RVALUE(obj)->v2);
+ ptr = RVALUE(obj)->v3;
+ }
+ break;
+
default:
rb_bug("rb_gc_mark(): unknown data type 0x%lx(%p) %s",
obj->as.basic.flags & T_MASK, obj,
@@ -1181,6 +1194,7 @@
case T_FLOAT:
case T_VARMAP:
case T_BLOCK:
+ case T_VALUE:
break;
case T_BIGNUM:
@@ -1216,7 +1230,6 @@
if (RANY(obj)->as.rstruct.ptr) {
RUBY_CRITICAL(free(RANY(obj)->as.rstruct.ptr));
}
- break;
default:
rb_bug("gc_sweep(): unknown data type 0x%lx(%p)",
@@ -1885,6 +1898,7 @@
rb_define_singleton_method(rb_mGC, "start", rb_gc_start, 0);
rb_define_singleton_method(rb_mGC, "enable", rb_gc_enable, 0);
rb_define_singleton_method(rb_mGC, "disable", rb_gc_disable, 0);
+ rb_define_singleton_method(rb_mGC, "debug_flag", get_gc_debug_flag, 0);
rb_define_singleton_method(rb_mGC, "debug_flag=", set_gc_debug_flag, 1);
rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0);
Modified: trunk/ruby.h
===================================================================
--- trunk/ruby.h 2006-02-06 14:52:06 UTC (rev 367)
+++ trunk/ruby.h 2006-02-07 05:44:51 UTC (rev 368)
@@ -220,6 +220,7 @@
#define T_MATCH 0x13
#define T_SYMBOL 0x14
+#define T_VALUE 0x1a
#define T_BLOCK 0x1b
#define T_UNDEF 0x1c
#define T_VARMAP 0x1d
@@ -334,6 +335,13 @@
struct st_table *iv_tbl;
};
+struct RValue {
+ struct RBasic basic;
+ VALUE v1;
+ VALUE v2;
+ VALUE v3;
+};
+
struct RClass {
struct RBasic basic;
struct st_table *iv_tbl;
@@ -444,6 +452,7 @@
#define RSTRUCT(obj) (R_CAST(RStruct)(obj))
#define RBIGNUM(obj) (R_CAST(RBignum)(obj))
#define RFILE(obj) (R_CAST(RFile)(obj))
+#define RVALUE(obj) (R_CAST(RValue)(obj))
#define FL_SINGLETON FL_USER0
#define FL_MARK (1<<5)
Modified: trunk/signal.c
===================================================================
--- trunk/signal.c 2006-02-06 14:52:06 UTC (rev 367)
+++ trunk/signal.c 2006-02-07 05:44:51 UTC (rev 368)
@@ -419,7 +419,7 @@
if(next_head == th->signal_queue.tail){
/* signal queue overflow */
- fprintf(stderr, "Signal Queue overflow. This signal (%d) is ignored.", sig);
+ fprintf(stderr, "Signal Queue overflow. This signal (%d) is ignored.\n", sig);
}
else{
th->signal_queue.buff[th->signal_queue.head] = sig;
Modified: trunk/test/ruby/test_gc.rb
===================================================================
--- trunk/test/ruby/test_gc.rb 2006-02-06 14:52:06 UTC (rev 367)
+++ trunk/test/ruby/test_gc.rb 2006-02-07 05:44:51 UTC (rev 368)
@@ -8,7 +8,8 @@
end
def test_gc
- # GC.debug_flag = false
+ prev_df = GC.debug_flag
+ GC.debug_flag = false
assert_nothing_raised do
1.upto(10000) {
@@ -29,6 +30,6 @@
GC.start
assert true # reach here or dumps core
- # GC.debug_flag = true
+ GC.debug_flag = prev_df
end
end
Modified: trunk/test.rb
===================================================================
--- trunk/test.rb 2006-02-06 14:52:06 UTC (rev 367)
+++ trunk/test.rb 2006-02-07 05:44:51 UTC (rev 368)
@@ -1,4 +1,118 @@
+
+ /a(b)(c)d/ =~ 'xyzabcdefgabcdefg'
+ [$1, $2, $3, $~.class, $&, $`, $', $+]
+
+
+__END__
+
+class C
+end
+
+C.module_eval %q{
+ def m
+ end
+}
+
+__END__
+
+require 'fileutils'
+
+__END__
+
+thg = ThreadGroup.new
+
t = Thread.new{
+ thg.add Thread.current
+ sleep
+}
+sleep 0.1
+[thg.list.size, ThreadGroup::Default.size]
+
+__END__
+a = b = nil
+ if a and b
+ p :ng
+ end
+ p :ok
+__END__
+ a = nil
+ if !a
+ p :ok
+ end
+__END__
+
+if 1
+ p :ok
+ end
+ if false
+ p :ng
+ end
+__END__
+a = nil
+while a
+ b
+end
+
+__END__
+
+require 'timeout'
+timeout(1){
+ sleep
+}
+
+__END__
+
+Thread.new{
+ i = 0
+ loop{
+ p i+=1
+ sleep 0.1
+ }
+}
+gets
+__END__
+
+a = b = c = false
+p((a and b and c))
+a = b = c = nil
+p((a and b and c))
+
+__END__
+
+a = 0
+ if a > 10
+ a = :then
+ elsif a > 5
+ a = :elsif1
+ elsif a > 0
+ a = :elsif2
+ else
+ a = :else
+ end
+ exit
+__END__
+if a
+ p 1
+end
+__END__
+Thread.new{
+ break
+}.join
+
+__END__
+
+fork do
+ break
+end
+__END__
+pid = fork{
+ p 1
+}
+#Process.waitpid(pid)
+
+__END__
+
+t = Thread.new{
Thread.stop
}
sleep 0.1
Modified: trunk/thread.c
===================================================================
--- trunk/thread.c 2006-02-06 14:52:06 UTC (rev 367)
+++ trunk/thread.c 2006-02-07 05:44:51 UTC (rev 368)
@@ -144,6 +144,7 @@
GetProcVal(th->first_proc, proc);
th->machine_stack_start = stack_start;
+ th->thgroup = th->vm->thgroup_default;
thread_debug("thread start: %p\n", th);
@@ -471,7 +472,6 @@
VALUE err = th->throwed_errinfo;
th->throwed_errinfo = 0;
if(err == eKillSignal){
- th->status == THREAD_TO_KILL;
TH_JUMP_TAG(th, TAG_FATAL);
}
else{
@@ -793,6 +793,122 @@
return GET_VM()->main_thread_val;
}
+
+/*
+ * call-seq:
+ * Thread.abort_on_exception => true or false
+ *
+ * Returns the status of the global ``abort on exception'' condition. The
+ * default is <code>false</code>. When set to <code>true</code>, or if the
+ * global <code>$DEBUG</code> flag is <code>true</code> (perhaps because the
+ * command line option <code>-d</code> was specified) all threads will abort
+ * (the process will <code>exit(0)</code>) if an exception is raised in any
+ * thread. See also <code>Thread::abort_on_exception=</code>.
+ */
+
+static VALUE
+rb_thread_s_abort_exc()
+{
+ return GET_VM()->thread_abort_on_exception ? Qtrue : Qfalse;
+}
+
+
+/*
+ * call-seq:
+ * Thread.abort_on_exception= boolean => true or false
+ *
+ * When set to <code>true</code>, all threads will abort if an exception is
+ * raised. Returns the new state.
+ *
+ * Thread.abort_on_exception = true
+ * t1 = Thread.new do
+ * puts "In new thread"
+ * raise "Exception from thread"
+ * end
+ * sleep(1)
+ * puts "not reached"
+ *
+ * <em>produces:</em>
+ *
+ * In new thread
+ * prog.rb:4: Exception from thread (RuntimeError)
+ * from prog.rb:2:in `initialize'
+ * from prog.rb:2:in `new'
+ * from prog.rb:2
+ */
+
+static VALUE
+rb_thread_s_abort_exc_set(VALUE self, VALUE val)
+{
+ rb_secure(4);
+ GET_VM()->thread_abort_on_exception = RTEST(val);
+ return val;
+}
+
+
+/*
+ * call-seq:
+ * thr.abort_on_exception => true or false
+ *
+ * Returns the status of the thread-local ``abort on exception'' condition for
+ * <i>thr</i>. The default is <code>false</code>. See also
+ * <code>Thread::abort_on_exception=</code>.
+ */
+
+static VALUE
+rb_thread_abort_exc(VALUE thread)
+{
+ yarv_thread_t *th;
+ GetThreadVal(thread, th);
+ return th->abort_on_exception ? Qtrue : Qfalse;
+}
+
+
+/*
+ * call-seq:
+ * thr.abort_on_exception= boolean => true or false
+ *
+ * When set to <code>true</code>, causes all threads (including the main
+ * program) to abort if an exception is raised in <i>thr</i>. The process will
+ * effectively <code>exit(0)</code>.
+ */
+
+static VALUE
+rb_thread_abort_exc_set(VALUE thread, VALUE val)
+{
+ yarv_thread_t *th;
+ rb_secure(4);
+
+ GetThreadVal(thread, th);
+ th->abort_on_exception = RTEST(val);
+ return val;
+}
+
+
+/*
+ * call-seq:
+ * thr.group => thgrp or nil
+ *
+ * Returns the <code>ThreadGroup</code> which contains <i>thr</i>, or nil if
+ * the thread is not a member of any group.
+ *
+ * Thread.main.group #=> #<ThreadGroup:0x4029d914>
+ */
+
+VALUE
+rb_thread_group(VALUE thread)
+{
+ yarv_thread_t *th;
+ VALUE group;
+ GetThreadVal(thread, th);
+ group = th->thgroup;
+
+ if (!group) {
+ group = Qnil;
+ }
+ return group;
+}
+
static const char *
thread_status_name(enum yarv_thread_status status)
{
@@ -902,6 +1018,27 @@
}
/*
+ * call-seq:
+ * thr.safe_level => integer
+ *
+ * Returns the safe level in effect for <i>thr</i>. Setting thread-local safe
+ * levels can help when implementing sandboxes which run insecure code.
+ *
+ * thr = Thread.new { $SAFE = 3; sleep }
+ * Thread.current.safe_level #=> 0
+ * thr.safe_level #=> 3
+ */
+
+static VALUE
+rb_thread_safe_level(VALUE thread)
+{
+ yarv_thread_t *th;
+ GetThreadVal(thread, th);
+
+ return INT2NUM(th->safe_level);
+}
+
+/*
* call-seq:
* thr.inspect => string
*
@@ -1267,8 +1404,197 @@
return rb_str_new2(buff);
}
+
+
+struct thgroup {
+ int enclosed;
+ VALUE group;
+};
+
+/*
+ * Document-class: ThreadGroup
+ *
+ * <code>ThreadGroup</code> provides a means of keeping track of a number of
+ * threads as a group. A <code>Thread</code> can belong to only one
+ * <code>ThreadGroup</code> at a time; adding a thread to a new group will
+ * remove it from any previous group.
+ *
+ * Newly created threads belong to the same group as the thread from which they
+ * were created.
+ */
+
+static VALUE thgroup_s_alloc _((VALUE));
+static VALUE
+thgroup_s_alloc(VALUE klass)
+{
+ VALUE group;
+ struct thgroup *data;
+
+ group = Data_Make_Struct(klass, struct thgroup, 0, free, data);
+ data->enclosed = 0;
+ data->group = group;
+
+ return group;
+}
+
+struct thgroup_list_params{
+ VALUE ary;
+ VALUE group;
+};
+
+static int
+thgroup_list_i(st_data_t key, st_data_t val, st_data_t data)
+{
+ VALUE thread = (VALUE)key;
+ VALUE ary = ((struct thgroup_list_params *)data)->ary;
+ VALUE group = ((struct thgroup_list_params *)data)->group;
+ yarv_thread_t *th;
+ GetThreadVal(thread, th);
+
+ if(th->thgroup == group){
+ rb_ary_push(ary, thread);
+ }
+ return ST_CONTINUE;
+}
+
+/*
+ * call-seq:
+ * thgrp.list => array
+ *
+ * Returns an array of all existing <code>Thread</code> objects that belong to
+ * this group.
+ *
+ * ThreadGroup::Default.list #=> [#<Thread:0x401bdf4c run>]
+ */
+
+static VALUE
+thgroup_list(VALUE group)
+{
+ yarv_thread_t *th;
+ VALUE ary = rb_ary_new();
+ struct thgroup_list_params param = {
+ ary, group,
+ };
+ st_foreach(GET_VM()->living_threads, thgroup_list_i, (st_data_t)¶m);
+ return ary;
+}
+
+
+/*
+ * call-seq:
+ * thgrp.enclose => thgrp
+ *
+ * Prevents threads from being added to or removed from the receiving
+ * <code>ThreadGroup</code>. New threads can still be started in an enclosed
+ * <code>ThreadGroup</code>.
+ *
+ * ThreadGroup::Default.enclose #=> #<ThreadGroup:0x4029d914>
+ * thr = Thread::new { Thread.stop } #=> #<Thread:0x402a7210 sleep>
+ * tg = ThreadGroup::new #=> #<ThreadGroup:0x402752d4>
+ * tg.add thr
+ *
+ * <em>produces:</em>
+ *
+ * ThreadError: can't move from the enclosed thread group
+ */
+
+VALUE
+thgroup_enclose(group)
+ VALUE group;
+{
+ struct thgroup *data;
+
+ Data_Get_Struct(group, struct thgroup, data);
+ data->enclosed = 1;
+
+ return group;
+}
+
+
+/*
+ * call-seq:
+ * thgrp.enclosed? => true or false
+ *
+ * Returns <code>true</code> if <em>thgrp</em> is enclosed. See also
+ * ThreadGroup#enclose.
+ */
+
+static VALUE
+thgroup_enclosed_p(VALUE group)
+{
+ struct thgroup *data;
+
+ Data_Get_Struct(group, struct thgroup, data);
+ if (data->enclosed) return Qtrue;
+ return Qfalse;
+}
+
+
+/*
+ * call-seq:
+ * thgrp.add(thread) => thgrp
+ *
+ * Adds the given <em>thread</em> to this group, removing it from any other
+ * group to which it may have previously belonged.
+ *
+ * puts "Initial group is #{ThreadGroup::Default.list}"
+ * tg = ThreadGroup.new
+ * t1 = Thread.new { sleep }
+ * t2 = Thread.new { sleep }
+ * puts "t1 is #{t1}"
+ * puts "t2 is #{t2}"
+ * tg.add(t1)
+ * puts "Initial group now #{ThreadGroup::Default.list}"
+ * puts "tg group now #{tg.list}"
+ *
+ * <em>produces:</em>
+ *
+ * Initial group is #<Thread:0x401bdf4c>
+ * t1 is #<Thread:0x401b3c90>
+ * t2 is #<Thread:0x401b3c18>
+ * Initial group now #<Thread:0x401b3c18>#<Thread:0x401bdf4c>
+ * tg group now #<Thread:0x401b3c90>
+ */
+
+static VALUE
+thgroup_add(VALUE group, VALUE thread)
+{
+ yarv_thread_t *th;
+ struct thgroup *data;
+
+ rb_secure(4);
+ GetThreadVal(thread, th);
+
+ if (OBJ_FROZEN(group)) {
+ rb_raise(rb_eThreadError, "can't move to the frozen thread group");
+ }
+ Data_Get_Struct(group, struct thgroup, data);
+ if (data->enclosed) {
+ rb_raise(rb_eThreadError, "can't move to the enclosed thread group");
+ }
+
+ if (!th->thgroup) {
+ return Qnil;
+ }
+
+ if (OBJ_FROZEN(th->thgroup)) {
+ rb_raise(rb_eThreadError, "can't move from the frozen thread group");
+ }
+ Data_Get_Struct(th->thgroup, struct thgroup, data);
+ if (data->enclosed) {
+ rb_raise(rb_eThreadError, "can't move from the enclosed thread group");
+ }
+
+ th->thgroup = group;
+ return group;
+}
+
+
void
Init_yarvthread(){
+ VALUE cThGroup;
+ VALUE thgroup_default;
+
rb_define_global_function("raw_gets", raw_gets, 0);
rb_define_singleton_method(cYarvThread, "new", yarv_thread_s_new, -2);
@@ -1300,8 +1626,22 @@
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);
-
+
+ cThGroup = rb_define_class("ThreadGroup", rb_cObject);
+ rb_define_alloc_func(cThGroup, thgroup_s_alloc);
+ rb_define_method(cThGroup, "list", thgroup_list, 0);
+ 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_VM()->thgroup_default = thgroup_default = rb_obj_alloc(cThGroup);
+ rb_define_const(cThGroup, "Default", thgroup_default);
+
Init_native_thread();
{
/* main thread setting */
Modified: trunk/vm.c
===================================================================
--- trunk/vm.c 2006-02-06 14:52:06 UTC (rev 367)
+++ trunk/vm.c 2006-02-07 05:44:51 UTC (rev 368)
@@ -643,26 +643,28 @@
static VALUE *
lfp_svar(VALUE *lfp, int cnt)
{
- NODE *node = (NODE*)lfp[-1];
+ struct RValue *val = (struct RValue *)lfp[-1];
- if((VALUE)node == Qnil){
- lfp[-1] = (VALUE)(node = NEW_IF(Qnil, Qnil, 0));
- node->nd_file = 0;
+ if((VALUE)val == Qnil){
+ val = RVALUE(rb_newobj());
+ OBJSETUP(val, 0, T_VALUE);
+ val->v1 = val->v2 = val->v3 = Qnil;
+ lfp[-1] = (VALUE)val;
}
if(cnt == 0){
- return &node->u1.value;
+ return &val->v1;
}
else if(cnt == 1){
- return &node->u2.value;
+ return &val->v2;
}
else if(cnt == -1){
- return (VALUE*)&node->nd_file;
+ return &val->basic.klass;
}
else{
VALUE ary;
- if((ary = node->u3.value) == 0){
- ary = node->u3.value = rb_ary_new();
+ if((ary = val->v3) == 0){
+ ary = val->v3 = rb_ary_new();
}
if(RARRAY(ary)->len <= cnt){
rb_ary_store(ary, cnt, Qnil);
Modified: trunk/yarvcore.c
===================================================================
--- trunk/yarvcore.c 2006-02-06 14:52:06 UTC (rev 367)
+++ trunk/yarvcore.c 2006-02-07 05:44:51 UTC (rev 368)
@@ -575,6 +575,7 @@
if(ptr){
yarv_vm_t *vm = ptr;
st_foreach(vm->living_threads, vm_mark_each_thread_func, 0);
+ MARK_UNLESS_NULL(vm->thgroup_default);
}
MARK_REPORT("<- vm", 0);
}
@@ -659,6 +660,7 @@
MARK_UNLESS_NULL(th->first_proc);
MARK_UNLESS_NULL(th->first_args);
+ MARK_UNLESS_NULL(th->thgroup);
MARK_UNLESS_NULL(th->wait_thread_value);
MARK_UNLESS_NULL(th->value);
MARK_UNLESS_NULL(th->errinfo);
@@ -1187,7 +1189,9 @@
th->machine_stack_start = rb_gc_stack_start;
Init_yarvthread();
-
+
+ th->thgroup = th->vm->thgroup_default;
+
vm->living_threads = st_init_numtable();
st_insert(vm->living_threads, th->self, (st_data_t)th->thread_id);
}
Modified: trunk/yarvcore.h
===================================================================
--- trunk/yarvcore.h 2006-02-06 14:52:06 UTC (rev 367)
+++ trunk/yarvcore.h 2006-02-07 05:44:51 UTC (rev 368)
@@ -291,7 +291,9 @@
VALUE main_thread_val;
st_table *living_threads;
+ VALUE thgroup_default;
+ int thread_abort_on_exception;
int exit_code;
unsigned long trace_flag;
} yarv_vm_t;
@@ -378,7 +380,8 @@
int priority;
native_thread_data_t native_thread_data;
-
+
+ VALUE thgroup;
VALUE value;
VALUE wait_thread_value;
@@ -409,7 +412,7 @@
/* misc */
int method_missing_reason;
-
+ int abort_on_exception;
} yarv_thread_t;
/** node -> yarv instruction sequence object */
Modified: trunk/yarvtest/test_thread.rb
===================================================================
--- trunk/yarvtest/test_thread.rb 2006-02-06 14:52:06 UTC (rev 367)
+++ trunk/yarvtest/test_thread.rb 2006-02-07 05:44:51 UTC (rev 368)
@@ -118,6 +118,25 @@
}.value + Thread.current[:a]
}
end
-
+
+ def test_thread_group
+ ae %q{
+ ptg = Thread.current.group
+ Thread.new{
+ ctg = Thread.current.group
+ [ctg.class, ctg == ptg]
+ }.value
+ }
+ ae %q{
+ thg = ThreadGroup.new
+
+ t = Thread.new{
+ thg.add Thread.current
+ sleep
+ }
+ sleep 0.1
+ [thg.list.size, ThreadGroup::Default.list.size]
+ }
+ end
end
--
ML: yarv-diff quickml.atdot.net
Info: http://www.atdot.net/~ko1/quickml