* Renamed get_team_death_entry() to team_get_death_entry() and make it available

to other kernel components.
* wait_for_thread_etc() will now search the team's death entries in case the
  thread is already gone; also resume_thread() is now done later, and its return
  code will no longer matter (as we already have our death entry, no matter if
  the thread is gone now or not).
* The fibo_load_image test now works as expected (only tested with low numbers
  yet, though - the mean testing comes later (first comes functionality) :-))


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19758 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2007-01-09 23:58:59 +00:00
parent cbe5f24524
commit cdcb059571
3 changed files with 70 additions and 39 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2004-2005, Haiku Inc.
* Copyright 2004-2007, Haiku Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _TEAM_H
@ -28,6 +28,8 @@ team_id team_get_current_team_id(void);
status_t team_get_address_space(team_id id, struct vm_address_space **_addressSpace);
char **user_team_get_arguments(void);
int user_team_get_arg_count(void);
status_t team_get_death_entry(struct team *team, thread_id child,
struct death_entry *death, struct death_entry **_freeDeath);
bool team_is_valid(team_id id);
struct team *team_get_team_struct_locked(team_id id);
int32 team_max_teams(void);

View File

@ -1289,37 +1289,6 @@ register_wait_for_any(struct team *team, thread_id child)
}
static status_t
get_team_death_entry(struct team *team, thread_id child, struct death_entry *death,
struct death_entry **_freeDeath)
{
struct death_entry *entry = NULL;
// find matching death entry structure
while ((entry = list_get_next_item(&team->dead_children.list, entry)) != NULL) {
if (child != -1 && entry->thread != child)
continue;
// we found one
*death = *entry;
// only remove the death entry if there aren't any other interested parties
if ((child == -1 && atomic_add(&team->dead_children.wait_for_any, -1) == 1)
|| (child != -1 && team->dead_children.wait_for_any == 0)) {
list_remove_link(entry);
team->dead_children.count--;
*_freeDeath = entry;
}
return B_OK;
}
return child > 0 ? B_BAD_THREAD_ID : B_WOULD_BLOCK;
}
/** Gets the next pending death entry, if any. Also fills in \a _waitSem
* to the semaphore the caller have to wait for for other death entries.
* Must be called with the team lock held.
@ -1336,7 +1305,7 @@ get_death_entry(struct team *team, pid_t child, struct death_entry *death,
// wait for any children or a specific child of this team to die
*_waitSem = team->dead_children.sem;
*_waitCount = &team->dead_children.waiters;
return get_team_death_entry(team, child, death, _freeDeath);
return team_get_death_entry(team, child, death, _freeDeath);
} else if (child < 0) {
// we wait for all children of the specified process group
group = team_get_process_group_locked(team->group->session, -child);
@ -1348,7 +1317,7 @@ get_death_entry(struct team *team, pid_t child, struct death_entry *death,
}
for (team = group->teams; team; team = team->group_next) {
status = get_team_death_entry(team, -1, death, _freeDeath);
status = team_get_death_entry(team, -1, death, _freeDeath);
if (status == B_OK) {
atomic_add(&group->wait_for_any, -1);
return B_OK;
@ -1568,6 +1537,41 @@ team_used_teams(void)
}
/** Fills the provided death entry if it's in the team.
* You need to have the team lock held when calling this function.
*/
status_t
team_get_death_entry(struct team *team, thread_id child, struct death_entry *death,
struct death_entry **_freeDeath)
{
struct death_entry *entry = NULL;
// find matching death entry structure
while ((entry = list_get_next_item(&team->dead_children.list, entry)) != NULL) {
if (child != -1 && entry->thread != child)
continue;
// we found one
*death = *entry;
// only remove the death entry if there aren't any other interested parties
if ((child == -1 && atomic_add(&team->dead_children.wait_for_any, -1) == 1)
|| (child != -1 && team->dead_children.wait_for_any == 0)) {
list_remove_link(entry);
team->dead_children.count--;
*_freeDeath = entry;
}
return B_OK;
}
return child > 0 ? B_BAD_THREAD_ID : B_WOULD_BLOCK;
}
/** Quick check to see if we have a valid team ID.
*/

View File

@ -1300,15 +1300,15 @@ status_t
wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout, status_t *_returnCode)
{
sem_id sem = B_BAD_THREAD_ID;
struct death_entry death;
struct death_entry death, *freeDeath = NULL;
struct thread *thread;
cpu_status state;
status_t status;
status_t status = B_OK;
if (id < B_OK)
return B_BAD_THREAD_ID;
// we need to resume the thread we're waiting for first
status = resume_thread(id);
if (status != B_OK)
return status;
state = disable_interrupts();
GRAB_THREAD_LOCK();
@ -1321,11 +1321,36 @@ wait_for_thread_etc(thread_id id, uint32 flags, bigtime_t timeout, status_t *_re
}
RELEASE_THREAD_LOCK();
if (thread == NULL) {
// we couldn't find this thread - maybe it's already gone, and we'll
// find its death entry
GRAB_TEAM_LOCK();
status = team_get_death_entry(thread_get_current_thread()->team,
id, &death, &freeDeath);
RELEASE_TEAM_LOCK();
}
restore_interrupts(state);
if (thread == NULL && status == B_OK) {
// we found the thread's death entry in our team
if (_returnCode)
*_returnCode = death.status;
free(freeDeath);
return B_OK;
}
// we need to wait for the death of the thread
if (sem < B_OK)
return B_BAD_THREAD_ID;
resume_thread(id);
status = acquire_sem_etc(sem, 1, flags, timeout);
if (status == B_OK) {