* 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
This commit is contained in:
parent
4ed7917682
commit
ff895459b7
@ -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 <condition_variable.h>
|
||||
|
||||
struct team_dead_children {
|
||||
ConditionVariable<team_dead_children> 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;
|
||||
|
@ -8,8 +8,15 @@
|
||||
|
||||
/* Team functions */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
|
||||
#include <elf.h>
|
||||
#include <file_cache.h>
|
||||
#include <int.h>
|
||||
@ -28,11 +35,6 @@
|
||||
#include <vm_address_space.h>
|
||||
#include <util/khash.h>
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
//#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<team_dead_children> 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;
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user