Added a list of death_entry's to the teams structure. It stores the
exit status of (non-main) threads of a team. Fixes bug #1644. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23009 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -94,7 +94,9 @@ struct team_watcher {
|
||||
};
|
||||
|
||||
#define MAX_DEAD_CHILDREN 32
|
||||
// this is a soft limit for the number of dead entries in a team
|
||||
// this is a soft limit for the number of child death entries in a team
|
||||
#define MAX_DEAD_THREADS 32
|
||||
// this is a soft limit for the number of thread death entries in a team
|
||||
|
||||
typedef struct team_dead_children team_dead_children;
|
||||
typedef struct team_job_control_children team_job_control_children;
|
||||
@@ -155,6 +157,8 @@ struct team {
|
||||
int pending_signals;
|
||||
void *io_context;
|
||||
sem_id death_sem; // semaphore to wait on for dying threads
|
||||
struct list dead_threads;
|
||||
int dead_threads_count;
|
||||
|
||||
team_dead_children *dead_children;
|
||||
team_job_control_children *stopped_children;
|
||||
|
||||
@@ -567,6 +567,10 @@ create_team_struct(const char *name, bool kernel)
|
||||
team->dead_threads_kernel_time = 0;
|
||||
team->dead_threads_user_time = 0;
|
||||
|
||||
// dead threads
|
||||
list_init(&team->dead_threads);
|
||||
team->dead_threads_count = 0;
|
||||
|
||||
// dead children
|
||||
team->dead_children = new(nothrow) team_dead_children;
|
||||
if (team->dead_children == NULL)
|
||||
@@ -636,6 +640,11 @@ delete_team_struct(struct team *team)
|
||||
|
||||
team->dead_children->condition_variable.Unpublish();
|
||||
|
||||
while (death_entry* threadDeathEntry = (death_entry*)list_remove_head_item(
|
||||
&team->dead_threads)) {
|
||||
free(threadDeathEntry);
|
||||
}
|
||||
|
||||
while (job_control_entry* entry = team->dead_children->entries.RemoveHead())
|
||||
delete entry;
|
||||
|
||||
|
||||
@@ -1215,11 +1215,14 @@ thread_exit(void)
|
||||
}
|
||||
|
||||
struct job_control_entry *death = NULL;
|
||||
struct death_entry* threadDeathEntry = NULL;
|
||||
|
||||
if (team != team_get_kernel_team()) {
|
||||
if (team->main_thread == thread) {
|
||||
// this was the main thread in this team, so we will delete that as well
|
||||
deleteTeam = true;
|
||||
}
|
||||
} else
|
||||
threadDeathEntry = (death_entry*)malloc(sizeof(death_entry));
|
||||
|
||||
// remove this thread from the current team and add it to the kernel
|
||||
// put the thread into the kernel team until it dies
|
||||
@@ -1272,8 +1275,30 @@ thread_exit(void)
|
||||
RELEASE_THREAD_LOCK();
|
||||
|
||||
team_remove_team(team, &freeGroup);
|
||||
} else
|
||||
} else {
|
||||
// The thread is not the main thread. We store a thread death
|
||||
// entry for it, unless someone is already waiting it.
|
||||
if (threadDeathEntry != NULL
|
||||
&& list_is_empty(&thread->exit.waiters)) {
|
||||
threadDeathEntry->thread = thread->id;
|
||||
threadDeathEntry->status = thread->exit.status;
|
||||
threadDeathEntry->reason = thread->exit.reason;
|
||||
threadDeathEntry->signal = thread->exit.signal;
|
||||
|
||||
// add entry -- remove and old one, if we hit the limit
|
||||
list_add_item(&team->dead_threads, threadDeathEntry);
|
||||
team->dead_threads_count++;
|
||||
threadDeathEntry = NULL;
|
||||
|
||||
if (team->dead_threads_count > MAX_DEAD_THREADS) {
|
||||
threadDeathEntry = (death_entry*)list_remove_head_item(
|
||||
&team->dead_threads);
|
||||
team->dead_threads_count--;
|
||||
}
|
||||
}
|
||||
|
||||
RELEASE_THREAD_LOCK();
|
||||
}
|
||||
|
||||
RELEASE_TEAM_LOCK();
|
||||
|
||||
@@ -1284,6 +1309,9 @@ thread_exit(void)
|
||||
TRACE(("thread_exit: thread %ld now a kernel thread!\n", thread->id));
|
||||
}
|
||||
|
||||
if (threadDeathEntry != NULL)
|
||||
free(threadDeathEntry);
|
||||
|
||||
// delete the team if we're its main thread
|
||||
if (deleteTeam) {
|
||||
team_delete_process_group(freeGroup);
|
||||
@@ -1640,6 +1668,8 @@ wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout,
|
||||
list_add_link_to_head(&thread->exit.waiters, &death);
|
||||
}
|
||||
|
||||
death_entry* threadDeathEntry = NULL;
|
||||
|
||||
RELEASE_THREAD_LOCK();
|
||||
|
||||
if (thread == NULL) {
|
||||
@@ -1647,15 +1677,31 @@ wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout,
|
||||
// find its death entry in our team
|
||||
GRAB_TEAM_LOCK();
|
||||
|
||||
struct team* team = thread_get_current_thread()->team;
|
||||
|
||||
// check the child death entries first (i.e. main threads of child
|
||||
// teams)
|
||||
bool deleteEntry;
|
||||
freeDeath = team_get_death_entry(thread_get_current_thread()->team, id,
|
||||
&deleteEntry);
|
||||
freeDeath = team_get_death_entry(team, id, &deleteEntry);
|
||||
if (freeDeath != NULL) {
|
||||
death.status = freeDeath->status;
|
||||
if (!deleteEntry)
|
||||
freeDeath = NULL;
|
||||
} else
|
||||
status = B_BAD_THREAD_ID;
|
||||
} else {
|
||||
// check the thread death entries of the team (non-main threads)
|
||||
while ((threadDeathEntry = (death_entry*)list_get_next_item(
|
||||
&team->dead_threads, threadDeathEntry)) != NULL) {
|
||||
if (threadDeathEntry->thread == id) {
|
||||
list_remove_item(&team->dead_threads, threadDeathEntry);
|
||||
team->dead_threads_count--;
|
||||
death.status = threadDeathEntry->status;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (threadDeathEntry == NULL)
|
||||
status = B_BAD_THREAD_ID;
|
||||
}
|
||||
|
||||
RELEASE_TEAM_LOCK();
|
||||
}
|
||||
@@ -1668,6 +1714,7 @@ wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout,
|
||||
*_returnCode = death.status;
|
||||
|
||||
delete freeDeath;
|
||||
free(threadDeathEntry);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user