diff --git a/src/testsuite.in b/src/testsuite.in index dd991ceb46d739cce03705e950d1d632604c5919..cf1bc945f0eb4cb42bfec4a30db05571420bece8 100644 --- a/src/testsuite.in +++ b/src/testsuite.in @@ -5363,6 +5363,14 @@ void test() return Process.system (RUNPIKE +" testsuite_test.pike"); ]], 0) + test_eval_error([[ + Thread.thread_create(lambda(){ + // NB: It's currently not possible to inhibit the + // backtrace (without messing with the master). + error("Ignore the following line.\n"); + })->wait(); + ]]) + cond_end // thread_create cond([[0]], diff --git a/src/threads.c b/src/threads.c index fae2e9a5cc054d3bcb0a54ffb008a755a3a10acd..e2a528a158d48ec627f409f3142d370764626cd9 100644 --- a/src/threads.c +++ b/src/threads.c @@ -1784,20 +1784,26 @@ TH_RETURN_TYPE new_thread_func(void *data) if(SETJMP(back)) { - if(throw_severity <= THROW_ERROR) + if(throw_severity <= THROW_ERROR) { + if (thread_state->thread_obj) { + /* Copy the thrown exit value to the thread_state here, + * if the thread hasn't been destructed. */ + assign_svalue(&thread_state->result, &throw_value); + } + call_handle_error(); - else if(throw_severity == THROW_EXIT) + } + + if(throw_severity == THROW_EXIT) { /* This is too early to get a clean exit if DO_PIKE_CLEANUP is * active. Otoh it cannot be done later since it requires the * evaluator stacks in the gc calls. It's difficult to solve * without handing over the cleanup duty to the main thread. */ pike_do_exit(throw_value.u.integer); - } else if (thread_state->thread_obj) { - /* Copy the thrown exit value to the thread_state here, - * if the thread hasn't been destructed. */ - assign_svalue(&thread_state->result, &throw_value); } + + thread_state->status = THREAD_ABORTED; } else { INT32 args=arg.args->size; back.severity=THROW_EXIT; @@ -1810,6 +1816,8 @@ TH_RETURN_TYPE new_thread_func(void *data) if (thread_state->thread_obj) assign_svalue(&thread_state->result, Pike_sp-1); pop_stack(); + + thread_state->status = THREAD_EXITED; } UNSETJMP(back); @@ -1821,7 +1829,6 @@ TH_RETURN_TYPE new_thread_func(void *data) thread_state->thread_local = NULL; } - thread_state->status = THREAD_EXITED; co_broadcast(&thread_state->status_change); THREADS_FPRINTF(0, (stderr,"new_thread_func(): Thread %p done\n", @@ -2683,6 +2690,7 @@ void f_thread_backtrace(INT32 args) *! @value Thread.THREAD_NOT_STARTED *! @value Thread.THREAD_RUNNING *! @value Thread.THREAD_EXITED + *! @value Thread.THREAD_ABORTED *! @endint */ void f_thread_id_status(INT32 args) @@ -2728,10 +2736,15 @@ void f_thread_id_id_number(INT32 args) *! *! Waits for the thread to complete, and then returns *! the value returned from the thread function. + *! + *! @throws + *! Rethrows the error thrown by the thread if it exited by + *! throwing an error. */ static void f_thread_id_result(INT32 UNUSED(args)) { struct thread_state *th=THIS_THREAD; + int th_status; if (threads_disabled) { Pike_error("Cannot wait for threads when threads are disabled!\n"); @@ -2741,7 +2754,7 @@ static void f_thread_id_result(INT32 UNUSED(args)) THREADS_FPRINTF(0, (stderr, "Thread->wait(): Waiting for thread_state %p " "(state:%d).\n", th, th->status)); - while(th->status != THREAD_EXITED) { + while(th->status < THREAD_EXITED) { SWAP_OUT_CURRENT_THREAD(); co_wait_interpreter(&th->status_change); SWAP_IN_CURRENT_THREAD(); @@ -2751,6 +2764,8 @@ static void f_thread_id_result(INT32 UNUSED(args)) "(state:%d).\n", th, th->status)); } + th_status = th->status; + assign_svalue_no_free(Pike_sp, &th->result); Pike_sp++; dmalloc_touch_svalue(Pike_sp-1); @@ -2760,6 +2775,8 @@ static void f_thread_id_result(INT32 UNUSED(args)) if (!th->thread_obj) /* Do this only if exit_thread_obj already has run. */ cleanup_thread_state (th); + + if (th_status == THREAD_ABORTED) f_throw(1); } static int num_pending_interrupts = 0; @@ -3370,6 +3387,7 @@ void th_init(void) add_integer_constant("THREAD_NOT_STARTED", THREAD_NOT_STARTED, 0); add_integer_constant("THREAD_RUNNING", THREAD_RUNNING, 0); add_integer_constant("THREAD_EXITED", THREAD_EXITED, 0); + add_integer_constant("THREAD_ABORTED", THREAD_ABORTED, 0); original_interpreter = Pike_interpreter_pointer; backend_thread_obj = fast_clone_object(thread_id_prog); diff --git a/src/threads.h b/src/threads.h index 2b911e5dcfd7a6d1aaed7da3212cb19877bf2d38..4e9f8b615a5ae5af1cdb6bb77ced1bc36e785d2b 100644 --- a/src/threads.h +++ b/src/threads.h @@ -23,6 +23,7 @@ struct pike_frame; #define THREAD_NOT_STARTED -1 #define THREAD_RUNNING 0 #define THREAD_EXITED 1 +#define THREAD_ABORTED 2 /* Thread flags */ #define THREAD_FLAG_TERM 1 /* Pending termination. */