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
|
#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_dead_children team_dead_children;
|
||||||
typedef struct team_job_control_children team_job_control_children;
|
typedef struct team_job_control_children team_job_control_children;
|
||||||
@@ -155,6 +157,8 @@ struct team {
|
|||||||
int pending_signals;
|
int pending_signals;
|
||||||
void *io_context;
|
void *io_context;
|
||||||
sem_id death_sem; // semaphore to wait on for dying threads
|
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_dead_children *dead_children;
|
||||||
team_job_control_children *stopped_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_kernel_time = 0;
|
||||||
team->dead_threads_user_time = 0;
|
team->dead_threads_user_time = 0;
|
||||||
|
|
||||||
|
// dead threads
|
||||||
|
list_init(&team->dead_threads);
|
||||||
|
team->dead_threads_count = 0;
|
||||||
|
|
||||||
// dead children
|
// dead children
|
||||||
team->dead_children = new(nothrow) team_dead_children;
|
team->dead_children = new(nothrow) team_dead_children;
|
||||||
if (team->dead_children == NULL)
|
if (team->dead_children == NULL)
|
||||||
@@ -636,6 +640,11 @@ delete_team_struct(struct team *team)
|
|||||||
|
|
||||||
team->dead_children->condition_variable.Unpublish();
|
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())
|
while (job_control_entry* entry = team->dead_children->entries.RemoveHead())
|
||||||
delete entry;
|
delete entry;
|
||||||
|
|
||||||
|
|||||||
@@ -1215,11 +1215,14 @@ thread_exit(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct job_control_entry *death = NULL;
|
struct job_control_entry *death = NULL;
|
||||||
|
struct death_entry* threadDeathEntry = NULL;
|
||||||
|
|
||||||
if (team != team_get_kernel_team()) {
|
if (team != team_get_kernel_team()) {
|
||||||
if (team->main_thread == thread) {
|
if (team->main_thread == thread) {
|
||||||
// this was the main thread in this team, so we will delete that as well
|
// this was the main thread in this team, so we will delete that as well
|
||||||
deleteTeam = true;
|
deleteTeam = true;
|
||||||
}
|
} else
|
||||||
|
threadDeathEntry = (death_entry*)malloc(sizeof(death_entry));
|
||||||
|
|
||||||
// remove this thread from the current team and add it to the kernel
|
// remove this thread from the current team and add it to the kernel
|
||||||
// put the thread into the kernel team until it dies
|
// put the thread into the kernel team until it dies
|
||||||
@@ -1272,8 +1275,30 @@ thread_exit(void)
|
|||||||
RELEASE_THREAD_LOCK();
|
RELEASE_THREAD_LOCK();
|
||||||
|
|
||||||
team_remove_team(team, &freeGroup);
|
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_THREAD_LOCK();
|
||||||
|
}
|
||||||
|
|
||||||
RELEASE_TEAM_LOCK();
|
RELEASE_TEAM_LOCK();
|
||||||
|
|
||||||
@@ -1284,6 +1309,9 @@ thread_exit(void)
|
|||||||
TRACE(("thread_exit: thread %ld now a kernel thread!\n", thread->id));
|
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
|
// delete the team if we're its main thread
|
||||||
if (deleteTeam) {
|
if (deleteTeam) {
|
||||||
team_delete_process_group(freeGroup);
|
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);
|
list_add_link_to_head(&thread->exit.waiters, &death);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
death_entry* threadDeathEntry = NULL;
|
||||||
|
|
||||||
RELEASE_THREAD_LOCK();
|
RELEASE_THREAD_LOCK();
|
||||||
|
|
||||||
if (thread == NULL) {
|
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
|
// find its death entry in our team
|
||||||
GRAB_TEAM_LOCK();
|
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;
|
bool deleteEntry;
|
||||||
freeDeath = team_get_death_entry(thread_get_current_thread()->team, id,
|
freeDeath = team_get_death_entry(team, id, &deleteEntry);
|
||||||
&deleteEntry);
|
|
||||||
if (freeDeath != NULL) {
|
if (freeDeath != NULL) {
|
||||||
death.status = freeDeath->status;
|
death.status = freeDeath->status;
|
||||||
if (!deleteEntry)
|
if (!deleteEntry)
|
||||||
freeDeath = NULL;
|
freeDeath = NULL;
|
||||||
} else
|
} 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;
|
status = B_BAD_THREAD_ID;
|
||||||
|
}
|
||||||
|
|
||||||
RELEASE_TEAM_LOCK();
|
RELEASE_TEAM_LOCK();
|
||||||
}
|
}
|
||||||
@@ -1668,6 +1714,7 @@ wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout,
|
|||||||
*_returnCode = death.status;
|
*_returnCode = death.status;
|
||||||
|
|
||||||
delete freeDeath;
|
delete freeDeath;
|
||||||
|
free(threadDeathEntry);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user