diff --git a/headers/os/kernel/OS.h b/headers/os/kernel/OS.h index 9273e66471..3a541a7091 100644 --- a/headers/os/kernel/OS.h +++ b/headers/os/kernel/OS.h @@ -156,7 +156,7 @@ enum { extern sem_id create_sem(int32 count, const char *name); extern status_t delete_sem(sem_id id); -extern status_t delete_sem_etc(sem_id id, status_t returnCode); /* ToDo: not public BeOS */ +extern status_t delete_sem_etc(sem_id id, status_t returnCode, bool interrupted); /* ToDo: not public BeOS */ extern status_t acquire_sem(sem_id id); extern status_t acquire_sem_etc(sem_id id, int32 count, uint32 flags, bigtime_t timeout); extern status_t release_sem(sem_id id); diff --git a/headers/os/kernel/syscalls.h b/headers/os/kernel/syscalls.h index b1137b2fb2..b6fc2d51f7 100755 --- a/headers/os/kernel/syscalls.h +++ b/headers/os/kernel/syscalls.h @@ -48,6 +48,7 @@ thread_id sys_get_current_thread_id(void); int sys_suspend_thread(thread_id tid); int sys_resume_thread(thread_id tid); int sys_kill_thread(thread_id tid); +void sys_exit_thread(status_t return_value); status_t sys_wait_on_thread(thread_id tid, status_t *retcode); int sys_kill_team(team_id tid); diff --git a/headers/os/kernel/thread_types.h b/headers/os/kernel/thread_types.h index 125044e3e2..f7c9d318cc 100644 --- a/headers/os/kernel/thread_types.h +++ b/headers/os/kernel/thread_types.h @@ -52,9 +52,10 @@ enum { TEAM_STATE_DEATH // being killed }; -#define SIG_NONE 0 -#define SIG_SUSPEND 1 -#define SIG_KILL 2 + +#define THREAD_RETURN_EXIT 0x1 +#define THREAD_RETURN_INTERRUPTED 0x2 + /** * The team structure; equivalent to a common process. @@ -128,7 +129,9 @@ struct thread { addr entry; void *args; struct team *team; + status_t return_code; sem_id return_code_sem; + int return_flags; region_id kernel_stack_region_id; addr kernel_stack_base; region_id user_stack_region_id; diff --git a/headers/private/kernel/sem.h b/headers/private/kernel/sem.h index ac68d4476a..da3692dc48 100755 --- a/headers/private/kernel/sem.h +++ b/headers/private/kernel/sem.h @@ -16,7 +16,7 @@ /* user calls */ sem_id user_create_sem(int32 count, const char *name); status_t user_delete_sem(sem_id id); -status_t user_delete_sem_etc(sem_id id, status_t return_code); +status_t user_delete_sem_etc(sem_id id, status_t return_code, bool interrupted); status_t user_acquire_sem(sem_id id); status_t user_acquire_sem_etc(sem_id id, int32 count, uint32 flags, bigtime_t timeout); status_t user_release_sem(sem_id id); diff --git a/headers/private/kernel/thread.h b/headers/private/kernel/thread.h index e971db279b..c14b1356bf 100755 --- a/headers/private/kernel/thread.h +++ b/headers/private/kernel/thread.h @@ -43,7 +43,7 @@ int thread_resume_thread(thread_id id); status_t thread_set_priority(thread_id id, int32 priority); int thread_init(kernel_args *ka); int thread_init_percpu(int cpu_num); -void thread_exit(int retcode); +void thread_exit(void); int thread_kill_thread(thread_id id); int thread_kill_thread_nowait(thread_id id); diff --git a/src/kernel/core/sem.c b/src/kernel/core/sem.c index acfdaed052..87afc7997a 100644 --- a/src/kernel/core/sem.c +++ b/src/kernel/core/sem.c @@ -245,12 +245,12 @@ create_sem(int32 count, const char *name) status_t delete_sem(sem_id id) { - return delete_sem_etc(id, 0); + return delete_sem_etc(id, 0, false); } status_t -delete_sem_etc(sem_id id, status_t return_code) +delete_sem_etc(sem_id id, status_t return_code, bool interrupted) { int slot; int state; @@ -282,7 +282,7 @@ delete_sem_etc(sem_id id, status_t return_code) // free any threads waiting for this semaphore while ((t = thread_dequeue(&gSems[slot].q)) != NULL) { t->state = B_THREAD_READY; - t->sem_errcode = B_BAD_SEM_ID; + t->sem_errcode = interrupted ? B_INTERRUPTED : B_BAD_SEM_ID; t->sem_deleted_retcode = return_code; t->sem_count = 0; thread_enqueue(t, &release_queue); @@ -851,7 +851,7 @@ sem_delete_owned_sems(team_id owner) RELEASE_SEM_LIST_LOCK(); restore_interrupts(state); - delete_sem_etc(id, 0); + delete_sem(id); count++; state = disable_interrupts(); @@ -896,9 +896,9 @@ user_delete_sem(sem_id id) status_t -user_delete_sem_etc(sem_id id, status_t return_code) +user_delete_sem_etc(sem_id id, status_t return_code, bool interrupted) { - return delete_sem_etc(id, return_code); + return delete_sem_etc(id, return_code, interrupted); } diff --git a/src/kernel/core/signal.c b/src/kernel/core/signal.c index 2500b558f0..167c5f2db4 100644 --- a/src/kernel/core/signal.c +++ b/src/kernel/core/signal.c @@ -72,9 +72,11 @@ handle_signals(struct thread *t, int state) case SIGKILL: case SIGKILLTHR: default: + if (!(t->return_flags & THREAD_RETURN_EXIT)) + t->return_flags |= THREAD_RETURN_INTERRUPTED; RELEASE_THREAD_LOCK(); restore_interrupts(state); - thread_exit(sig); + thread_exit(); } } diff --git a/src/kernel/core/syscalls.c b/src/kernel/core/syscalls.c index 8f030c4d61..66bb1372c4 100644 --- a/src/kernel/core/syscalls.c +++ b/src/kernel/core/syscalls.c @@ -200,7 +200,8 @@ int syscall_dispatcher(unsigned long call_num, void *arg_buffer, uint64 *call_re *call_ret = thread_get_current_thread_id(); break; case SYSCALL_EXIT_THREAD: - thread_exit((int)arg0); + sys_exit_thread((status_t)arg0); +// thread_exit((int)arg0); *call_ret = 0; break; case SYSCALL_CREATE_TEAM: diff --git a/src/kernel/core/team.c b/src/kernel/core/team.c index 4de9ef3de4..82cb5c82ef 100644 --- a/src/kernel/core/team.c +++ b/src/kernel/core/team.c @@ -376,7 +376,7 @@ create_team_struct(const char *name, bool kernel) p->thread_list = NULL; p->main_thread = NULL; p->state = TEAM_STATE_BIRTH; - p->pending_signals = SIG_NONE; + p->pending_signals = 0; p->death_sem = -1; p->user_env_base = 0; diff --git a/src/kernel/core/thread.c b/src/kernel/core/thread.c index 6dd9d14678..b03f8583ff 100644 --- a/src/kernel/core/thread.c +++ b/src/kernel/core/thread.c @@ -270,6 +270,8 @@ create_thread_struct(const char *name) t->user_time = 0; t->kernel_time = 0; t->last_time = 0; + t->return_code = 0; + t->return_flags = 0; sprintf(temp, "thread_0x%lx_retcode_sem", t->id); t->return_code_sem = create_sem(0, temp); @@ -292,11 +294,11 @@ create_thread_struct(const char *name) return t; err4: - delete_sem_etc(t->msg.read_sem, -1); + delete_sem_etc(t->msg.read_sem, -1, false); err3: - delete_sem_etc(t->msg.write_sem, -1); + delete_sem_etc(t->msg.write_sem, -1, false); err2: - delete_sem_etc(t->return_code_sem, -1); + delete_sem_etc(t->return_code_sem, -1, false); err1: kfree(t); err: @@ -308,11 +310,11 @@ static void delete_thread_struct(struct thread *t) { if (t->return_code_sem >= 0) - delete_sem_etc(t->return_code_sem, -1); + delete_sem_etc(t->return_code_sem, -1, false); if (t->msg.write_sem >= 0) - delete_sem_etc(t->msg.write_sem, -1); + delete_sem_etc(t->msg.write_sem, -1, false); if (t->msg.read_sem >= 0) - delete_sem_etc(t->msg.read_sem, -1); + delete_sem_etc(t->msg.read_sem, -1, false); kfree(t); } @@ -957,7 +959,7 @@ thread_exit2(void *_args) void -thread_exit(int retcode) +thread_exit(void) { int state; struct thread *t = thread_get_current_thread(); @@ -966,7 +968,9 @@ thread_exit(int retcode) unsigned int death_stack; sem_id cached_death_sem; - dprintf("thread 0x%lx exiting w/return code 0x%x\n", t->id, retcode); + dprintf("thread 0x%lx exiting %s w/return code 0x%x\n", t->id, + t->return_flags & THREAD_RETURN_INTERRUPTED ? "due to signal" : "normally", + (int)t->return_code); // boost our priority to get this over with thread_set_priority(t->id, B_FIRST_REAL_TIME_PRIORITY); @@ -1048,7 +1052,7 @@ thread_exit(int retcode) sem_id s = t->return_code_sem; t->return_code_sem = -1; - delete_sem_etc(s, retcode); + delete_sem_etc(s, t->return_code, t->return_flags & THREAD_RETURN_INTERRUPTED ? true : false); } death_stack = get_death_stack(); @@ -1077,6 +1081,23 @@ thread_exit(int retcode) } +void +sys_exit_thread(status_t return_value) +{ + struct thread *t = thread_get_current_thread(); + int state; + + state = disable_interrupts(); + GRAB_THREAD_LOCK(); + t->return_code = return_value; + t->return_flags = THREAD_RETURN_EXIT; + RELEASE_THREAD_LOCK(); + restore_interrupts(state); + + send_signal_etc(t->id, SIGKILLTHR, B_DO_NOT_RESCHEDULE); +} + + int thread_kill_thread(thread_id id) { @@ -1102,7 +1123,10 @@ thread_kill_thread_nowait(thread_id id) static void thread_kthread_exit(void) { - thread_exit(0); + struct thread *t = thread_get_current_thread(); + + t->return_flags = THREAD_RETURN_EXIT; + thread_exit(); }