diff options
Diffstat (limited to 'kern')
-rw-r--r-- | kern/ast.c | 2 | ||||
-rw-r--r-- | kern/exception.c | 32 | ||||
-rw-r--r-- | kern/profile.c | 2 | ||||
-rw-r--r-- | kern/thread.c | 4 | ||||
-rw-r--r-- | kern/thread.h | 2 |
5 files changed, 33 insertions, 9 deletions
@@ -96,7 +96,7 @@ ast_taken(void) if (self != current_processor()->idle_thread) { #ifndef MIGRATING_THREADS while (thread_should_halt(self)) - thread_halt_self(); + thread_halt_self(thread_exception_return); #endif /* diff --git a/kern/exception.c b/kern/exception.c index 6cb3bfb..63a63d6 100644 --- a/kern/exception.c +++ b/kern/exception.c @@ -231,7 +231,7 @@ exception_no_server(void) */ while (thread_should_halt(self)) - thread_halt_self(); + thread_halt_self(thread_exception_return); #if 0 @@ -257,7 +257,7 @@ exception_no_server(void) */ (void) task_terminate(self->task); - thread_halt_self(); + thread_halt_self(thread_exception_return); panic("terminating the task didn't kill us"); /*NOTREACHED*/ } @@ -848,6 +848,26 @@ exception_raise_continue(void) } /* + * Routine: thread_release_and_exception_return + * Purpose: + * Continue after thread was halted. + * Conditions: + * Nothing locked. We are running on a new kernel stack and + * control goes back to thread_exception_return. + * Returns: + * Doesn't return. + */ +static void +thread_release_and_exception_return(void) +{ + ipc_thread_t self = current_thread(); + /* reply port must be released */ + ipc_port_release(self->ith_port); + thread_exception_return(); + /*NOTREACHED*/ +} + +/* * Routine: exception_raise_continue_slow * Purpose: * Continue after finishing an ipc_mqueue_receive @@ -876,10 +896,14 @@ exception_raise_continue_slow( */ while (thread_should_halt(self)) { - /* don't terminate while holding a reference */ + /* if thread is about to terminate, release the port */ if (self->ast & AST_TERMINATE) ipc_port_release(reply_port); - thread_halt_self(); + /* + * Use the continuation to release the port in + * case the thread is about to halt. + */ + thread_halt_self(thread_release_and_exception_return); } ip_lock(reply_port); diff --git a/kern/profile.c b/kern/profile.c index 2c9c44b..1381b1a 100644 --- a/kern/profile.c +++ b/kern/profile.c @@ -172,7 +172,7 @@ printf("profile_thread: mach_msg failed returned %x\n",(int)mr); sizeof(struct buf_to_send)); } - thread_halt_self(); + thread_halt_self(thread_exception_return); } diff --git a/kern/thread.c b/kern/thread.c index c638075..3e90079 100644 --- a/kern/thread.c +++ b/kern/thread.c @@ -1132,7 +1132,7 @@ void __attribute__((noreturn)) walking_zombie(void) * Thread calls this routine on exit from the kernel when it * notices a halt request. */ -void thread_halt_self(void) +void thread_halt_self(continuation_t continuation) { thread_t thread = current_thread(); spl_t s; @@ -1173,7 +1173,7 @@ void thread_halt_self(void) thread_unlock(thread); splx(s); counter(c_thread_halt_self_block++); - thread_block(thread_exception_return); + thread_block(continuation); /* * thread_release resets TH_HALTED. */ diff --git a/kern/thread.h b/kern/thread.h index 949d618..7106fd2 100644 --- a/kern/thread.h +++ b/kern/thread.h @@ -362,7 +362,7 @@ extern void thread_release(thread_t); extern kern_return_t thread_halt( thread_t thread, boolean_t must_halt); -extern void thread_halt_self(void); +extern void thread_halt_self(continuation_t); extern void thread_force_terminate(thread_t); extern thread_t kernel_thread( task_t task, |