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:
@@ -57,11 +57,11 @@ struct death_entry {
|
|||||||
|
|
||||||
struct process_session {
|
struct process_session {
|
||||||
pid_t id;
|
pid_t id;
|
||||||
struct list groups;
|
int32 group_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct process_group {
|
struct process_group {
|
||||||
struct list_link link;
|
struct process_group *next; // next in hash
|
||||||
struct process_session *session;
|
struct process_session *session;
|
||||||
pid_t id;
|
pid_t id;
|
||||||
sem_id dead_child_sem;
|
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
|
// this is a soft limit for the number of dead entries in a team
|
||||||
|
|
||||||
struct team {
|
struct team {
|
||||||
struct team *next; /* next team in the hash */
|
struct team *next; // next in hash
|
||||||
struct team *siblings_next;
|
struct team *siblings_next;
|
||||||
struct team *parent;
|
struct team *parent;
|
||||||
struct team *children;
|
struct team *children;
|
||||||
|
|||||||
+51
-29
@@ -63,8 +63,8 @@ struct fork_arg {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// team list
|
|
||||||
static void *sTeamHash = NULL;
|
static void *sTeamHash = NULL;
|
||||||
|
static void *sGroupHash = NULL;
|
||||||
static struct team *sKernelTeam = NULL;
|
static struct team *sKernelTeam = NULL;
|
||||||
|
|
||||||
// some arbitrary chosen limits - should probably depend on the available
|
// 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 void delete_team_struct(struct team *p);
|
||||||
static int team_struct_compare(void *_p, const void *_key);
|
static int team_struct_compare(void *_p, const void *_key);
|
||||||
static uint32 team_struct_hash(void *_p, const void *_key, uint32 range);
|
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 void free_strings_array(char **strings, int32 count);
|
||||||
static status_t user_copy_strings_array(char * const *strings, int32 count, char ***_strings);
|
static status_t user_copy_strings_array(char * const *strings, int32 count, char ***_strings);
|
||||||
static void _dump_team_info(struct team *p);
|
static void _dump_team_info(struct team *p);
|
||||||
@@ -175,9 +177,12 @@ team_init(kernel_args *args)
|
|||||||
struct process_group *group;
|
struct process_group *group;
|
||||||
|
|
||||||
// create the team hash table
|
// 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);
|
&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
|
// create initial session and process groups
|
||||||
|
|
||||||
session = create_process_session(1);
|
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.
|
/** 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)
|
team_get_team_struct_locked(team_id id)
|
||||||
{
|
{
|
||||||
struct team_key key;
|
struct team_key key;
|
||||||
|
|
||||||
key.id = id;
|
key.id = id;
|
||||||
|
|
||||||
return hash_lookup(sTeamHash, &key);
|
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
|
static void
|
||||||
insert_group_into_session(struct process_session *session, struct process_group *group)
|
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;
|
return;
|
||||||
|
|
||||||
group->session = session;
|
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
|
static void
|
||||||
insert_team_into_group(struct process_group *group, struct team *team)
|
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)
|
if (session == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
list_remove_link(group);
|
hash_remove(sGroupHash, group);
|
||||||
|
|
||||||
// we cannot free the resource here, so we're keeping the group link
|
// we cannot free the resource here, so we're keeping the group link
|
||||||
// around - this way it'll be freed by free_process_group()
|
// 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;
|
group->session = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -632,7 +667,7 @@ create_process_session(pid_t id)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
session->id = id;
|
session->id = id;
|
||||||
list_init(&session->groups);
|
session->group_count = 0;
|
||||||
|
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
@@ -1517,21 +1552,13 @@ err1:
|
|||||||
static struct process_group *
|
static struct process_group *
|
||||||
get_process_group_locked(struct team *team, pid_t id)
|
get_process_group_locked(struct team *team, pid_t id)
|
||||||
{
|
{
|
||||||
struct list *groups = &team->group->session->groups;
|
struct process_group *group;
|
||||||
struct process_group *group = NULL;
|
struct team_key key;
|
||||||
|
key.id = id;
|
||||||
|
|
||||||
// ToDo: a process group lasts as long as its last member - and
|
group = (struct process_group *)hash_lookup(sGroupHash, &key);
|
||||||
// that doesn't have to be the process leader. IOW we need
|
if (group != NULL && team->group->session == group->session)
|
||||||
// a separate hash table for those groups without a leader.
|
|
||||||
|
|
||||||
// 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;
|
return group;
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -2337,17 +2364,10 @@ _user_setpgid(pid_t processID, pid_t groupID)
|
|||||||
remove_team_from_group(team, &freeGroup);
|
remove_team_from_group(team, &freeGroup);
|
||||||
insert_team_into_group(group, team);
|
insert_team_into_group(group, team);
|
||||||
} else {
|
} 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
|
// check if this team can have the group ID; there must be one matching
|
||||||
// process ID in the team's session
|
// process ID in the team's session
|
||||||
|
|
||||||
while ((group = list_get_next_item(&session->groups, group)) != NULL) {
|
struct process_group *group = get_process_group_locked(team, groupID);
|
||||||
if (group->id == groupID)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (group) {
|
if (group) {
|
||||||
// we got a group, let's move the team there
|
// we got a group, let's move the team there
|
||||||
remove_team_from_group(team, &freeGroup);
|
remove_team_from_group(team, &freeGroup);
|
||||||
@@ -2361,8 +2381,10 @@ _user_setpgid(pid_t processID, pid_t groupID)
|
|||||||
RELEASE_TEAM_LOCK();
|
RELEASE_TEAM_LOCK();
|
||||||
restore_interrupts(state);
|
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(group);
|
||||||
|
}
|
||||||
|
|
||||||
team_delete_process_group(freeGroup);
|
team_delete_process_group(freeGroup);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user