* 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:
Ingo Weinhold
2005-03-25 18:28:24 +00:00
parent d2c78559a0
commit 4f43c96006
2 changed files with 47 additions and 11 deletions
+42 -7
View File
@@ -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);
+5 -4
View File
@@ -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
{