kernel/team: Convert Team linked-lists into DoublyLinkedLists.

They were hand-rolled singly-linked lists before. This adds 24 bytes
of size to the Team structure, but turns all the removal operations
in parent and process group into O(1) operations instead of O(N) ones.
Realistically, the Thread linked-lists should be converted as well,
but this is trickier due to interdependence on the Team structure.
This commit is contained in:
Augustin Cavalier
2025-01-06 23:39:40 -05:00
parent cc9746dbc6
commit 6a75e767e6
3 changed files with 31 additions and 58 deletions
+12 -8
View File
@@ -220,14 +220,13 @@ struct Team : TeamThreadIteratorEntry<team_id>, KernelReferenceable,
AssociatedDataOwner { AssociatedDataOwner {
DoublyLinkedListLink<Team> global_list_link; DoublyLinkedListLink<Team> global_list_link;
Team *hash_next; // next in hash Team *hash_next; // next in hash
Team *siblings_next; // next in parent's list; protected by DoublyLinkedListLink<Team> siblings_link; // protected by parent's fLock
// parent's fLock
Team *parent; // write-protected by both parent (if any) Team *parent; // write-protected by both parent (if any)
// and this team's fLock // and this team's fLock
Team *children; // protected by this team's fLock; DoublyLinkedList<Team, DoublyLinkedListMemberGetLink<Team, &Team::siblings_link> > children;
// adding/removing a child also requires the // protected by this team's fLock;
// child's fLock // adding/removing a child also requires the child's fLock
Team *group_next; // protected by the group's lock DoublyLinkedListLink<Team> group_link; // protected by the group's lock
int64 serial_number; // immutable after adding team to hash int64 serial_number; // immutable after adding team to hash
@@ -667,9 +666,14 @@ private:
struct ProcessGroup : KernelReferenceable { struct ProcessGroup : KernelReferenceable {
struct ProcessGroup *next; // next in hash typedef DoublyLinkedList<Team,
DoublyLinkedListMemberGetLink<Team,
&Team::group_link> > TeamList;
public:
struct ProcessGroup *hash_next;
pid_t id; pid_t id;
BKernel::Team *teams; TeamList teams;
public: public:
ProcessGroup(pid_t id); ProcessGroup(pid_t id);
+1 -1
View File
@@ -1828,7 +1828,7 @@ send_signal_to_process_group_locked(ProcessGroup* group, const Signal& signal,
bool firstTeam = true; bool firstTeam = true;
for (Team* team = group->teams; team != NULL; team = team->group_next) { for (Team* team = group->teams.First(); team != NULL; team = group->teams.GetNext(team)) {
status_t error = send_signal_to_team(team, signal, status_t error = send_signal_to_team(team, signal,
flags | B_DO_NOT_RESCHEDULE); flags | B_DO_NOT_RESCHEDULE);
// If sending to the first team in the group failed, let the whole call // If sending to the first team in the group failed, let the whole call
+18 -49
View File
@@ -132,7 +132,7 @@ struct ProcessGroupHashDefinition {
ProcessGroup*& GetLink(ProcessGroup* value) const ProcessGroup*& GetLink(ProcessGroup* value) const
{ {
return value->next; return value->hash_next;
} }
}; };
@@ -431,7 +431,7 @@ Team::Team(team_id id, bool kernel)
this->id = id; this->id = id;
visible = true; visible = true;
hash_next = siblings_next = parent = children = group_next = NULL; hash_next = parent = NULL;
serial_number = -1; serial_number = -1;
group_id = session_id = -1; group_id = session_id = -1;
@@ -990,7 +990,6 @@ Team::UserCPUTime() const
ProcessGroup::ProcessGroup(pid_t id) ProcessGroup::ProcessGroup(pid_t id)
: :
id(id), id(id),
teams(NULL),
fSession(NULL), fSession(NULL),
fInOrphanedCheckList(false) fInOrphanedCheckList(false)
{ {
@@ -1074,7 +1073,7 @@ ProcessGroup::IsOrphaned() const
// group's session." (Open Group Base Specs Issue 7) // group's session." (Open Group Base Specs Issue 7)
bool orphaned = true; bool orphaned = true;
Team* team = teams; Team* team = teams.First();
while (orphaned && team != NULL) { while (orphaned && team != NULL) {
team->LockTeamAndParent(false); team->LockTeamAndParent(false);
@@ -1086,7 +1085,7 @@ ProcessGroup::IsOrphaned() const
team->UnlockTeamAndParent(); team->UnlockTeamAndParent();
team = team->group_next; team = teams.GetNext(team);
} }
return orphaned; return orphaned;
@@ -1152,7 +1151,7 @@ _dump_team_info(Team* team)
} else } else
kprintf("\n"); kprintf("\n");
kprintf("children: %p\n", team->children); kprintf("children: %p\n", team->children.First());
kprintf("num_threads: %d\n", team->num_threads); kprintf("num_threads: %d\n", team->num_threads);
kprintf("state: %d\n", team->state); kprintf("state: %d\n", team->state);
kprintf("flags: 0x%" B_PRIx32 "\n", team->flags); kprintf("flags: 0x%" B_PRIx32 "\n", team->flags);
@@ -1282,8 +1281,7 @@ insert_team_into_parent(Team* parent, Team* team)
{ {
ASSERT(parent != NULL); ASSERT(parent != NULL);
team->siblings_next = parent->children; parent->children.Add(team, false);
parent->children = team;
team->parent = parent; team->parent = parent;
} }
@@ -1298,22 +1296,8 @@ insert_team_into_parent(Team* parent, Team* team)
static void static void
remove_team_from_parent(Team* parent, Team* team) remove_team_from_parent(Team* parent, Team* team)
{ {
Team* child; parent->children.Remove(team);
Team* last = NULL; team->parent = NULL;
for (child = parent->children; child != NULL;
child = child->siblings_next) {
if (child == team) {
if (last == NULL)
parent->children = child->siblings_next;
else
last->siblings_next = child->siblings_next;
team->parent = NULL;
break;
}
last = child;
}
} }
@@ -1348,8 +1332,7 @@ insert_team_into_group(ProcessGroup* group, Team* team)
team->group_id = group->id; team->group_id = group->id;
team->session_id = group->Session()->id; team->session_id = group->Session()->id;
team->group_next = group->teams; group->teams.Add(team, false);
group->teams = team;
group->AcquireReference(); group->AcquireReference();
} }
@@ -1365,28 +1348,14 @@ static void
remove_team_from_group(Team* team) remove_team_from_group(Team* team)
{ {
ProcessGroup* group = team->group; ProcessGroup* group = team->group;
Team* current;
Team* last = NULL;
// the team must be in a process group to let this function have any effect // the team must be in a process group to let this function have any effect
if (group == NULL) if (group == NULL)
return; return;
for (current = group->teams; current != NULL; group->teams.Remove(team);
current = current->group_next) {
if (current == team) {
if (last == NULL)
group->teams = current->group_next;
else
last->group_next = current->group_next;
break;
}
last = current;
}
team->group = NULL; team->group = NULL;
team->group_next = NULL;
team->group_id = -1; team->group_id = -1;
group->ReleaseReference(); group->ReleaseReference();
@@ -2329,8 +2298,8 @@ err1:
static bool static bool
has_children_in_group(Team* parent, pid_t groupID) has_children_in_group(Team* parent, pid_t groupID)
{ {
for (Team* child = parent->children; child != NULL; for (Team* child = parent->children.First(); child != NULL;
child = child->siblings_next) { child = parent->children.GetNext(child)) {
TeamLocker childLocker(child); TeamLocker childLocker(child);
if (child->group_id == groupID) if (child->group_id == groupID)
return true; return true;
@@ -2534,7 +2503,7 @@ wait_for_child(pid_t child, uint32 flags, siginfo_t& _info,
// to the process group specification at all. // to the process group specification at all.
bool childrenExist = false; bool childrenExist = false;
if (child == -1) { if (child == -1) {
childrenExist = team->children != NULL; childrenExist = !team->children.IsEmpty();
} else if (child < -1) { } else if (child < -1) {
childrenExist = has_children_in_group(team, -child); childrenExist = has_children_in_group(team, -child);
} else if (child != team->id) { } else if (child != team->id) {
@@ -2734,7 +2703,7 @@ fill_team_info(Team* team, team_info* info, size_t size)
static bool static bool
process_group_has_stopped_processes(ProcessGroup* group) process_group_has_stopped_processes(ProcessGroup* group)
{ {
Team* team = group->teams; Team* team = group->teams.First();
while (team != NULL) { while (team != NULL) {
// the parent team's lock guards the job control entry -- acquire it // the parent team's lock guards the job control entry -- acquire it
team->LockTeamAndParent(false); team->LockTeamAndParent(false);
@@ -2747,7 +2716,7 @@ process_group_has_stopped_processes(ProcessGroup* group)
team->UnlockTeamAndParent(); team->UnlockTeamAndParent();
team = team->group_next; team = group->teams.GetNext(team);
} }
return false; return false;
@@ -2833,8 +2802,8 @@ common_get_team_usage_info(team_id id, int32 who, team_usage_info* info,
case B_TEAM_USAGE_CHILDREN: case B_TEAM_USAGE_CHILDREN:
{ {
Team* child = team->children; Team* child = team->children.First();
for (; child != NULL; child = child->siblings_next) { for (; child != NULL; child = team->children.GetNext(team)) {
TeamLocker childLocker(child); TeamLocker childLocker(child);
Thread* thread = team->thread_list; Thread* thread = team->thread_list;
@@ -3160,7 +3129,7 @@ team_remove_team(Team* team, pid_t& _signalGroup)
remove_team_from_group(team); remove_team_from_group(team);
// move the team's children to the kernel team // move the team's children to the kernel team
while (Team* child = team->children) { while (Team* child = team->children.First()) {
// remove the child from the current team and add it to the kernel team // remove the child from the current team and add it to the kernel team
TeamLocker childLocker(child); TeamLocker childLocker(child);