From: Tanaka Akira Date: 2007-06-14T14:28:22+09:00 Subject: [ruby-dev:30982] Re: Linux/ia64で'ucontext_t' undeclared In article , Yukihiro Matsumoto writes: > |# make testは実行できて(859 failed 14) > |# make TESTS=ruby test-allはIllegal instructionでした > > Illegal instructionはいずれ追いかけないといけないでしょうね。 マルチスレッドになったんだから各スレッドの register stack を GC で scan しないといけないし、Fiber や継続では register stack を保存・復帰しなきゃいけないのに、そういうコードがない んだから、そういうコードを足すところからですね。 そうやっても test-all で SEGV しますが、それが ia64 固有かど うかはよくわかりません。SEGV するのは ia64 だけじゃありませ んし。 いくらか GC 問題もつぶしましたが、その際の印象として、YARV では VALUE を含む構造体へのポインタを扱っていて剣呑ですねぇ。 Index: eval_load.c =================================================================== --- eval_load.c (revision 12533) +++ eval_load.c (working copy) @@ -574,10 +574,10 @@ void Init_load() { - rb_load_path = rb_ary_new(); rb_define_readonly_variable("$:", &rb_load_path); rb_define_readonly_variable("$-I", &rb_load_path); rb_define_readonly_variable("$LOAD_PATH", &rb_load_path); + rb_load_path = rb_ary_new(); rb_define_virtual_variable("$\"", get_loaded_features, 0); rb_define_virtual_variable("$LOADED_FEATURES", get_loaded_features, 0); Index: variable.c =================================================================== --- variable.c (revision 12533) +++ variable.c (working copy) @@ -428,7 +428,8 @@ void rb_gc_mark_global_tbl(void) { - st_foreach_safe(rb_global_tbl, mark_global_entry, 0); + if (rb_global_tbl) + st_foreach_safe(rb_global_tbl, mark_global_entry, 0); } static ID Index: thread.c =================================================================== --- thread.c (revision 12533) +++ thread.c (working copy) @@ -276,18 +276,28 @@ rb_thread_t *th = th_ptr; th->status = THREAD_KILLED; th->machine_stack_start = th->machine_stack_end = 0; +#ifdef __ia64 + th->machine_register_stack_start = th->machine_register_stack_end = 0; +#endif native_mutex_destroy(&th->interrupt_lock); native_thread_destroy(th); } static int -thread_start_func_2(rb_thread_t *th, VALUE *stack_start) +thread_start_func_2(rb_thread_t *th, VALUE *stack_start +#ifdef __ia64 + , VALUE *register_stack_start +#endif +) { int state; VALUE args = th->first_args; rb_proc_t *proc; rb_thread_t *join_th; th->machine_stack_start = stack_start; +#ifdef __ia64 + th->machine_register_stack_start = register_stack_start; +#endif th->thgroup = th->vm->thgroup_default; thread_debug("thread start: %p\n", th); @@ -1822,6 +1832,9 @@ rb_gc_save_machine_context(rb_thread_t *th) { rb_gc_set_stack_end(&th->machine_stack_end); +#ifdef __ia64 + th->machine_register_stack_end = rb_ia64_bsp(); +#endif setjmp(th->machine_regs); } Index: gc.c =================================================================== --- gc.c (revision 12533) +++ gc.c (working copy) @@ -540,7 +540,12 @@ return (VALUE)data; } +#ifdef __ia64 +#define SET_STACK_END (rb_gc_set_stack_end(&th->machine_stack_end), th->machine_register_stack_end = rb_ia64_bsp()) +#else #define SET_STACK_END rb_gc_set_stack_end(&th->machine_stack_end) +#endif + #define STACK_START (th->machine_stack_start) #define STACK_END (th->machine_stack_end) @@ -1384,10 +1389,10 @@ else rb_gc_mark_locations(th->machine_stack_start, th->machine_stack_end + 1); #endif -#ifdef __ia64__ +#ifdef __ia64 /* mark backing store (flushed register stack) */ /* the basic idea from guile GC code */ - rb_gc_mark_locations(rb_gc_register_stack_start, (VALUE*)rb_ia64_bsp()); + rb_gc_mark_locations(th->machine_register_stack_start, th->machine_register_stack_end); #endif #if defined(__human68k__) || defined(__mc68000__) rb_gc_mark_locations((VALUE*)((char*)STACK_END + 2), @@ -1441,6 +1446,9 @@ rb_gc_mark_locations(th->machine_stack_end, th->machine_stack_start); } #endif +#ifdef __ia64 + rb_gc_mark_locations(th->machine_register_stack_start, th->machine_register_stack_end); +#endif } Index: yarvcore.c =================================================================== --- yarvcore.c (revision 12533) +++ yarvcore.c (working copy) @@ -395,6 +395,9 @@ VALUE insns_name_array(void); extern VALUE *rb_gc_stack_start; +#ifdef __ia64 +extern VALUE *rb_gc_register_stack_start; +#endif static VALUE sdr(void) @@ -542,12 +545,13 @@ { rb_vm_t *vm = ruby_current_vm; rb_thread_t *th = GET_THREAD(); + volatile VALUE th_self; /* create vm object */ vm->self = Data_Wrap_Struct(rb_cVM, vm_mark, vm_free, vm); /* create main thread */ - th->self = Data_Wrap_Struct(rb_cThread, thread_mark, thread_free, th); + th_self = th->self = Data_Wrap_Struct(rb_cThread, thread_mark, thread_free, th); vm->main_thread = th; vm->running_thread = th; @@ -557,7 +561,7 @@ rb_thread_set_current(th); vm->living_threads = st_init_numtable(); - st_insert(vm->living_threads, th->self, (st_data_t) th->thread_id); + st_insert(vm->living_threads, th_self, (st_data_t) th->thread_id); } yarv_init_redefined_flag(); } @@ -575,6 +579,9 @@ th_init2(th); th->vm = vm; th->machine_stack_start = rb_gc_stack_start; +#ifdef __ia64 + th->machine_register_stack_start = rb_gc_register_stack_start; +#endif rb_thread_set_current_raw(th); } Index: yarvcore.h =================================================================== --- yarvcore.h (revision 12533) +++ yarvcore.h (working copy) @@ -486,6 +486,10 @@ /* for GC */ VALUE *machine_stack_start; VALUE *machine_stack_end; +#ifdef __ia64 + VALUE *machine_register_stack_start; + VALUE *machine_register_stack_end; +#endif jmp_buf machine_regs; int mark_stack_len; Index: thread_pthread.ci =================================================================== --- thread_pthread.ci (revision 12533) +++ thread_pthread.ci (working copy) @@ -86,7 +86,11 @@ posix_signal(SIGVTALRM, null_func); } -NOINLINE(static int thread_start_func_2(rb_thread_t *th, VALUE *stack_start)); +NOINLINE(static int thread_start_func_2(rb_thread_t *th, VALUE *stack_start +#ifdef __ia64 + , VALUE *register_stack_start +#endif +)); static void native_thread_destroy(rb_thread_t *th) @@ -107,7 +111,7 @@ VALUE stack_start; /* run */ - thread_start_func_2(th, &stack_start); + thread_start_func_2(th, &stack_start, rb_ia64_bsp()); } #if USE_THREAD_CACHE if (1) { Index: cont.c =================================================================== --- cont.c (revision 12533) +++ cont.c (working copy) @@ -22,6 +22,11 @@ VALUE *vm_stack; VALUE *machine_stack; VALUE *machine_stack_src; +#ifdef __ia64 + VALUE *machine_register_stack; + VALUE *machine_register_stack_src; + int machine_register_stack_size; +#endif rb_thread_t saved_thread; rb_jmpbuf_t jmpbuf; int machine_stack_size; @@ -59,6 +64,12 @@ rb_gc_mark_locations(cont->machine_stack, cont->machine_stack + cont->machine_stack_size); } +#ifdef __ia64 + if (cont->machine_register_stack) { + rb_gc_mark_locations(cont->machine_register_stack, + cont->machine_register_stack + cont->machine_register_stack_size); + } +#endif } MARK_REPORT_LEAVE("cont"); } @@ -71,6 +82,9 @@ rb_context_t *cont = ptr; FREE_UNLESS_NULL(cont->saved_thread.stack); FREE_UNLESS_NULL(cont->machine_stack); +#ifdef __ia64 + FREE_UNLESS_NULL(cont->machine_register_stack); +#endif FREE_UNLESS_NULL(cont->vm_stack); ruby_xfree(ptr); } @@ -83,6 +97,10 @@ int size; rb_gc_set_stack_end(&th->machine_stack_end); +#ifdef __ia64 + th->machine_register_stack_end = rb_ia64_bsp(); +#endif + if (th->machine_stack_start > th->machine_stack_end) { size = cont->machine_stack_size = th->machine_stack_start - th->machine_stack_end; cont->machine_stack_src = th->machine_stack_end; @@ -100,6 +118,20 @@ } MEMCPY(cont->machine_stack, cont->machine_stack_src, VALUE, size); + +#ifdef __ia64 + rb_ia64_flushrs(); + size = cont->machine_register_stack_size = th->machine_register_stack_end - th->machine_register_stack_start; + cont->machine_register_stack_src = th->machine_register_stack_start; + if (cont->machine_register_stack) { + REALLOC_N(cont->machine_register_stack, VALUE, size); + } + else { + cont->machine_register_stack = ALLOC_N(VALUE, size); + } + + MEMCPY(cont->machine_register_stack, cont->machine_register_stack_src, VALUE, size); +#endif } static rb_context_t * @@ -132,9 +164,11 @@ { rb_context_t *cont; rb_thread_t *th; + volatile VALUE contval; th_stack_to_heap(GET_THREAD()); cont = cont_new(rb_cCont); + contval = cont->self; th = &cont->saved_thread; cont->vm_stack = ALLOC_N(VALUE, th->stack_size); @@ -203,12 +237,51 @@ VALUE, cont->machine_stack_size); } +#ifdef __ia64 + if (cont->machine_register_stack_src) { + MEMCPY(cont->machine_register_stack_src, cont->machine_register_stack, + VALUE, cont->machine_register_stack_size); + } +#endif + ruby_longjmp(cont->jmpbuf, 1); } NORETURN(NOINLINE(static void cont_restore_0(rb_context_t *, VALUE *))); +#ifdef __ia64 +#define C(a) rse_##a##0, rse_##a##1, rse_##a##2, rse_##a##3, rse_##a##4 +#define E(a) rse_##a##0= rse_##a##1= rse_##a##2= rse_##a##3= rse_##a##4 +static volatile int C(a), C(b), C(c), C(d), C(e); +static volatile int C(f), C(g), C(h), C(i), C(j); +static volatile int C(k), C(l), C(m), C(n), C(o); +static volatile int C(p), C(q), C(r), C(s), C(t); +int rb_dummy_false = 0; +NORETURN(NOINLINE(static void register_stack_extend(rb_context_t *, VALUE *))); static void +register_stack_extend(rb_context_t *cont, VALUE *curr_bsp) +{ + if (rb_dummy_false) { + /* use registers as much as possible */ + E(a) = E(b) = E(c) = E(d) = E(e) = + E(f) = E(g) = E(h) = E(i) = E(j) = + E(k) = E(l) = E(m) = E(n) = E(o) = + E(p) = E(q) = E(r) = E(s) = E(t) = 0; + E(a) = E(b) = E(c) = E(d) = E(e) = + E(f) = E(g) = E(h) = E(i) = E(j) = + E(k) = E(l) = E(m) = E(n) = E(o) = + E(p) = E(q) = E(r) = E(s) = E(t) = 0; + } + if (curr_bsp < cont->machine_register_stack_src+cont->machine_register_stack_size) { + register_stack_extend(cont, (VALUE*)rb_ia64_bsp()); + } + cont_restore_1(cont); +} +#undef C +#undef E +#endif + +static void cont_restore_0(rb_context_t *cont, VALUE *addr_in_prev_frame) { if (cont->machine_stack_src) { @@ -238,7 +311,11 @@ } #endif } +#ifdef __ia64 + register_stack_extend(cont, (VALUE*)rb_ia64_bsp()); +#else cont_restore_1(cont); +#endif } /* -- [田中 哲][たなか あきら][Tanaka Akira]