12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124 |
- diff --git a/eval.c b/eval.c
- index 4098b83..c70f270 100644
- --- a/eval.c
- +++ b/eval.c
- @@ -73,6 +73,7 @@ char *strrchr _((const char*,const char));
- #endif
-
- #include <time.h>
- +#include <sys/mman.h>
-
- #ifdef __BEOS__
- #include <net/socket.h>
- @@ -1025,7 +1026,7 @@ static struct tag *prot_tag;
- _tag.blkid = 0; \
- prot_tag = &_tag
-
- -#define PROT_NONE Qfalse /* 0 */
- +#define PROT_EMPTY Qfalse /* 0 */
- #define PROT_THREAD Qtrue /* 2 */
- #define PROT_FUNC INT2FIX(0) /* 1 */
- #define PROT_LOOP INT2FIX(1) /* 3 */
- @@ -1236,7 +1237,7 @@ error_print()
-
- if (NIL_P(ruby_errinfo)) return;
-
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- if (EXEC_TAG() == 0) {
- errat = get_backtrace(ruby_errinfo);
- }
- @@ -1396,7 +1397,7 @@ ruby_init()
- /* default visibility is private at toplevel */
- SCOPE_SET(SCOPE_PRIVATE);
-
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- if ((state = EXEC_TAG()) == 0) {
- rb_call_inits();
- ruby_class = rb_cObject;
- @@ -1530,7 +1531,7 @@ ruby_options(argc, argv)
- int state;
-
- Init_stack((void*)&state);
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- if ((state = EXEC_TAG()) == 0) {
- ruby_process_options(argc, argv);
- }
- @@ -1547,7 +1548,7 @@ void rb_exec_end_proc _((void));
- static void
- ruby_finalize_0()
- {
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- if (EXEC_TAG() == 0) {
- rb_trap_exit();
- }
- @@ -1585,7 +1586,7 @@ ruby_cleanup(ex)
- Init_stack((void *)&state);
- ruby_finalize_0();
- errs[0] = ruby_errinfo;
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- PUSH_ITER(ITER_NOT);
- if ((state = EXEC_TAG()) == 0) {
- rb_thread_cleanup();
- @@ -1636,7 +1637,7 @@ ruby_exec_internal()
- {
- int state;
-
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- PUSH_ITER(ITER_NOT);
- /* default visibility is private at toplevel */
- SCOPE_SET(SCOPE_PRIVATE);
- @@ -1858,7 +1859,7 @@ rb_eval_cmd(cmd, arg, level)
- }
- if (TYPE(cmd) != T_STRING) {
- PUSH_ITER(ITER_NOT);
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- ruby_safe_level = level;
- if ((state = EXEC_TAG()) == 0) {
- val = rb_funcall2(cmd, rb_intern("call"), RARRAY(arg)->len, RARRAY(arg)->ptr);
- @@ -1880,7 +1881,7 @@ rb_eval_cmd(cmd, arg, level)
-
- ruby_safe_level = level;
-
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- if ((state = EXEC_TAG()) == 0) {
- val = eval(ruby_top_self, cmd, Qnil, 0, 0);
- }
- @@ -2387,7 +2388,7 @@ is_defined(self, node, buf)
- val = self;
- if (node->nd_recv == (NODE *)1) goto check_bound;
- case NODE_CALL:
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- if ((state = EXEC_TAG()) == 0) {
- val = rb_eval(self, node->nd_recv);
- }
- @@ -2489,7 +2490,7 @@ is_defined(self, node, buf)
- break;
-
- case NODE_COLON2:
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- if ((state = EXEC_TAG()) == 0) {
- val = rb_eval(self, node->nd_head);
- }
- @@ -2538,7 +2539,7 @@ is_defined(self, node, buf)
- goto again;
-
- default:
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- if ((state = EXEC_TAG()) == 0) {
- rb_eval(self, node);
- }
- @@ -2742,7 +2743,7 @@ call_trace_func(event, node, self, id, klass)
- klass = rb_iv_get(klass, "__attached__");
- }
- }
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- raised = rb_thread_reset_raised(th);
- if ((state = EXEC_TAG()) == 0) {
- srcfile = rb_str_new2(ruby_sourcefile?ruby_sourcefile:"(ruby)");
- @@ -3302,7 +3303,7 @@ rb_eval(self, n)
- volatile VALUE e_info = ruby_errinfo;
- volatile int rescuing = 0;
-
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- if ((state = EXEC_TAG()) == 0) {
- retry_entry:
- result = rb_eval(self, node->nd_head);
- @@ -3351,7 +3352,7 @@ rb_eval(self, n)
- break;
-
- case NODE_ENSURE:
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- if ((state = EXEC_TAG()) == 0) {
- result = rb_eval(self, node->nd_head);
- }
- @@ -3569,7 +3570,7 @@ rb_eval(self, n)
- ruby_frame = &frame;
-
- PUSH_SCOPE();
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- if (node->nd_rval) {
- saved_cref = ruby_cref;
- ruby_cref = (NODE*)node->nd_rval;
- @@ -4195,7 +4196,7 @@ module_setup(module, n)
- }
-
- PUSH_CREF(module);
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- if ((state = EXEC_TAG()) == 0) {
- EXEC_EVENT_HOOK(RUBY_EVENT_CLASS, n, ruby_cbase,
- ruby_frame->last_func, ruby_frame->last_class);
- @@ -4602,7 +4603,7 @@ rb_longjmp(tag, mesg)
- VALUE e = ruby_errinfo;
- int status;
-
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- if ((status = EXEC_TAG()) == 0) {
- StringValue(e);
- warn_printf("Exception `%s' at %s:%d - %s\n",
- @@ -4974,7 +4975,7 @@ rb_yield_0(val, self, klass, flags, avalue)
- node = block->body;
-
- if (block->var) {
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- if ((state = EXEC_TAG()) == 0) {
- if (block->var == (NODE*)1) { /* no parameter || */
- if (lambda && RARRAY(val)->len != 0) {
- @@ -5032,7 +5033,7 @@ rb_yield_0(val, self, klass, flags, avalue)
- ruby_current_node = node;
-
- PUSH_ITER(block->iter);
- - PUSH_TAG(lambda ? PROT_NONE : PROT_YIELD);
- + PUSH_TAG(lambda ? PROT_EMPTY : PROT_YIELD);
- if ((state = EXEC_TAG()) == 0) {
- redo:
- if (nd_type(node) == NODE_CFUNC || nd_type(node) == NODE_IFUNC) {
- @@ -5430,7 +5431,7 @@ rb_rescue2(b_proc, data1, r_proc, data2, va_alist)
- VALUE eclass;
- va_list args;
-
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- switch (state = EXEC_TAG()) {
- case TAG_RETRY:
- if (!handle) break;
- @@ -5488,7 +5489,7 @@ rb_protect(proc, data, state)
- VALUE result = Qnil; /* OK */
- int status;
-
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- cont_protect = (VALUE)rb_node_newnode(NODE_MEMO, cont_protect, 0, 0);
- if ((status = EXEC_TAG()) == 0) {
- result = (*proc)(data);
- @@ -5516,7 +5517,7 @@ rb_ensure(b_proc, data1, e_proc, data2)
- volatile VALUE result = Qnil;
- VALUE retval;
-
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- if ((state = EXEC_TAG()) == 0) {
- result = (*b_proc)(data1);
- }
- @@ -5543,7 +5544,7 @@ rb_with_disable_interrupt(proc, data)
- int thr_critical = rb_thread_critical;
-
- rb_thread_critical = Qtrue;
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- if ((status = EXEC_TAG()) == 0) {
- result = (*proc)(data);
- }
- @@ -6230,7 +6231,7 @@ rb_funcall_rescue(recv, mid, n, va_alist)
-
- va_init_list(ar, n);
-
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- if ((status = EXEC_TAG()) == 0) {
- result = vafuncall(recv, mid, n, &ar);
- }
- @@ -6499,7 +6500,7 @@ eval(self, src, scope, file, line)
- if (TYPE(ruby_class) == T_ICLASS) {
- ruby_class = RBASIC(ruby_class)->klass;
- }
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- if ((state = EXEC_TAG()) == 0) {
- NODE *node;
-
- @@ -6658,7 +6659,7 @@ exec_under(func, under, cbase, args)
-
- mode = scope_vmode;
- SCOPE_SET(SCOPE_PUBLIC);
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- if ((state = EXEC_TAG()) == 0) {
- val = (*func)(args);
- }
- @@ -6889,7 +6890,7 @@ rb_load(fname, wrap)
- PUSH_SCOPE();
- /* default visibility is private at loading toplevel */
- SCOPE_SET(SCOPE_PRIVATE);
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- state = EXEC_TAG();
- last_func = ruby_frame->last_func;
- last_node = ruby_current_node;
- @@ -6948,7 +6949,7 @@ rb_load_protect(fname, wrap, state)
- {
- int status;
-
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- if ((status = EXEC_TAG()) == 0) {
- rb_load(fname, wrap);
- }
- @@ -7269,7 +7270,7 @@ rb_require_safe(fname, safe)
- saved.node = ruby_current_node;
- saved.func = ruby_frame->last_func;
- saved.safe = ruby_safe_level;
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- if ((state = EXEC_TAG()) == 0) {
- VALUE feature, path;
- long handle;
- @@ -7977,7 +7978,7 @@ rb_exec_end_proc()
- tmp_end_procs = link = ephemeral_end_procs;
- ephemeral_end_procs = 0;
- while (link) {
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- if ((status = EXEC_TAG()) == 0) {
- ruby_safe_level = link->safe;
- (*link->func)(link->data);
- @@ -7995,7 +7996,7 @@ rb_exec_end_proc()
- tmp_end_procs = link = end_procs;
- end_procs = 0;
- while (link) {
- - PUSH_TAG(PROT_NONE);
- + PUSH_TAG(PROT_EMPTY);
- if ((status = EXEC_TAG()) == 0) {
- ruby_safe_level = link->safe;
- (*link->func)(link->data);
- @@ -8654,7 +8655,7 @@ proc_invoke(proc, args, self, klass)
- ruby_block = &_block;
- PUSH_ITER(ITER_CUR);
- ruby_frame->iter = ITER_CUR;
- - PUSH_TAG(pcall ? PROT_LAMBDA : PROT_NONE);
- + PUSH_TAG(pcall ? PROT_LAMBDA : PROT_EMPTY);
- state = EXEC_TAG();
- if (state == 0) {
- proc_set_safe_level(proc);
- @@ -9896,6 +9897,7 @@ win32_set_exception_list(p)
- int rb_thread_pending = 0;
-
- VALUE rb_cThread;
- +static unsigned int rb_thread_stack_size;
-
- extern VALUE rb_last_status;
-
- @@ -10123,12 +10125,20 @@ thread_mark(th)
- rb_gc_mark(th->thread);
- if (th->join) rb_gc_mark(th->join->thread);
-
- - rb_gc_mark(th->klass);
- - rb_gc_mark(th->wrapper);
- - rb_gc_mark((VALUE)th->cref);
- + if (curr_thread == th) {
- + rb_gc_mark(ruby_class);
- + rb_gc_mark(ruby_wrapper);
- + rb_gc_mark((VALUE)ruby_cref);
- + rb_gc_mark((VALUE)ruby_scope);
- + rb_gc_mark((VALUE)ruby_dyna_vars);
- + } else {
- + rb_gc_mark(th->klass);
- + rb_gc_mark(th->wrapper);
- + rb_gc_mark((VALUE)th->cref);
- + rb_gc_mark((VALUE)th->scope);
- + rb_gc_mark((VALUE)th->dyna_vars);
- + }
-
- - rb_gc_mark((VALUE)th->scope);
- - rb_gc_mark((VALUE)th->dyna_vars);
- rb_gc_mark(th->errinfo);
- rb_gc_mark(th->last_status);
- rb_gc_mark(th->last_line);
- @@ -10138,11 +10148,11 @@ thread_mark(th)
- rb_gc_mark_maybe(th->sandbox);
-
- /* mark data in copied stack */
- - if (th == curr_thread) return;
- + if (th == main_thread) return;
- if (th->status == THREAD_KILLED) return;
- if (th->stk_len == 0) return; /* stack not active, no need to mark. */
- - if (th->stk_ptr) {
- - rb_gc_mark_locations(th->stk_ptr, th->stk_ptr+th->stk_len);
- + if (th->stk_ptr && th != curr_thread) {
- + rb_gc_mark_locations(th->stk_pos, th->stk_base);
- #if defined(THINK_C) || defined(__human68k__)
- rb_gc_mark_locations(th->stk_ptr+2, th->stk_ptr+th->stk_len+2);
- #endif
- @@ -10152,24 +10162,30 @@ thread_mark(th)
- }
- #endif
- }
- - frame = th->frame;
- +
- + if (curr_thread == th)
- + frame = ruby_frame;
- + else
- + frame = th->frame;
- +
- while (frame && frame != top_frame) {
- - frame = ADJ(frame);
- rb_gc_mark_frame(frame);
- if (frame->tmp) {
- struct FRAME *tmp = frame->tmp;
- -
- while (tmp && tmp != top_frame) {
- - tmp = ADJ(tmp);
- rb_gc_mark_frame(tmp);
- tmp = tmp->prev;
- }
- }
- frame = frame->prev;
- }
- - block = th->block;
- +
- + if (curr_thread == th)
- + block = ruby_block;
- + else
- + block = th->block;
- +
- while (block) {
- - block = ADJ(block);
- rb_gc_mark_frame(&block->frame);
- block = block->prev;
- }
- @@ -10232,7 +10248,7 @@ static inline void
- stack_free(th)
- rb_thread_t th;
- {
- - if (th->stk_ptr) free(th->stk_ptr);
- + if (th->stk_ptr) munmap(th->stk_ptr, th->stk_size);
- th->stk_ptr = 0;
- #ifdef __ia64
- if (th->bstr_ptr) free(th->bstr_ptr);
- @@ -10293,35 +10309,8 @@ rb_thread_save_context(th)
- static VALUE tval;
-
- len = ruby_stack_length(&pos);
- - th->stk_len = 0;
- - th->stk_pos = pos;
- - if (len > th->stk_max) {
- - VALUE *ptr = realloc(th->stk_ptr, sizeof(VALUE) * len);
- - if (!ptr) rb_memerror();
- - th->stk_ptr = ptr;
- - th->stk_max = len;
- - }
- th->stk_len = len;
- - FLUSH_REGISTER_WINDOWS;
- - MEMCPY(th->stk_ptr, th->stk_pos, VALUE, th->stk_len);
- -#ifdef __ia64
- - th->bstr_pos = rb_gc_register_stack_start;
- - len = (VALUE*)rb_ia64_bsp() - th->bstr_pos;
- - th->bstr_len = 0;
- - if (len > th->bstr_max) {
- - VALUE *ptr = realloc(th->bstr_ptr, sizeof(VALUE) * len);
- - if (!ptr) rb_memerror();
- - th->bstr_ptr = ptr;
- - th->bstr_max = len;
- - }
- - th->bstr_len = len;
- - rb_ia64_flushrs();
- - MEMCPY(th->bstr_ptr, th->bstr_pos, VALUE, th->bstr_len);
- -#endif
- -#ifdef SAVE_WIN32_EXCEPTION_LIST
- - th->win32_exception_list = win32_get_exception_list();
- -#endif
- -
- + th->stk_pos = pos;
- th->frame = ruby_frame;
- th->scope = ruby_scope;
- ruby_scope->flags |= SCOPE_DONT_RECYCLE;
- @@ -10431,11 +10420,6 @@ rb_thread_restore_context_0(rb_thread_t th, int exit)
- #endif
- tmp = th;
- ex = exit;
- - FLUSH_REGISTER_WINDOWS;
- - MEMCPY(tmp->stk_pos, tmp->stk_ptr, VALUE, tmp->stk_len);
- -#ifdef __ia64
- - MEMCPY(tmp->bstr_pos, tmp->bstr_ptr, VALUE, tmp->bstr_len);
- -#endif
-
- tval = rb_lastline_get();
- rb_lastline_set(tmp->last_line);
- @@ -10526,8 +10510,8 @@ rb_thread_restore_context(th, exit)
- rb_thread_t th;
- int exit;
- {
- - if (!th->stk_ptr) rb_bug("unsaved context");
- - stack_extend(th, exit);
- + if (!th->stk_ptr && th != main_thread) rb_bug("unsaved context");
- + rb_thread_restore_context_0(th, exit);
- }
-
- static void
- @@ -10546,7 +10530,6 @@ rb_thread_die(th)
- {
- th->thgroup = 0;
- th->status = THREAD_KILLED;
- - stack_free(th);
- }
-
- static void
- @@ -11822,6 +11805,7 @@ rb_thread_group(thread)
- \
- th->stk_ptr = 0;\
- th->stk_len = 0;\
- + th->stk_size = 0;\
- th->stk_max = 0;\
- th->wait_for = 0;\
- IA64_INIT(th->bstr_ptr = 0);\
- @@ -11869,6 +11853,48 @@ rb_thread_alloc(klass)
- THREAD_ALLOC(th);
- th->thread = Data_Wrap_Struct(klass, thread_mark, thread_free, th);
-
- + /* if main_thread != NULL, then this is NOT the main thread, so
- + * we create a heap-stack
- + */
- + if (main_thread) {
- + /* Allocate stack, don't forget to add 1 extra word because of the MATH below */
- + unsigned int pagesize = getpagesize();
- + unsigned int total_size = rb_thread_stack_size + pagesize + sizeof(int);
- + void *stack_area = NULL;
- +
- + stack_area = mmap(NULL, total_size, PROT_READ | PROT_WRITE | PROT_EXEC,
- + MAP_PRIVATE | MAP_ANON, -1, 0);
- +
- + if (stack_area == MAP_FAILED) {
- + fprintf(stderr, "Thread stack allocation failed!\n");
- + rb_memerror();
- + }
- +
- + th->stk_ptr = th->stk_pos = stack_area;
- + th->stk_size = total_size;
- +
- + if (mprotect(th->stk_ptr, pagesize, PROT_NONE) == -1) {
- + fprintf(stderr, "Failed to create thread guard region: %s\n", strerror(errno));
- + rb_memerror();
- + }
- +
- + th->guard = th->stk_ptr + (pagesize/sizeof(VALUE *));
- +
- + /* point stk_base at the top of the stack */
- + /* ASSUMPTIONS:
- + * 1.) The address returned by malloc is "suitably aligned" for anything on this system
- + * 2.) Adding a value that is "aligned" for this platform should not unalign the address
- + * returned from malloc.
- + * 3.) Don't push anything on to the stack, otherwise it'll get unaligned.
- + * 4.) x86_64 ABI says aligned AFTER arguments have been pushed. You *must* then do a call[lq]
- + * or push[lq] something else on to the stack if you inted to do a ret.
- + */
- + th->stk_base = th->stk_ptr + ((total_size - sizeof(int))/sizeof(VALUE *));
- + th->stk_len = rb_thread_stack_size;
- + } else {
- + th->stk_ptr = th->stk_pos = rb_gc_stack_start;
- + }
- +
- for (vars = th->dyna_vars; vars; vars = vars->next) {
- if (FL_TEST(vars, DVAR_DONT_RECYCLE)) break;
- FL_SET(vars, DVAR_DONT_RECYCLE);
- @@ -12014,17 +12040,22 @@ rb_thread_cancel_timer()
- }
- #endif
-
- +struct thread_start_args {
- + VALUE (*fn)();
- + void *arg;
- + rb_thread_t th;
- +} new_th;
- +
- +static VALUE
- +rb_thread_start_2();
- +
- static VALUE
- rb_thread_start_0(fn, arg, th)
- VALUE (*fn)();
- void *arg;
- rb_thread_t th;
- {
- - volatile rb_thread_t th_save = th;
- volatile VALUE thread = th->thread;
- - struct BLOCK *volatile saved_block = 0;
- - enum rb_thread_status status;
- - int state;
-
- if (OBJ_FROZEN(curr_thread->thgroup)) {
- rb_raise(rb_eThreadError,
- @@ -12054,16 +12085,41 @@ rb_thread_start_0(fn, arg, th)
- return thread;
- }
-
- - if (ruby_block) { /* should nail down higher blocks */
- - struct BLOCK dummy;
- + new_th.fn = fn;
- + new_th.arg = arg;
- + new_th.th = th;
- +
- +#if defined(__i386__)
- + __asm__ __volatile__ ("movl %0, %%esp\n\t"
- + "calll *%1\n"
- + :: "r" (th->stk_base),
- + "r" (rb_thread_start_2));
- +#elif defined(__x86_64__)
- + __asm__ __volatile__ ("movq %0, %%rsp\n\t"
- + "callq *%1\n"
- + :: "r" (th->stk_base),
- + "r" (rb_thread_start_2));
- +#else
- + #error unsupported architecture!
- +#endif
- + /* NOTREACHED */
- + return 0;
- +}
-
- - dummy.prev = ruby_block;
- - blk_copy_prev(&dummy);
- - saved_block = ruby_block = dummy.prev;
- - }
- - scope_dup(ruby_scope);
- +static VALUE
- +rb_thread_start_2()
- +{
- + volatile rb_thread_t th = new_th.th;
- + volatile rb_thread_t th_save = th;
- + volatile VALUE thread = th->thread;
- + struct BLOCK *volatile saved_block = 0;
- + enum rb_thread_status status;
- + int state;
- + struct tag *tag;
- + struct RVarmap *vars;
- + struct FRAME dummy_frame;
-
- - if (!th->next) {
- + if (!th->next) {
- /* merge in thread list */
- th->prev = curr_thread;
- curr_thread->next->prev = th;
- @@ -12071,13 +12127,27 @@ rb_thread_start_0(fn, arg, th)
- curr_thread->next = th;
- th->priority = curr_thread->priority;
- th->thgroup = curr_thread->thgroup;
- + }
- + curr_thread = th;
- +
- + dummy_frame = *ruby_frame;
- + dummy_frame.prev = top_frame;
- + ruby_frame = &dummy_frame;
- +
- + if (ruby_block) { /* should nail down higher blocks */
- + struct BLOCK dummy;
- +
- + dummy.prev = ruby_block;
- + blk_copy_prev(&dummy);
- + saved_block = ruby_block = dummy.prev;
- }
-
- + scope_dup(ruby_scope);
- +
- PUSH_TAG(PROT_THREAD);
- if ((state = EXEC_TAG()) == 0) {
- if (THREAD_SAVE_CONTEXT(th) == 0) {
- - curr_thread = th;
- - th->result = (*fn)(arg, th);
- + th->result = (*new_th.fn)(new_th.arg, th);
- }
- th = th_save;
- }
- @@ -12414,6 +12484,43 @@ rb_thread_cleanup()
- END_FOREACH_FROM(curr, th);
- }
-
- +/*
- + * call-seq:
- + * Thread.stack_size => fixnum
- + *
- + * Returns the thread stack size in bytes
- + */
- +static VALUE
- +rb_thread_stacksize_get()
- +{
- + return INT2FIX(rb_thread_stack_size);
- +}
- +
- +/*
- + * call-seq:
- + * Thread.stack_size= fixnum => Qnil
- + *
- + * Sets the global thread stacksize and returns Qnil.
- + */
- +static VALUE
- +rb_thread_stacksize_set(obj, val)
- + VALUE obj;
- + VALUE val;
- +{
- +
- + unsigned int size = FIX2UINT(val);
- +
- + /* 16byte alignment works for both x86 and x86_64 */
- + if (size & (~0xf)) {
- + size += 0x10;
- + size = size & (~0xf);
- + }
- +
- + rb_thread_stack_size = size;
- +
- + return Qnil;
- +}
- +
- int rb_thread_critical;
-
-
- @@ -13167,6 +13274,8 @@ Init_Thread()
- {
- VALUE cThGroup;
-
- + rb_thread_stack_size = (1024 * 1024);
- +
- rb_eThreadError = rb_define_class("ThreadError", rb_eStandardError);
- rb_cThread = rb_define_class("Thread", rb_cObject);
- rb_undef_alloc_func(rb_cThread);
- @@ -13190,6 +13299,9 @@ Init_Thread()
- 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_singleton_method(rb_cThread, "stack_size", rb_thread_stacksize_get, 0);
- + rb_define_singleton_method(rb_cThread, "stack_size=", rb_thread_stacksize_set, 1);
- +
- rb_define_method(rb_cThread, "run", rb_thread_run, 0);
- rb_define_method(rb_cThread, "wakeup", rb_thread_wakeup, 0);
- rb_define_method(rb_cThread, "kill", rb_thread_kill, 0);
- diff --git a/gc.c b/gc.c
- index 318e24c..0746834 100644
- --- a/gc.c
- +++ b/gc.c
- @@ -466,12 +466,12 @@ stack_end_address(VALUE **stack_end_p)
- # define STACK_END (stack_end)
- #endif
- #if STACK_GROW_DIRECTION < 0
- -# define STACK_LENGTH (rb_gc_stack_start - STACK_END)
- +# define STACK_LENGTH(start) ((start) - STACK_END)
- #elif STACK_GROW_DIRECTION > 0
- -# define STACK_LENGTH (STACK_END - rb_gc_stack_start + 1)
- +# define STACK_LENGTH(start) (STACK_END - (start) + 1)
- #else
- -# define STACK_LENGTH ((STACK_END < rb_gc_stack_start) ? rb_gc_stack_start - STACK_END\
- - : STACK_END - rb_gc_stack_start + 1)
- +# define STACK_LENGTH(start) ((STACK_END < (start)) ? (start) - STACK_END\
- + : STACK_END - (start) + 1)
- #endif
- #if STACK_GROW_DIRECTION > 0
- # define STACK_UPPER(x, a, b) a
- @@ -494,27 +494,36 @@ stack_grow_direction(addr)
-
- #define GC_WATER_MARK 512
-
- -#define CHECK_STACK(ret) do {\
- +#define CHECK_STACK(ret, start) do {\
- SET_STACK_END;\
- - (ret) = (STACK_LENGTH > STACK_LEVEL_MAX + GC_WATER_MARK);\
- + (ret) = (STACK_LENGTH(start) > STACK_LEVEL_MAX + GC_WATER_MARK);\
- } while (0)
-
- size_t
- ruby_stack_length(p)
- VALUE **p;
- {
- - SET_STACK_END;
- - if (p) *p = STACK_UPPER(STACK_END, rb_gc_stack_start, STACK_END);
- - return STACK_LENGTH;
- + SET_STACK_END;
- + VALUE *start;
- + if (rb_curr_thread == rb_main_thread) {
- + start = rb_gc_stack_start;
- + } else {
- + start = rb_curr_thread->stk_base;
- + }
- + if (p) *p = STACK_UPPER(STACK_END, start, STACK_END);
- + return STACK_LENGTH(start);
- }
-
- int
- ruby_stack_check()
- {
- - int ret;
- -
- - CHECK_STACK(ret);
- - return ret;
- + int ret;
- + if (rb_curr_thread == rb_main_thread) {
- + CHECK_STACK(ret, rb_gc_stack_start);
- + } else {
- + CHECK_STACK(ret, rb_curr_thread->stk_base);
- + }
- + return ret;
- }
-
- #define MARK_STACK_MAX 1024
- @@ -1404,10 +1413,13 @@ garbage_collect()
-
- init_mark_stack();
-
- - gc_mark((VALUE)ruby_current_node, 0);
- -
- /* mark frame stack */
- - for (frame = ruby_frame; frame; frame = frame->prev) {
- + if (rb_curr_thread == rb_main_thread)
- + frame = ruby_frame;
- + else
- + frame = rb_main_thread->frame;
- +
- + for (; frame; frame = frame->prev) {
- rb_gc_mark_frame(frame);
- if (frame->tmp) {
- struct FRAME *tmp = frame->tmp;
- @@ -1417,16 +1429,35 @@ garbage_collect()
- }
- }
- }
- - gc_mark((VALUE)ruby_scope, 0);
- - gc_mark((VALUE)ruby_dyna_vars, 0);
- +
- + if (rb_curr_thread == rb_main_thread) {
- + gc_mark((VALUE)ruby_current_node, 0);
- + gc_mark((VALUE)ruby_scope, 0);
- + gc_mark((VALUE)ruby_dyna_vars, 0);
- + } else {
- + gc_mark((VALUE)rb_main_thread->node, 0);
- + gc_mark((VALUE)rb_main_thread->scope, 0);
- + gc_mark((VALUE)rb_main_thread->dyna_vars, 0);
- +
- + /* scan the current thread's stack */
- + rb_gc_mark_locations((VALUE*)STACK_END, rb_curr_thread->stk_base);
- + }
- +
- if (finalizer_table) {
- - mark_tbl(finalizer_table, 0);
- + mark_tbl(finalizer_table, 0);
- }
-
- FLUSH_REGISTER_WINDOWS;
- /* This assumes that all registers are saved into the jmp_buf (and stack) */
- setjmp(save_regs_gc_mark);
- mark_locations_array((VALUE*)save_regs_gc_mark, sizeof(save_regs_gc_mark) / sizeof(VALUE *));
- +
- + /* If this is not the main thread, we need to scan the C stack, so
- + * set STACK_END to the end of the C stack.
- + */
- + if (rb_curr_thread != rb_main_thread)
- + STACK_END = rb_main_thread->stk_pos;
- +
- #if STACK_GROW_DIRECTION < 0
- rb_gc_mark_locations((VALUE*)STACK_END, rb_gc_stack_start);
- #elif STACK_GROW_DIRECTION > 0
- @@ -1446,6 +1477,7 @@ garbage_collect()
- rb_gc_mark_locations((VALUE*)((char*)STACK_END + 2),
- (VALUE*)((char*)rb_gc_stack_start + 2));
- #endif
- +
- rb_gc_mark_threads();
-
- /* mark protected global variables */
- diff --git a/lib/logger.rb b/lib/logger.rb
- index e9ab171..2564c33 100644
- --- a/lib/logger.rb
- +++ b/lib/logger.rb
- @@ -170,7 +170,7 @@ require 'monitor'
-
- class Logger
- VERSION = "1.2.6"
- - id, name, rev = %w$Id$
- + id, name, rev = %w$Id logger.rb 1234$
- ProgName = "#{name.chomp(",v")}/#{rev}"
-
- class Error < RuntimeError; end
- diff --git a/node.h b/node.h
- index 476a826..ecdc053 100644
- --- a/node.h
- +++ b/node.h
- @@ -411,8 +411,11 @@ struct rb_thread {
-
- size_t stk_len;
- size_t stk_max;
- + size_t stk_size;
- VALUE *stk_ptr;
- VALUE *stk_pos;
- + VALUE *stk_base;
- + VALUE *guard;
- #ifdef __ia64
- size_t bstr_len;
- size_t bstr_max;
- diff --git a/signal.c b/signal.c
- index b6cad9d..116ac05 100644
- --- a/signal.c
- +++ b/signal.c
- @@ -14,6 +14,7 @@
-
- #include "ruby.h"
- #include "rubysig.h"
- +#include "node.h"
- #include <signal.h>
- #include <stdio.h>
-
- @@ -425,15 +426,22 @@ typedef RETSIGTYPE (*sighandler_t)_((int));
- static sighandler_t
- ruby_signal(signum, handler)
- int signum;
- - sighandler_t handler;
- + void *handler;
- {
- struct sigaction sigact, old;
-
- rb_trap_accept_nativethreads[signum] = 0;
-
- - sigact.sa_handler = handler;
- + if (signum == SIGSEGV || signum == SIGBUS) {
- + sigact.sa_sigaction = handler;
- + sigact.sa_flags = (SA_ONSTACK | SA_RESETHAND | SA_SIGINFO);
- + } else {
- + sigact.sa_handler = handler;
- + sigact.sa_flags = 0;
- + }
- +
- sigemptyset(&sigact.sa_mask);
- - sigact.sa_flags = 0;
- +
- # ifdef SA_NOCLDWAIT
- if (signum == SIGCHLD && handler == SIG_IGN)
- sigact.sa_flags |= SA_NOCLDWAIT;
- @@ -596,7 +604,132 @@ sighandler(sig)
- }
- }
-
- +#include <stdio.h>
- +#ifdef HAVE_STDARG_PROTOTYPES
- +#include <stdarg.h>
- +#define va_init_list(a,b) va_start(a,b)
- +#else
- +#include <varargs.h>
- +#define va_init_list(a,b) va_start(a)
- +#endif
- +
- +void
- +#ifdef HAVE_STDARG_PROTOTYPES
- +sig_printf(const char *fmt, ...)
- +#else
- + sig_printf(fmt, va_alist)
- + const char *fmt;
- + va_dcl
- +#endif
- +{
- + char buf[BUFSIZ];
- + va_list args;
- + FILE *out = stderr;
- +
- + va_init_list(args, fmt);
- + vfprintf(out, fmt, args);
- + va_end(args);
- + fprintf(out, "\n");
- +}
- +
- +static void
- +dump_machine_state(uc)
- + ucontext_t *uc;
- +{
- + const char *dump64 =
- + " ----------------- Register state dump ----------------------\n"
- + "rax = 0x%.16x rbx = 0x%.16x rcx = 0x%.16x rdx = 0x%.16x\n"
- + "rdi = 0x%.16x rsi = 0x%.16x rbp = 0x%.16x rsp = 0x%.16x\n"
- + "r8 = 0x%.16x r9 = 0x%.16x r10 = 0x%.16x r11 = 0x%.16x\n"
- + "r12 = 0x%.16x r13 = 0x%.16x r14 = 0x%.16x r15 = 0x%.16x\n"
- + "rip = 0x%.16x rflags = 0x%.16x cs = 0x%.16x fs = 0x%.16x\n"
- + "gs = 0x%.16x";
- +
- + const char *dump32 =
- + " ----------------- Register state dump -------------------\n"
- + "eax = 0x%.8x ebx = 0x%.8x ecx = 0x%.8x edx = 0x%.8x\n"
- + "edi = 0x%.8x esi = 0x%.8x ebp = 0x%.8x esp = 0x%.8x\n"
- + "ss = 0x%.8x eflags = 0x%.8x eip = 0x%.8x cs = 0x%.8x\n"
- + "ds = 0x%.8x es = 0x%.8x fs = 0x%.8x gs = 0x%.8x\n";
- +
- +#if defined(__LP64__) && defined(__APPLE__)
- + sig_printf(dump64, uc->uc_mcontext->__ss.__rax, uc->uc_mcontext->__ss.__rbx,
- + uc->uc_mcontext->__ss.__rcx, uc->uc_mcontext->__ss.__rdx, uc->uc_mcontext->__ss.__rdi,
- + uc->uc_mcontext->__ss.__rsi, uc->uc_mcontext->__ss.__rbp, uc->uc_mcontext->__ss.__rsp,
- + uc->uc_mcontext->__ss.__r8, uc->uc_mcontext->__ss.__r9, uc->uc_mcontext->__ss.__r10,
- + uc->uc_mcontext->__ss.__r11, uc->uc_mcontext->__ss.__r12, uc->uc_mcontext->__ss.__r13,
- + uc->uc_mcontext->__ss.__r14, uc->uc_mcontext->__ss.__r15, uc->uc_mcontext->__ss.__rip,
- + uc->uc_mcontext->__ss.__rflags, uc->uc_mcontext->__ss.__cs, uc->uc_mcontext->__ss.__fs,
- + uc->uc_mcontext->__ss.__gs);
- +#elif !defined(__LP64__) && defined(__APPLE__)
- + sig_printf(dump32, uc->uc_mcontext->__ss.__eax, uc->uc_mcontext->__ss.__ebx,
- + uc->uc_mcontext->__ss.__ecx, uc->uc_mcontext->__ss.__edx,
- + uc->uc_mcontext->__ss.__edi, uc->uc_mcontext->__ss.__esi,
- + uc->uc_mcontext->__ss.__ebp, uc->uc_mcontext->__ss.__esp,
- + uc->uc_mcontext->__ss.__ss, uc->uc_mcontext->__ss.__eflags,
- + uc->uc_mcontext->__ss.__eip, uc->uc_mcontext->__ss.__cs,
- + uc->uc_mcontext->__ss.__ds, uc->uc_mcontext->__ss.__es,
- + uc->uc_mcontext->__ss.__fs, uc->uc_mcontext->__ss.__gs);
- +#elif defined(__i386__)
- + sig_printf(dump32, uc->uc_mcontext.gregs[REG_EAX], uc->uc_mcontext.gregs[REG_EBX],
- + uc->uc_mcontext.gregs[REG_ECX], uc->uc_mcontext.gregs[REG_EDX],
- + uc->uc_mcontext.gregs[REG_EDI], uc->uc_mcontext.gregs[REG_ESI],
- + uc->uc_mcontext.gregs[REG_EBP], uc->uc_mcontext.gregs[REG_ESP],
- + uc->uc_mcontext.gregs[REG_SS], uc->uc_mcontext.gregs[REG_EFL],
- + uc->uc_mcontext.gregs[REG_EIP], uc->uc_mcontext.gregs[REG_EIP],
- + uc->uc_mcontext.gregs[REG_DS], uc->uc_mcontext.gregs[REG_ES],
- + uc->uc_mcontext.gregs[REG_FS], uc->uc_mcontext.gregs[REG_FS]);
- +#elif defined(__x86_64__)
- + sig_printf(dump64, uc->uc_mcontext.gregs[REG_RAX], uc->uc_mcontext.gregs[REG_RBX],
- + uc->uc_mcontext.gregs[REG_RCX], uc->uc_mcontext.gregs[REG_RDX],
- + uc->uc_mcontext.gregs[REG_RDI], uc->uc_mcontext.gregs[REG_RSI],
- + uc->uc_mcontext.gregs[REG_RBP], uc->uc_mcontext.gregs[REG_RSP],
- + uc->uc_mcontext.gregs[REG_R8], uc->uc_mcontext.gregs[REG_R9],
- + uc->uc_mcontext.gregs[REG_R10], uc->uc_mcontext.gregs[REG_R11],
- + uc->uc_mcontext.gregs[REG_R12], uc->uc_mcontext.gregs[REG_R13],
- + uc->uc_mcontext.gregs[REG_R14], uc->uc_mcontext.gregs[REG_R15],
- + uc->uc_mcontext.gregs[REG_RIP], uc->uc_mcontext.gregs[REG_EFL],
- + uc->uc_mcontext.gregs[REG_CSGSFS]);
- +#else
- +#endif
- +}
- +
- +static int
- +check_guard(caddr_t fault_addr, rb_thread_t th) {
- + if(fault_addr <= (caddr_t)rb_curr_thread->guard &&
- + fault_addr >= (caddr_t)rb_curr_thread->stk_ptr) {
- + return 1;
- + }
- + return 0;
- +}
- +
- #ifdef SIGBUS
- +#ifdef POSIX_SIGNAL
- +static void sigbus _((int, siginfo_t*, void*));
- +static void
- +sigbus(sig, ip, context)
- + int sig;
- + siginfo_t *ip;
- + void *context;
- +{
- +#if defined(HAVE_NATIVETHREAD) && defined(HAVE_NATIVETHREAD_KILL)
- + if (!is_ruby_native_thread() && !rb_trap_accept_nativethreads[sig]) {
- + sigsend_to_ruby_thread(sig);
- + return;
- + }
- +#endif
- +
- + dump_machine_state(context);
- + if (check_guard((caddr_t)ip->si_addr, rb_curr_thread)) {
- + /* we hit the guard page, print out a warning to help app developers */
- + rb_bug("Thread stack overflow! Try increasing it!");
- + } else {
- + rb_bug("Bus Error");
- + }
- +}
- +
- +#else /* !defined(POSIX_SIGNAL) */
- +
- static RETSIGTYPE sigbus _((int));
- static RETSIGTYPE
- sigbus(sig)
- @@ -612,8 +745,36 @@ sigbus(sig)
- rb_bug("Bus Error");
- }
- #endif
- +#endif
- +
-
- #ifdef SIGSEGV
- +#ifdef POSIX_SIGNAL
- +static void sigsegv _((int, siginfo_t*, void*));
- +static void
- +sigsegv(sig, ip, context)
- + int sig;
- + siginfo_t *ip;
- + void *context;
- +{
- +#if defined(HAVE_NATIVETHREAD) && defined(HAVE_NATIVETHREAD_KILL)
- + if (!is_ruby_native_thread() && !rb_trap_accept_nativethreads[sig]) {
- + sigsend_to_ruby_thread(sig);
- + return;
- + }
- +#endif
- +
- + dump_machine_state(context);
- + if (check_guard((caddr_t)ip->si_addr, rb_curr_thread)) {
- + /* we hit the guard page, print out a warning to help app developers */
- + rb_bug("Thread stack overflow! Try increasing it!");
- + } else {
- + rb_bug("Segmentation fault");
- + }
- +}
- +
- +#else /* !defined(POSIX_SIGNAL) */
- +
- static RETSIGTYPE sigsegv _((int));
- static RETSIGTYPE
- sigsegv(sig)
- @@ -629,6 +790,7 @@ sigsegv(sig)
- rb_bug("Segmentation fault");
- }
- #endif
- +#endif
-
- #ifdef SIGPIPE
- static RETSIGTYPE sigpipe _((int));
- @@ -698,7 +860,8 @@ static VALUE
- trap(arg)
- struct trap_arg *arg;
- {
- - sighandler_t func, oldfunc;
- + sighandler_t oldfunc;
- + void *func;
- VALUE command, oldcmd;
- int sig = -1;
- char *s;
- @@ -945,6 +1108,20 @@ sig_list()
- }
-
- static void
- +create_sigstack()
- +{
- + stack_t ss;
- + ss.ss_size = SIGSTKSZ;
- + ss.ss_sp = malloc(ss.ss_size);
- + ss.ss_flags = 0;
- + if (sigaltstack(&ss, NULL) < 0) {
- + free(ss.ss_sp);
- + fprintf(stderr, "Couldn't create signal stack! Error %d: %s\n", errno, strerror(errno));
- + exit(1);
- + }
- +}
- +
- +static void
- install_sighandler(signum, handler)
- int signum;
- sighandler_t handler;
- @@ -953,7 +1130,7 @@ install_sighandler(signum, handler)
-
- old = ruby_signal(signum, handler);
- if (old != SIG_DFL) {
- - ruby_signal(signum, old);
- + ruby_signal(signum, old);
- }
- }
-
- @@ -1080,6 +1257,8 @@ Init_signal()
- rb_alias(rb_eSignal, rb_intern("signm"), rb_intern("message"));
- rb_define_method(rb_eInterrupt, "initialize", interrupt_init, 1);
-
- + create_sigstack();
- +
- install_sighandler(SIGINT, sighandler);
- #ifdef SIGHUP
- install_sighandler(SIGHUP, sighandler);
|