From ff895459b795520dddd83f77c7460ba7810e3c87 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 27 Aug 2007 20:30:34 +0000 Subject: [PATCH] * Replaced the team::dead_children::sem semaphore by a condition variable. Due to C code including the header I had to turn it from and aggregated member to a pointer. I'm very close to starting to convert all remaining .c to .cpp files. :-/ * Got rid of the "waiters" field. It was only written, never read. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22084 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/thread_types.h | 31 +++++++--- src/system/kernel/team.cpp | 85 ++++++++++++++------------- src/system/kernel/thread.cpp | 13 ++-- 3 files changed, 72 insertions(+), 57 deletions(-) diff --git a/headers/private/kernel/thread_types.h b/headers/private/kernel/thread_types.h index 573547eaaa..98f6962832 100644 --- a/headers/private/kernel/thread_types.h +++ b/headers/private/kernel/thread_types.h @@ -82,6 +82,27 @@ struct team_watcher { #define MAX_DEAD_CHILDREN 32 // this is a soft limit for the number of dead entries in a team +typedef struct team_dead_children team_dead_children; + + +#ifdef __cplusplus + +#include + +struct team_dead_children { + ConditionVariable condition_variable; + // wait for dead child entries + struct list list; + uint32 count; + vint32 wait_for_any; // count of wait_for_child() that wait for any + // child + bigtime_t kernel_time; + bigtime_t user_time; +}; + +#endif // __cplusplus + + struct team { struct team *next; // next in hash struct team *siblings_next; @@ -99,15 +120,7 @@ struct team { int pending_signals; void *io_context; sem_id death_sem; // semaphore to wait on for dying threads - struct { - sem_id sem; // wait for dead child entries - struct list list; - uint32 count; - vint32 wait_for_any; // count of wait_for_child() that wait for any child - int32 waiters; // count of all threads waiting for dead children sem - bigtime_t kernel_time; - bigtime_t user_time; - } dead_children; + team_dead_children *dead_children; struct vm_address_space *address_space; struct thread *main_thread; struct thread *thread_list; diff --git a/src/system/kernel/team.cpp b/src/system/kernel/team.cpp index 8f0bcb9af6..41d6ba33e7 100644 --- a/src/system/kernel/team.cpp +++ b/src/system/kernel/team.cpp @@ -8,8 +8,15 @@ /* Team functions */ +#include +#include +#include +#include + #include +#include + #include #include #include @@ -28,11 +35,6 @@ #include #include -#include -#include -#include -#include - //#define TRACE_TEAM #ifdef TRACE_TEAM # define TRACE(x) dprintf x @@ -543,6 +545,7 @@ create_team_struct(const char *name, bool kernel) struct team *team = (struct team *)malloc(sizeof(struct team)); if (team == NULL) return NULL; + MemoryDeleter teamDeleter(team); team->next = team->siblings_next = team->children = team->parent = NULL; team->id = allocate_thread_id(); @@ -561,31 +564,33 @@ create_team_struct(const char *name, bool kernel) team->dead_threads_kernel_time = 0; team->dead_threads_user_time = 0; - list_init(&team->dead_children.list); - team->dead_children.count = 0; - team->dead_children.wait_for_any = 0; - team->dead_children.waiters = 0; - team->dead_children.kernel_time = 0; - team->dead_children.user_time = 0; - team->dead_children.sem = create_sem(0, "dead children"); - if (team->dead_children.sem < B_OK) - goto error1; + team->dead_children + = (team_dead_children*)malloc(sizeof(team_dead_children)); + if (team->dead_children == NULL) + return NULL; + MemoryDeleter deadChildrenDeleter(team->dead_children); + + list_init(&team->dead_children->list); + team->dead_children->count = 0; + team->dead_children->wait_for_any = 0; + team->dead_children->kernel_time = 0; + team->dead_children->user_time = 0; + team->dead_children->condition_variable.Publish(team->dead_children, + "dead children"); list_init(&team->image_list); list_init(&team->watcher_list); clear_team_debug_info(&team->debug_info, true); - if (arch_team_init_team_struct(team, kernel) < 0) - goto error2; + if (arch_team_init_team_struct(team, kernel) < 0) { + team->dead_children->condition_variable.Unpublish(); + return NULL; + } + deadChildrenDeleter.Detach(); + teamDeleter.Detach(); return team; - -error2: - delete_sem(team->dead_children.sem); -error1: - free(team); - return NULL; } @@ -594,13 +599,14 @@ delete_team_struct(struct team *team) { struct death_entry *death; - delete_sem(team->dead_children.sem); + team->dead_children->condition_variable.Unpublish(); while ((death = (struct death_entry*)list_remove_head_item( - &team->dead_children.list)) != NULL) { + &team->dead_children->list)) != NULL) { free(death); } + free(team->dead_children); free(team); } @@ -1276,11 +1282,11 @@ wait_for_child(thread_id child, uint32 flags, int32 *_reason, status_t *_returnC } if (child < 0) { // we need to make sure the death entries won't get deleted too soon - atomic_add(&team->dead_children.wait_for_any, 1); + atomic_add(&team->dead_children->wait_for_any, 1); } while (true) { - sem_id waitSem = -1; + ConditionVariableEntry waitEntry; cpu_status state = disable_interrupts(); GRAB_THREAD_LOCK(); @@ -1332,8 +1338,7 @@ wait_for_child(thread_id child, uint32 flags, int32 *_reason, status_t *_returnC if (status == B_WOULD_BLOCK && (flags & WNOHANG) == 0) { // We need to hold the team lock when changing this counter, // but of course only if we really will wait later - waitSem = team->dead_children.sem; - team->dead_children.waiters++; + waitEntry.Add(team->dead_children); } RELEASE_TEAM_LOCK(); @@ -1345,7 +1350,7 @@ wait_for_child(thread_id child, uint32 flags, int32 *_reason, status_t *_returnC if (status != B_WOULD_BLOCK || (flags & WNOHANG) != 0) goto err; - status = acquire_sem_etc(waitSem, 1, B_CAN_INTERRUPT, 0); + status = waitEntry.Wait(B_CAN_INTERRUPT); if (status == B_INTERRUPTED) goto err; } @@ -1361,7 +1366,7 @@ wait_for_child(thread_id child, uint32 flags, int32 *_reason, status_t *_returnC err: if (child < 0) - atomic_add(&team->dead_children.wait_for_any, -1); + atomic_add(&team->dead_children->wait_for_any, -1); return status; } @@ -1480,7 +1485,7 @@ team_get_death_entry(struct team *team, thread_id child, struct death_entry *dea } while ((entry = (struct death_entry*)list_get_next_item( - &team->dead_children.list, entry)) != NULL) { + &team->dead_children->list, entry)) != NULL) { if (child != -1 && entry->thread != child && entry->group_id != -child) continue; @@ -1489,10 +1494,10 @@ team_get_death_entry(struct team *team, thread_id child, struct death_entry *dea *death = *entry; // only remove the death entry if there aren't any other interested parties - if ((child < 0 && atomic_add(&team->dead_children.wait_for_any, -1) == 1) - || (child > 0 && team->dead_children.wait_for_any == 0)) { + if ((child < 0 && atomic_add(&team->dead_children->wait_for_any, -1) == 1) + || (child > 0 && team->dead_children->wait_for_any == 0)) { list_remove_link(entry); - team->dead_children.count--; + team->dead_children->count--; *_freeDeath = entry; } @@ -1588,10 +1593,10 @@ team_remove_team(struct team *team, struct process_group **_freeGroup) struct team *parent = team->parent; // remember how long this team lasted - parent->dead_children.kernel_time += team->dead_threads_kernel_time - + team->dead_children.kernel_time; - parent->dead_children.user_time += team->dead_threads_user_time - + team->dead_children.user_time; + parent->dead_children->kernel_time += team->dead_threads_kernel_time + + team->dead_children->kernel_time; + parent->dead_children->user_time += team->dead_threads_user_time + + team->dead_children->user_time; hash_remove(sTeamHash, team); sUsedTeams--; @@ -2064,8 +2069,8 @@ _get_team_usage_info(team_id id, int32 who, team_usage_info *info, size_t size) userTime += child->dead_threads_user_time; } - kernelTime += team->dead_children.kernel_time; - userTime += team->dead_children.user_time; + kernelTime += team->dead_children->kernel_time; + userTime += team->dead_children->user_time; break; } } diff --git a/src/system/kernel/thread.cpp b/src/system/kernel/thread.cpp index 92bb5cd75d..79cf868a59 100644 --- a/src/system/kernel/thread.cpp +++ b/src/system/kernel/thread.cpp @@ -1164,11 +1164,11 @@ thread_exit(void) if (death != NULL) { // insert death entry into the parent's list - list_add_link_to_tail(&parent->dead_children.list, death); - if (++parent->dead_children.count > MAX_DEAD_CHILDREN) { + list_add_link_to_tail(&parent->dead_children->list, death); + if (++parent->dead_children->count > MAX_DEAD_CHILDREN) { death = (struct death_entry*)list_remove_head_item( - &parent->dead_children.list); - parent->dead_children.count--; + &parent->dead_children->list); + parent->dead_children->count--; } else death = NULL; @@ -1176,10 +1176,7 @@ thread_exit(void) // notify listeners that a new death entry is available // TODO: should that be moved to handle_signal() (for SIGCHLD)? - release_sem_etc(parent->dead_children.sem, - parent->dead_children.waiters, B_DO_NOT_RESCHEDULE); - - parent->dead_children.waiters = 0; + parent->dead_children->condition_variable.NotifyOne(); } else RELEASE_THREAD_LOCK();