* 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;
|
struct thread *temp_thread;
|
||||||
char death_sem_name[B_OS_NAME_LENGTH];
|
char death_sem_name[B_OS_NAME_LENGTH];
|
||||||
cpu_status state;
|
cpu_status state;
|
||||||
|
sem_id deathSem;
|
||||||
|
int32 threadCount;
|
||||||
|
|
||||||
sprintf(death_sem_name, "team %ld death sem", team->id);
|
sprintf(death_sem_name, "team %ld death sem", team->id);
|
||||||
team->death_sem = create_sem(0, death_sem_name);
|
deathSem = create_sem(0, death_sem_name);
|
||||||
if (team->death_sem < 0)
|
if (deathSem < 0)
|
||||||
panic("thread_exit: cannot init death sem for team %ld\n", team->id);
|
panic("thread_exit: cannot init death sem for team %ld\n", team->id);
|
||||||
|
|
||||||
state = disable_interrupts();
|
state = disable_interrupts();
|
||||||
GRAB_TEAM_LOCK();
|
GRAB_TEAM_LOCK();
|
||||||
|
|
||||||
|
team->death_sem = deathSem;
|
||||||
|
threadCount = team->num_threads;
|
||||||
|
|
||||||
// If the team was being debugged, that will stop with the termination
|
// If the team was being debugged, that will stop with the termination
|
||||||
// of the nub thread. The team structure has already been removed from
|
// 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
|
// 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);
|
restore_interrupts(state);
|
||||||
|
|
||||||
// wait until all threads in team are dead.
|
// 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);
|
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 *team = thread_get_current_thread()->team;
|
||||||
struct team_arg *teamArgs;
|
struct team_arg *teamArgs;
|
||||||
const char *threadName;
|
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));
|
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
|
// we currently need to be single threaded here
|
||||||
// ToDo: maybe we should just kill all other threads and
|
// ToDo: maybe we should just kill all other threads and
|
||||||
// make the current thread the team's main thread?
|
// make the current thread the team's main thread?
|
||||||
if (team->main_thread != thread_get_current_thread()
|
if (team->main_thread != thread_get_current_thread())
|
||||||
|| team->main_thread != team->thread_list
|
|
||||||
|| team->main_thread->team_next != NULL)
|
|
||||||
return B_NOT_ALLOWED;
|
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?
|
// ToDo: maybe we should make sure upfront that the target path is an app?
|
||||||
|
|
||||||
teamArgs = create_team_arg(argCount, args, envCount, env);
|
teamArgs = create_team_arg(argCount, args, envCount, env);
|
||||||
@@ -1184,6 +1215,8 @@ exec_team(int32 argCount, char **args, int32 envCount, char **env)
|
|||||||
// alarm, signals
|
// alarm, signals
|
||||||
// thread_atkernel_exit() might not be called at all
|
// thread_atkernel_exit() might not be called at all
|
||||||
|
|
||||||
|
user_debug_prepare_for_exec();
|
||||||
|
|
||||||
vm_delete_areas(team->aspace);
|
vm_delete_areas(team->aspace);
|
||||||
delete_owned_ports(team->id);
|
delete_owned_ports(team->id);
|
||||||
sem_delete_owned_sems(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);
|
cache_node_launched(argCount, args);
|
||||||
|
|
||||||
|
user_debug_finish_after_exec();
|
||||||
|
|
||||||
// rename the team
|
// rename the team
|
||||||
|
|
||||||
strlcpy(team->name, args[0], B_OS_NAME_LENGTH);
|
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
|
// we can't let the interrupts disabled at this point
|
||||||
enable_interrupts();
|
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
|
// delete the old kernel stack area
|
||||||
TRACE(("thread_exit2: deleting old kernel stack id 0x%lx for thread 0x%lx\n",
|
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;
|
thread_id mainParentThread = -1;
|
||||||
bool deleteTeam = false;
|
bool deleteTeam = false;
|
||||||
uint32 death_stack;
|
uint32 death_stack;
|
||||||
sem_id cachedDeathSem, parentDeadSem = -1, groupDeadSem = -1;
|
sem_id cachedDeathSem = -1, parentDeadSem = -1, groupDeadSem = -1;
|
||||||
status_t status;
|
status_t status;
|
||||||
struct thread_debug_info debugInfo;
|
struct thread_debug_info debugInfo;
|
||||||
team_id teamID = team->id;
|
team_id teamID = team->id;
|
||||||
@@ -889,6 +889,8 @@ thread_exit(void)
|
|||||||
remove_thread_from_team(team, thread);
|
remove_thread_from_team(team, thread);
|
||||||
insert_thread_into_team(team_get_kernel_team(), thread);
|
insert_thread_into_team(team_get_kernel_team(), thread);
|
||||||
|
|
||||||
|
cachedDeathSem = team->death_sem;
|
||||||
|
|
||||||
if (deleteTeam) {
|
if (deleteTeam) {
|
||||||
struct team *parent = team->parent;
|
struct team *parent = team->parent;
|
||||||
|
|
||||||
@@ -939,8 +941,7 @@ thread_exit(void)
|
|||||||
|
|
||||||
send_signal_etc(mainParentThread, SIGCHLD, B_DO_NOT_RESCHEDULE);
|
send_signal_etc(mainParentThread, SIGCHLD, B_DO_NOT_RESCHEDULE);
|
||||||
cachedDeathSem = -1;
|
cachedDeathSem = -1;
|
||||||
} else
|
}
|
||||||
cachedDeathSem = team->death_sem;
|
|
||||||
|
|
||||||
// fill all death entries and delete the sem that others will use to wait on us
|
// fill all death entries and delete the sem that others will use to wait on us
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user