* Dealt with a race condition on team exit. The death semaphore and
the thread count need to be accessed atomically. * Made debugging through exec*() work. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@11993 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+42
-7
@@ -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);
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user