Process groups are no longer searched via their team/session, but by using a separate

hash. This also allows them to stay valid after the group leader died when there are
other teams left in it. This closes bug #1.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18622 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2006-08-24 22:58:48 +00:00
parent 3e975f9210
commit 6961cdf6f2
2 changed files with 55 additions and 33 deletions

View File

@ -57,11 +57,11 @@ struct death_entry {
struct process_session {
pid_t id;
struct list groups;
int32 group_count;
};
struct process_group {
struct list_link link;
struct process_group *next; // next in hash
struct process_session *session;
pid_t id;
sem_id dead_child_sem;
@ -86,7 +86,7 @@ struct team_watcher {
// this is a soft limit for the number of dead entries in a team
struct team {
struct team *next; /* next team in the hash */
struct team *next; // next in hash
struct team *siblings_next;
struct team *parent;
struct team *children;

View File

@ -63,8 +63,8 @@ struct fork_arg {
};
// team list
static void *sTeamHash = NULL;
static void *sGroupHash = NULL;
static struct team *sKernelTeam = NULL;
// some arbitrary chosen limits - should probably depend on the available
@ -82,6 +82,8 @@ static struct team *create_team_struct(const char *name, bool kernel);
static void delete_team_struct(struct team *p);
static int team_struct_compare(void *_p, const void *_key);
static uint32 team_struct_hash(void *_p, const void *_key, uint32 range);
static int process_group_compare(void *_p, const void *_key);
static uint32 process_group_hash(void *_p, const void *_key, uint32 range);
static void free_strings_array(char **strings, int32 count);
static status_t user_copy_strings_array(char * const *strings, int32 count, char ***_strings);
static void _dump_team_info(struct team *p);
@ -175,9 +177,12 @@ team_init(kernel_args *args)
struct process_group *group;
// create the team hash table
sTeamHash = hash_init(15, offsetof(struct team, next),
sTeamHash = hash_init(16, offsetof(struct team, next),
&team_struct_compare, &team_struct_hash);
sGroupHash = hash_init(16, offsetof(struct process_group, next),
&process_group_compare, &process_group_hash);
// create initial session and process groups
session = create_process_session(1);
@ -361,6 +366,32 @@ copy_strings_array(char * const *strings, int32 count, char ***_strings,
}
static int
process_group_compare(void *_group, const void *_key)
{
struct process_group *group = _group;
const struct team_key *key = _key;
if (group->id == key->id)
return 0;
return 1;
}
static uint32
process_group_hash(void *_group, const void *_key, uint32 range)
{
struct process_group *group = _group;
const struct team_key *key = _key;
if (group != NULL)
return group->id % range;
return (uint32)key->id % range;
}
/** Quick check to see if we have a valid team ID.
*/
@ -389,7 +420,6 @@ struct team *
team_get_team_struct_locked(team_id id)
{
struct team_key key;
key.id = id;
return hash_lookup(sTeamHash, &key);
@ -482,6 +512,8 @@ is_process_group_leader(struct team *team)
}
/** You must hold the team lock when calling this function. */
static void
insert_group_into_session(struct process_session *session, struct process_group *group)
{
@ -489,10 +521,13 @@ insert_group_into_session(struct process_session *session, struct process_group
return;
group->session = session;
list_add_link_to_tail(&session->groups, group);
hash_insert(sGroupHash, group);
session->group_count++;
}
/** You must hold the team lock when calling this function. */
static void
insert_team_into_group(struct process_group *group, struct team *team)
{
@ -520,11 +555,11 @@ remove_group_from_session(struct process_group *group)
if (session == NULL)
return;
list_remove_link(group);
hash_remove(sGroupHash, group);
// we cannot free the resource here, so we're keeping the group link
// around - this way it'll be freed by free_process_group()
if (!list_is_empty(&session->groups))
if (--session->group_count > 0)
group->session = NULL;
}
@ -632,7 +667,7 @@ create_process_session(pid_t id)
return NULL;
session->id = id;
list_init(&session->groups);
session->group_count = 0;
return session;
}
@ -1517,21 +1552,13 @@ err1:
static struct process_group *
get_process_group_locked(struct team *team, pid_t id)
{
struct list *groups = &team->group->session->groups;
struct process_group *group = NULL;
// ToDo: a process group lasts as long as its last member - and
// that doesn't have to be the process leader. IOW we need
// a separate hash table for those groups without a leader.
struct process_group *group;
struct team_key key;
key.id = id;
// a short cut when the current team's group is asked for
if (team->group->id == id)
return team->group;
while ((group = list_get_next_item(groups, group)) != NULL) {
if (group->id == id)
return group;
}
group = (struct process_group *)hash_lookup(sGroupHash, &key);
if (group != NULL && team->group->session == group->session)
return group;
return NULL;
}
@ -2337,17 +2364,10 @@ _user_setpgid(pid_t processID, pid_t groupID)
remove_team_from_group(team, &freeGroup);
insert_team_into_group(group, team);
} else {
struct process_session *session = team->group->session;
struct process_group *group = NULL;
// check if this team can have the group ID; there must be one matching
// process ID in the team's session
while ((group = list_get_next_item(&session->groups, group)) != NULL) {
if (group->id == groupID)
break;
}
struct process_group *group = get_process_group_locked(team, groupID);
if (group) {
// we got a group, let's move the team there
remove_team_from_group(team, &freeGroup);
@ -2361,8 +2381,10 @@ _user_setpgid(pid_t processID, pid_t groupID)
RELEASE_TEAM_LOCK();
restore_interrupts(state);
if (status != B_OK && group != NULL)
if (status != B_OK && group != NULL) {
// in case of error, the group hasn't been added into the hash
team_delete_process_group(group);
}
team_delete_process_group(freeGroup);