kernel/thread: Convert Team::thread_list to a DoublyLinkedList.

Increase the size of the Thread structure by another pointer,
but makes thread insertions and removals constant-time.
This commit is contained in:
Augustin Cavalier
2025-03-03 13:49:49 -05:00
parent f6ca5f1927
commit 61d76848f0
6 changed files with 52 additions and 69 deletions
+3 -3
View File
@@ -222,7 +222,7 @@ struct Thread : TeamThreadIteratorEntry<thread_id>, KernelReferenceable {
// enabled, etc.)
int64 serial_number; // immutable after adding thread to hash
Thread *hash_next; // protected by thread hash lock
Thread *team_next; // protected by team lock and fLock
DoublyLinkedListLink<Thread> team_link; // protected by team lock and fLock
char name[B_OS_NAME_LENGTH]; // protected by fLock
bool going_to_suspend; // protected by scheduler lock
int32 priority; // protected by scheduler lock
@@ -467,8 +467,8 @@ struct Team : TeamThreadIteratorEntry<team_id>, KernelReferenceable,
VMAddressSpace *address_space;
Thread *main_thread; // protected by fLock, immutable
// after first set
Thread *thread_list; // protected by fLock, signal_lock and
// gThreadCreationLock
DoublyLinkedList<Thread, DoublyLinkedListMemberGetLink<Thread, &Thread::team_link> >
thread_list; // protected by fLock, signal_lock and gThreadCreationLock
struct team_loading_info *loading_info; // protected by fLock
DoublyLinkedList<image> image_list; // protected by sImageMutex
struct list watcher_list;
+4 -4
View File
@@ -877,8 +877,8 @@ private:
{
int32 count = 0;
for (Thread* thread = fTeam->thread_list; thread != NULL;
thread = thread->team_next) {
for (Thread* thread = fTeam->thread_list.First(); thread != NULL;
thread = fTeam->thread_list.GetNext(thread)) {
count++;
if (setFlag) {
atomic_or(&thread->flags, THREAD_FLAGS_TRAP_FOR_CORE_DUMP);
@@ -907,8 +907,8 @@ private:
fThreadCount = 0;
int32 missing = 0;
for (Thread* thread = fTeam->thread_list; thread != NULL;
thread = thread->team_next) {
for (Thread* thread = fTeam->thread_list.First(); thread != NULL;
thread = fTeam->thread_list.GetNext(thread)) {
fThreadCount++;
ThreadState* state = fPreAllocatedThreadStates.RemoveHead();
if (state != NULL) {
+14 -10
View File
@@ -171,14 +171,16 @@ update_threads_breakpoints_flag()
TeamLocker teamLocker(team);
Thread* thread = team->thread_list;
if (arch_has_breakpoints(&team->debug_info.arch_info)) {
for (; thread != NULL; thread = thread->team_next)
for (Thread* thread = team->thread_list.First(); thread != NULL;
thread = team->thread_list.GetNext(thread)) {
atomic_or(&thread->flags, THREAD_FLAGS_BREAKPOINTS_DEFINED);
}
} else {
for (; thread != NULL; thread = thread->team_next)
for (Thread* thread = team->thread_list.First(); thread != NULL;
thread = team->thread_list.GetNext(thread)) {
atomic_and(&thread->flags, ~THREAD_FLAGS_BREAKPOINTS_DEFINED);
}
}
}
@@ -205,14 +207,16 @@ update_thread_debugger_installed_flag(Thread* thread)
static void
update_threads_debugger_installed_flag(Team* team)
{
Thread* thread = team->thread_list;
if (atomic_get(&team->debug_info.flags) & B_TEAM_DEBUG_DEBUGGER_INSTALLED) {
for (; thread != NULL; thread = thread->team_next)
for (Thread* thread = team->thread_list.First(); thread != NULL;
thread = team->thread_list.GetNext(thread)) {
atomic_or(&thread->flags, THREAD_FLAGS_DEBUGGER_INSTALLED);
}
} else {
for (; thread != NULL; thread = thread->team_next)
for (Thread* thread = team->thread_list.First(); thread != NULL;
thread = team->thread_list.GetNext(thread)) {
atomic_and(&thread->flags, ~THREAD_FLAGS_DEBUGGER_INSTALLED);
}
}
}
@@ -2606,8 +2610,8 @@ install_team_debugger_init_debug_infos(Team *team, team_id debuggerTeam,
arch_clear_team_debug_info(&team->debug_info.arch_info);
// set the user debug flags and signal masks of all threads to the default
for (Thread *thread = team->thread_list; thread;
thread = thread->team_next) {
for (Thread *thread = team->thread_list.First(); thread != NULL;
thread = team->thread_list.GetNext(thread)) {
SpinLocker threadDebugInfoLocker(thread->debug_info.lock);
if (thread->id == nubThread) {
+12 -12
View File
@@ -785,8 +785,8 @@ update_current_thread_signals_flag()
static void
update_team_threads_signal_flag(Team* team)
{
for (Thread* thread = team->thread_list; thread != NULL;
thread = thread->team_next) {
for (Thread* thread = team->thread_list.First(); thread != NULL;
thread = team->thread_list.GetNext(thread)) {
update_thread_signals_flag(thread);
}
}
@@ -1307,8 +1307,8 @@ is_team_signal_blocked(Team* team, int signal)
{
sigset_t mask = SIGNAL_TO_MASK(signal);
for (Thread* thread = team->thread_list; thread != NULL;
thread = thread->team_next) {
for (Thread* thread = team->thread_list.First(); thread != NULL;
thread = team->thread_list.GetNext(thread)) {
if ((thread->sig_block_mask & mask) == 0)
return false;
}
@@ -1672,8 +1672,8 @@ send_signal_to_team_locked(Team* team, uint32 signalNumber, Signal* signal,
case SIGCONT:
// Wake up any suspended threads, interrupt the others, if they
// don't block the signal.
for (Thread* thread = team->thread_list; thread != NULL;
thread = thread->team_next) {
for (Thread* thread = team->thread_list.First(); thread != NULL;
thread = team->thread_list.GetNext(thread)) {
thread->going_to_suspend = false;
SpinLocker _(thread->scheduler_lock);
@@ -1698,8 +1698,8 @@ send_signal_to_team_locked(Team* team, uint32 signalNumber, Signal* signal,
case SIGTTOU:
// send the stop signal to all threads
// TODO: Is that correct or should we only target the main thread?
for (Thread* thread = team->thread_list; thread != NULL;
thread = thread->team_next) {
for (Thread* thread = team->thread_list.First(); thread != NULL;
thread = team->thread_list.GetNext(thread)) {
thread->AddPendingSignal(signalNumber);
}
@@ -1714,8 +1714,8 @@ send_signal_to_team_locked(Team* team, uint32 signalNumber, Signal* signal,
default:
// Interrupt all interruptibly waiting threads, if the signal is
// not masked.
for (Thread* thread = team->thread_list; thread != NULL;
thread = thread->team_next) {
for (Thread* thread = team->thread_list.First(); thread != NULL;
thread = team->thread_list.GetNext(thread)) {
sigset_t nonBlocked = ~thread->sig_block_mask
| SIGNAL_TO_MASK(SIGCHLD);
if ((thread->AllPendingSignals() & nonBlocked) != 0) {
@@ -2030,8 +2030,8 @@ sigaction_internal(int signal, const struct sigaction* act,
team->RemovePendingSignal(signal);
for (Thread* thread = team->thread_list; thread != NULL;
thread = thread->team_next) {
for (Thread* thread = team->thread_list.First(); thread != NULL;
thread = team->thread_list.GetNext(thread)) {
thread->RemovePendingSignal(signal);
}
}
+13 -20
View File
@@ -461,7 +461,6 @@ Team::Team(team_id id, bool kernel)
address_space = NULL;
main_thread = NULL;
thread_list = NULL;
loading_info = NULL;
list_init(&watcher_list);
@@ -938,8 +937,8 @@ Team::CPUTime(bool ignoreCurrentRun, Thread* lockedThread) const
Thread* currentThread = thread_get_current_thread();
bigtime_t now = system_time();
for (Thread* thread = thread_list; thread != NULL;
thread = thread->team_next) {
for (Thread* thread = thread_list.First(); thread != NULL;
thread = thread_list.GetNext(thread)) {
bool alreadyLocked = thread == lockedThread;
SpinLocker threadTimeLocker(thread->time_lock, alreadyLocked);
time += thread->kernel_time + thread->user_time;
@@ -970,8 +969,8 @@ Team::UserCPUTime() const
bigtime_t now = system_time();
for (Thread* thread = thread_list; thread != NULL;
thread = thread->team_next) {
for (Thread* thread = thread_list.First(); thread != NULL;
thread = thread_list.GetNext(thread)) {
SpinLocker threadTimeLocker(thread->time_lock);
time += thread->user_time;
@@ -1161,7 +1160,7 @@ _dump_team_info(Team* team)
(void*)team->user_data, team->user_data_area);
kprintf("free user thread: %p\n", team->free_user_threads);
kprintf("main_thread: %p\n", team->main_thread);
kprintf("thread_list: %p\n", team->thread_list);
kprintf("thread_list: %p\n", team->thread_list.First());
kprintf("group_id: %" B_PRId32 "\n", team->group_id);
kprintf("session_id: %" B_PRId32 "\n", team->session_id);
}
@@ -1963,8 +1962,8 @@ exec_team(const char* path, char**& _flatArgs, size_t flatArgsSize,
debugInfoLocker.Unlock();
for (Thread* thread = team->thread_list; thread != NULL;
thread = thread->team_next) {
for (Thread* thread = team->thread_list.First(); thread != NULL;
thread = team->thread_list.GetNext(thread)) {
if (thread != team->main_thread && thread->id != nubThreadID)
return B_NOT_ALLOWED;
}
@@ -2785,9 +2784,8 @@ common_get_team_usage_info(team_id id, int32 who, team_usage_info* info,
switch (who) {
case B_TEAM_USAGE_SELF:
{
Thread* thread = team->thread_list;
for (; thread != NULL; thread = thread->team_next) {
for (Thread* thread = team->thread_list.First(); thread != NULL;
thread = team->thread_list.GetNext(thread)) {
InterruptsSpinLocker threadTimeLocker(thread->time_lock);
kernelTime += thread->kernel_time;
userTime += thread->user_time;
@@ -2804,9 +2802,8 @@ common_get_team_usage_info(team_id id, int32 who, team_usage_info* info,
for (; child != NULL; child = team->children.GetNext(child)) {
TeamLocker childLocker(child);
Thread* thread = child->thread_list;
for (; thread != NULL; thread = thread->team_next) {
for (Thread* thread = child->thread_list.First(); thread != NULL;
thread = child->thread_list.GetNext(thread)) {
InterruptsSpinLocker threadTimeLocker(thread->time_lock);
kernelTime += thread->kernel_time;
userTime += thread->user_time;
@@ -3236,15 +3233,13 @@ team_shutdown_team(Team* team)
team->death_entry = &deathEntry;
deathEntry.remaining_threads = 0;
Thread* thread = team->thread_list;
while (thread != NULL) {
for (Thread* thread = team->thread_list.First(); thread != NULL;
thread = team->thread_list.GetNext(thread)) {
if (thread != team->main_thread) {
Signal signal(SIGKILLTHR, SI_USER, B_OK, team->id);
send_signal_to_thread(thread, signal, B_DO_NOT_RESCHEDULE);
deathEntry.remaining_threads++;
}
thread = thread->team_next;
}
if (deathEntry.remaining_threads == 0)
@@ -3255,9 +3250,7 @@ team_shutdown_team(Team* team)
deathEntry.condition.Add(&entry);
teamLocker.Unlock();
entry.Wait();
teamLocker.Lock();
}
+6 -20
View File
@@ -264,7 +264,6 @@ Thread::Thread(const char* name, thread_id threadID, struct cpu_ent* cpu)
flags(0),
serial_number(-1),
hash_next(NULL),
team_next(NULL),
priority(-1),
io_priority(-1),
cpu(cpu),
@@ -708,8 +707,7 @@ ThreadCreationAttributes::InitFromUserAttributes(
static void
insert_thread_into_team(Team *team, Thread *thread)
{
thread->team_next = team->thread_list;
team->thread_list = thread;
team->thread_list.Add(thread, false);
team->num_threads++;
if (team->num_threads == 1) {
@@ -727,20 +725,8 @@ insert_thread_into_team(Team *team, Thread *thread)
static void
remove_thread_from_team(Team *team, Thread *thread)
{
Thread *temp, *last = NULL;
for (temp = team->thread_list; temp != NULL; temp = temp->team_next) {
if (temp == thread) {
if (last == NULL)
team->thread_list = temp->team_next;
else
last->team_next = temp->team_next;
team->num_threads--;
break;
}
last = temp;
}
team->thread_list.Remove(thread);
team->num_threads--;
}
@@ -1874,7 +1860,7 @@ _dump_thread_info(Thread *thread, bool shortInfo)
kprintf("serial_number: %" B_PRId64 "\n", thread->serial_number);
kprintf("name: \"%s\"\n", thread->name);
kprintf("hash_next: %p\nteam_next: %p\n",
thread->hash_next, thread->team_next);
thread->hash_next, thread->team_link.next);
kprintf("priority: %" B_PRId32 " (I/O: %" B_PRId32 ")\n",
thread->priority, thread->io_priority);
kprintf("state: %s\n", state_to_text(thread, thread->state));
@@ -3339,8 +3325,8 @@ _get_next_thread_info(team_id teamID, int32 *_cookie, thread_info *info,
// don't wrap they are always sorted from highest to lowest).
// TODO: That is broken not only when the IDs wrap, but also for the
// kernel team, to which threads are added when they are dying.
for (Thread* next = team->thread_list; next != NULL;
next = next->team_next) {
for (Thread* next = team->thread_list.First(); next != NULL;
next = team->thread_list.GetNext(next)) {
if (next->id <= lastID)
break;