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:
@@ -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);
|
||||||
|
|||||||
@@ -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
@@ -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);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user