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:
Ingo Weinhold
2007-11-28 00:07:32 +00:00
parent d61a403741
commit 92ab20b3a4
3 changed files with 67 additions and 7 deletions
+5 -1
View File
@@ -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;
+9
View File
@@ -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;
+53 -6
View File
@@ -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;
}