diff --git a/src/kernel/core/team.c b/src/kernel/core/team.c index 0386960f26..9a9d048632 100644 --- a/src/kernel/core/team.c +++ b/src/kernel/core/team.c @@ -753,15 +753,20 @@ team_delete_team(struct team *team) struct thread *temp_thread; char death_sem_name[B_OS_NAME_LENGTH]; cpu_status state; + sem_id deathSem; + int32 threadCount; sprintf(death_sem_name, "team %ld death sem", team->id); - team->death_sem = create_sem(0, death_sem_name); - if (team->death_sem < 0) + deathSem = create_sem(0, death_sem_name); + if (deathSem < 0) panic("thread_exit: cannot init death sem for team %ld\n", team->id); state = disable_interrupts(); GRAB_TEAM_LOCK(); + team->death_sem = deathSem; + threadCount = team->num_threads; + // If the team was being debugged, that will stop with the termination // of the nub thread. The team structure has already been removed from // the team hash table at this point, so noone can install a debugger @@ -811,7 +816,7 @@ team_delete_team(struct team *team) restore_interrupts(state); // wait until all threads in team are dead. - acquire_sem_etc(team->death_sem, team->num_threads, 0, 0); + acquire_sem_etc(team->death_sem, threadCount, 0, 0); delete_sem(team->death_sem); } @@ -1158,7 +1163,10 @@ exec_team(int32 argCount, char **args, int32 envCount, char **env) struct team *team = thread_get_current_thread()->team; struct team_arg *teamArgs; const char *threadName; - status_t status; + status_t status = B_OK; + cpu_status state; + struct thread *thread; + thread_id nubThreadID = -1; TRACE(("exec_team(path = \"%s\", argc = %ld, envCount = %ld)\n", args[0], argCount, envCount)); @@ -1169,11 +1177,34 @@ exec_team(int32 argCount, char **args, int32 envCount, char **env) // we currently need to be single threaded here // ToDo: maybe we should just kill all other threads and // make the current thread the team's main thread? - if (team->main_thread != thread_get_current_thread() - || team->main_thread != team->thread_list - || team->main_thread->team_next != NULL) + if (team->main_thread != thread_get_current_thread()) return B_NOT_ALLOWED; + // The debug nub thread, a pure kernel thread, is allowed to survive. + // We iterate through the thread list to make sure that there's no other + // thread. + state = disable_interrupts(); + GRAB_TEAM_LOCK(); + GRAB_TEAM_DEBUG_INFO_LOCK(team->debug_info); + + if (team->debug_info.flags & B_TEAM_DEBUG_DEBUGGER_INSTALLED) + nubThreadID = team->debug_info.nub_thread; + + RELEASE_TEAM_DEBUG_INFO_LOCK(team->debug_info); + + for (thread = team->thread_list; thread; thread = thread->team_next) { + if (thread != team->main_thread && thread->id != nubThreadID) { + status = B_NOT_ALLOWED; + break; + } + } + + RELEASE_TEAM_LOCK(); + restore_interrupts(state); + + if (status != B_OK) + return status; + // ToDo: maybe we should make sure upfront that the target path is an app? teamArgs = create_team_arg(argCount, args, envCount, env); @@ -1184,6 +1215,8 @@ exec_team(int32 argCount, char **args, int32 envCount, char **env) // alarm, signals // thread_atkernel_exit() might not be called at all + user_debug_prepare_for_exec(); + vm_delete_areas(team->aspace); delete_owned_ports(team->id); sem_delete_owned_sems(team->id); @@ -1192,6 +1225,8 @@ exec_team(int32 argCount, char **args, int32 envCount, char **env) cache_node_launched(argCount, args); + user_debug_finish_after_exec(); + // rename the team strlcpy(team->name, args[0], B_OS_NAME_LENGTH); diff --git a/src/kernel/core/thread.c b/src/kernel/core/thread.c index 39717da1ca..0436f971b0 100644 --- a/src/kernel/core/thread.c +++ b/src/kernel/core/thread.c @@ -750,7 +750,7 @@ thread_exit2(void *_args) // we can't let the interrupts disabled at this point enable_interrupts(); - TRACE(("thread_exit2, running on death stack 0x%lx\n", args.t->kernel_stack_base)); + TRACE(("thread_exit2, running on death stack 0x%lx\n", args.death_stack)); // delete the old kernel stack area TRACE(("thread_exit2: deleting old kernel stack id 0x%lx for thread 0x%lx\n", @@ -808,7 +808,7 @@ thread_exit(void) thread_id mainParentThread = -1; bool deleteTeam = false; uint32 death_stack; - sem_id cachedDeathSem, parentDeadSem = -1, groupDeadSem = -1; + sem_id cachedDeathSem = -1, parentDeadSem = -1, groupDeadSem = -1; status_t status; struct thread_debug_info debugInfo; team_id teamID = team->id; @@ -889,6 +889,8 @@ thread_exit(void) remove_thread_from_team(team, thread); insert_thread_into_team(team_get_kernel_team(), thread); + cachedDeathSem = team->death_sem; + if (deleteTeam) { struct team *parent = team->parent; @@ -939,8 +941,7 @@ thread_exit(void) send_signal_etc(mainParentThread, SIGCHLD, B_DO_NOT_RESCHEDULE); cachedDeathSem = -1; - } else - cachedDeathSem = team->death_sem; + } // fill all death entries and delete the sem that others will use to wait on us {