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