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.)
|
// enabled, etc.)
|
||||||
int64 serial_number; // immutable after adding thread to hash
|
int64 serial_number; // immutable after adding thread to hash
|
||||||
Thread *hash_next; // protected by thread hash lock
|
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
|
char name[B_OS_NAME_LENGTH]; // protected by fLock
|
||||||
bool going_to_suspend; // protected by scheduler lock
|
bool going_to_suspend; // protected by scheduler lock
|
||||||
int32 priority; // protected by scheduler lock
|
int32 priority; // protected by scheduler lock
|
||||||
@@ -467,8 +467,8 @@ struct Team : TeamThreadIteratorEntry<team_id>, KernelReferenceable,
|
|||||||
VMAddressSpace *address_space;
|
VMAddressSpace *address_space;
|
||||||
Thread *main_thread; // protected by fLock, immutable
|
Thread *main_thread; // protected by fLock, immutable
|
||||||
// after first set
|
// after first set
|
||||||
Thread *thread_list; // protected by fLock, signal_lock and
|
DoublyLinkedList<Thread, DoublyLinkedListMemberGetLink<Thread, &Thread::team_link> >
|
||||||
// gThreadCreationLock
|
thread_list; // protected by fLock, signal_lock and gThreadCreationLock
|
||||||
struct team_loading_info *loading_info; // protected by fLock
|
struct team_loading_info *loading_info; // protected by fLock
|
||||||
DoublyLinkedList<image> image_list; // protected by sImageMutex
|
DoublyLinkedList<image> image_list; // protected by sImageMutex
|
||||||
struct list watcher_list;
|
struct list watcher_list;
|
||||||
|
|||||||
@@ -877,8 +877,8 @@ private:
|
|||||||
{
|
{
|
||||||
int32 count = 0;
|
int32 count = 0;
|
||||||
|
|
||||||
for (Thread* thread = fTeam->thread_list; thread != NULL;
|
for (Thread* thread = fTeam->thread_list.First(); thread != NULL;
|
||||||
thread = thread->team_next) {
|
thread = fTeam->thread_list.GetNext(thread)) {
|
||||||
count++;
|
count++;
|
||||||
if (setFlag) {
|
if (setFlag) {
|
||||||
atomic_or(&thread->flags, THREAD_FLAGS_TRAP_FOR_CORE_DUMP);
|
atomic_or(&thread->flags, THREAD_FLAGS_TRAP_FOR_CORE_DUMP);
|
||||||
@@ -907,8 +907,8 @@ private:
|
|||||||
fThreadCount = 0;
|
fThreadCount = 0;
|
||||||
int32 missing = 0;
|
int32 missing = 0;
|
||||||
|
|
||||||
for (Thread* thread = fTeam->thread_list; thread != NULL;
|
for (Thread* thread = fTeam->thread_list.First(); thread != NULL;
|
||||||
thread = thread->team_next) {
|
thread = fTeam->thread_list.GetNext(thread)) {
|
||||||
fThreadCount++;
|
fThreadCount++;
|
||||||
ThreadState* state = fPreAllocatedThreadStates.RemoveHead();
|
ThreadState* state = fPreAllocatedThreadStates.RemoveHead();
|
||||||
if (state != NULL) {
|
if (state != NULL) {
|
||||||
|
|||||||
@@ -171,15 +171,17 @@ update_threads_breakpoints_flag()
|
|||||||
|
|
||||||
TeamLocker teamLocker(team);
|
TeamLocker teamLocker(team);
|
||||||
|
|
||||||
Thread* thread = team->thread_list;
|
|
||||||
|
|
||||||
if (arch_has_breakpoints(&team->debug_info.arch_info)) {
|
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);
|
atomic_or(&thread->flags, THREAD_FLAGS_BREAKPOINTS_DEFINED);
|
||||||
|
}
|
||||||
} else {
|
} 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);
|
atomic_and(&thread->flags, ~THREAD_FLAGS_BREAKPOINTS_DEFINED);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -205,15 +207,17 @@ update_thread_debugger_installed_flag(Thread* thread)
|
|||||||
static void
|
static void
|
||||||
update_threads_debugger_installed_flag(Team* team)
|
update_threads_debugger_installed_flag(Team* team)
|
||||||
{
|
{
|
||||||
Thread* thread = team->thread_list;
|
|
||||||
|
|
||||||
if (atomic_get(&team->debug_info.flags) & B_TEAM_DEBUG_DEBUGGER_INSTALLED) {
|
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);
|
atomic_or(&thread->flags, THREAD_FLAGS_DEBUGGER_INSTALLED);
|
||||||
|
}
|
||||||
} else {
|
} 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);
|
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);
|
arch_clear_team_debug_info(&team->debug_info.arch_info);
|
||||||
|
|
||||||
// set the user debug flags and signal masks of all threads to the default
|
// set the user debug flags and signal masks of all threads to the default
|
||||||
for (Thread *thread = team->thread_list; thread;
|
for (Thread *thread = team->thread_list.First(); thread != NULL;
|
||||||
thread = thread->team_next) {
|
thread = team->thread_list.GetNext(thread)) {
|
||||||
SpinLocker threadDebugInfoLocker(thread->debug_info.lock);
|
SpinLocker threadDebugInfoLocker(thread->debug_info.lock);
|
||||||
|
|
||||||
if (thread->id == nubThread) {
|
if (thread->id == nubThread) {
|
||||||
|
|||||||
@@ -785,8 +785,8 @@ update_current_thread_signals_flag()
|
|||||||
static void
|
static void
|
||||||
update_team_threads_signal_flag(Team* team)
|
update_team_threads_signal_flag(Team* team)
|
||||||
{
|
{
|
||||||
for (Thread* thread = team->thread_list; thread != NULL;
|
for (Thread* thread = team->thread_list.First(); thread != NULL;
|
||||||
thread = thread->team_next) {
|
thread = team->thread_list.GetNext(thread)) {
|
||||||
update_thread_signals_flag(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);
|
sigset_t mask = SIGNAL_TO_MASK(signal);
|
||||||
|
|
||||||
for (Thread* thread = team->thread_list; thread != NULL;
|
for (Thread* thread = team->thread_list.First(); thread != NULL;
|
||||||
thread = thread->team_next) {
|
thread = team->thread_list.GetNext(thread)) {
|
||||||
if ((thread->sig_block_mask & mask) == 0)
|
if ((thread->sig_block_mask & mask) == 0)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1672,8 +1672,8 @@ send_signal_to_team_locked(Team* team, uint32 signalNumber, Signal* signal,
|
|||||||
case SIGCONT:
|
case SIGCONT:
|
||||||
// Wake up any suspended threads, interrupt the others, if they
|
// Wake up any suspended threads, interrupt the others, if they
|
||||||
// don't block the signal.
|
// don't block the signal.
|
||||||
for (Thread* thread = team->thread_list; thread != NULL;
|
for (Thread* thread = team->thread_list.First(); thread != NULL;
|
||||||
thread = thread->team_next) {
|
thread = team->thread_list.GetNext(thread)) {
|
||||||
thread->going_to_suspend = false;
|
thread->going_to_suspend = false;
|
||||||
|
|
||||||
SpinLocker _(thread->scheduler_lock);
|
SpinLocker _(thread->scheduler_lock);
|
||||||
@@ -1698,8 +1698,8 @@ send_signal_to_team_locked(Team* team, uint32 signalNumber, Signal* signal,
|
|||||||
case SIGTTOU:
|
case SIGTTOU:
|
||||||
// send the stop signal to all threads
|
// send the stop signal to all threads
|
||||||
// TODO: Is that correct or should we only target the main thread?
|
// TODO: Is that correct or should we only target the main thread?
|
||||||
for (Thread* thread = team->thread_list; thread != NULL;
|
for (Thread* thread = team->thread_list.First(); thread != NULL;
|
||||||
thread = thread->team_next) {
|
thread = team->thread_list.GetNext(thread)) {
|
||||||
thread->AddPendingSignal(signalNumber);
|
thread->AddPendingSignal(signalNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1714,8 +1714,8 @@ send_signal_to_team_locked(Team* team, uint32 signalNumber, Signal* signal,
|
|||||||
default:
|
default:
|
||||||
// Interrupt all interruptibly waiting threads, if the signal is
|
// Interrupt all interruptibly waiting threads, if the signal is
|
||||||
// not masked.
|
// not masked.
|
||||||
for (Thread* thread = team->thread_list; thread != NULL;
|
for (Thread* thread = team->thread_list.First(); thread != NULL;
|
||||||
thread = thread->team_next) {
|
thread = team->thread_list.GetNext(thread)) {
|
||||||
sigset_t nonBlocked = ~thread->sig_block_mask
|
sigset_t nonBlocked = ~thread->sig_block_mask
|
||||||
| SIGNAL_TO_MASK(SIGCHLD);
|
| SIGNAL_TO_MASK(SIGCHLD);
|
||||||
if ((thread->AllPendingSignals() & nonBlocked) != 0) {
|
if ((thread->AllPendingSignals() & nonBlocked) != 0) {
|
||||||
@@ -2030,8 +2030,8 @@ sigaction_internal(int signal, const struct sigaction* act,
|
|||||||
|
|
||||||
team->RemovePendingSignal(signal);
|
team->RemovePendingSignal(signal);
|
||||||
|
|
||||||
for (Thread* thread = team->thread_list; thread != NULL;
|
for (Thread* thread = team->thread_list.First(); thread != NULL;
|
||||||
thread = thread->team_next) {
|
thread = team->thread_list.GetNext(thread)) {
|
||||||
thread->RemovePendingSignal(signal);
|
thread->RemovePendingSignal(signal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-20
@@ -461,7 +461,6 @@ Team::Team(team_id id, bool kernel)
|
|||||||
|
|
||||||
address_space = NULL;
|
address_space = NULL;
|
||||||
main_thread = NULL;
|
main_thread = NULL;
|
||||||
thread_list = NULL;
|
|
||||||
loading_info = NULL;
|
loading_info = NULL;
|
||||||
|
|
||||||
list_init(&watcher_list);
|
list_init(&watcher_list);
|
||||||
@@ -938,8 +937,8 @@ Team::CPUTime(bool ignoreCurrentRun, Thread* lockedThread) const
|
|||||||
Thread* currentThread = thread_get_current_thread();
|
Thread* currentThread = thread_get_current_thread();
|
||||||
bigtime_t now = system_time();
|
bigtime_t now = system_time();
|
||||||
|
|
||||||
for (Thread* thread = thread_list; thread != NULL;
|
for (Thread* thread = thread_list.First(); thread != NULL;
|
||||||
thread = thread->team_next) {
|
thread = thread_list.GetNext(thread)) {
|
||||||
bool alreadyLocked = thread == lockedThread;
|
bool alreadyLocked = thread == lockedThread;
|
||||||
SpinLocker threadTimeLocker(thread->time_lock, alreadyLocked);
|
SpinLocker threadTimeLocker(thread->time_lock, alreadyLocked);
|
||||||
time += thread->kernel_time + thread->user_time;
|
time += thread->kernel_time + thread->user_time;
|
||||||
@@ -970,8 +969,8 @@ Team::UserCPUTime() const
|
|||||||
|
|
||||||
bigtime_t now = system_time();
|
bigtime_t now = system_time();
|
||||||
|
|
||||||
for (Thread* thread = thread_list; thread != NULL;
|
for (Thread* thread = thread_list.First(); thread != NULL;
|
||||||
thread = thread->team_next) {
|
thread = thread_list.GetNext(thread)) {
|
||||||
SpinLocker threadTimeLocker(thread->time_lock);
|
SpinLocker threadTimeLocker(thread->time_lock);
|
||||||
time += thread->user_time;
|
time += thread->user_time;
|
||||||
|
|
||||||
@@ -1161,7 +1160,7 @@ _dump_team_info(Team* team)
|
|||||||
(void*)team->user_data, team->user_data_area);
|
(void*)team->user_data, team->user_data_area);
|
||||||
kprintf("free user thread: %p\n", team->free_user_threads);
|
kprintf("free user thread: %p\n", team->free_user_threads);
|
||||||
kprintf("main_thread: %p\n", team->main_thread);
|
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("group_id: %" B_PRId32 "\n", team->group_id);
|
||||||
kprintf("session_id: %" B_PRId32 "\n", team->session_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();
|
debugInfoLocker.Unlock();
|
||||||
|
|
||||||
for (Thread* thread = team->thread_list; thread != NULL;
|
for (Thread* thread = team->thread_list.First(); thread != NULL;
|
||||||
thread = thread->team_next) {
|
thread = team->thread_list.GetNext(thread)) {
|
||||||
if (thread != team->main_thread && thread->id != nubThreadID)
|
if (thread != team->main_thread && thread->id != nubThreadID)
|
||||||
return B_NOT_ALLOWED;
|
return B_NOT_ALLOWED;
|
||||||
}
|
}
|
||||||
@@ -2785,9 +2784,8 @@ common_get_team_usage_info(team_id id, int32 who, team_usage_info* info,
|
|||||||
switch (who) {
|
switch (who) {
|
||||||
case B_TEAM_USAGE_SELF:
|
case B_TEAM_USAGE_SELF:
|
||||||
{
|
{
|
||||||
Thread* thread = team->thread_list;
|
for (Thread* thread = team->thread_list.First(); thread != NULL;
|
||||||
|
thread = team->thread_list.GetNext(thread)) {
|
||||||
for (; thread != NULL; thread = thread->team_next) {
|
|
||||||
InterruptsSpinLocker threadTimeLocker(thread->time_lock);
|
InterruptsSpinLocker threadTimeLocker(thread->time_lock);
|
||||||
kernelTime += thread->kernel_time;
|
kernelTime += thread->kernel_time;
|
||||||
userTime += thread->user_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)) {
|
for (; child != NULL; child = team->children.GetNext(child)) {
|
||||||
TeamLocker childLocker(child);
|
TeamLocker childLocker(child);
|
||||||
|
|
||||||
Thread* thread = child->thread_list;
|
for (Thread* thread = child->thread_list.First(); thread != NULL;
|
||||||
|
thread = child->thread_list.GetNext(thread)) {
|
||||||
for (; thread != NULL; thread = thread->team_next) {
|
|
||||||
InterruptsSpinLocker threadTimeLocker(thread->time_lock);
|
InterruptsSpinLocker threadTimeLocker(thread->time_lock);
|
||||||
kernelTime += thread->kernel_time;
|
kernelTime += thread->kernel_time;
|
||||||
userTime += thread->user_time;
|
userTime += thread->user_time;
|
||||||
@@ -3236,15 +3233,13 @@ team_shutdown_team(Team* team)
|
|||||||
team->death_entry = &deathEntry;
|
team->death_entry = &deathEntry;
|
||||||
deathEntry.remaining_threads = 0;
|
deathEntry.remaining_threads = 0;
|
||||||
|
|
||||||
Thread* thread = team->thread_list;
|
for (Thread* thread = team->thread_list.First(); thread != NULL;
|
||||||
while (thread != NULL) {
|
thread = team->thread_list.GetNext(thread)) {
|
||||||
if (thread != team->main_thread) {
|
if (thread != team->main_thread) {
|
||||||
Signal signal(SIGKILLTHR, SI_USER, B_OK, team->id);
|
Signal signal(SIGKILLTHR, SI_USER, B_OK, team->id);
|
||||||
send_signal_to_thread(thread, signal, B_DO_NOT_RESCHEDULE);
|
send_signal_to_thread(thread, signal, B_DO_NOT_RESCHEDULE);
|
||||||
deathEntry.remaining_threads++;
|
deathEntry.remaining_threads++;
|
||||||
}
|
}
|
||||||
|
|
||||||
thread = thread->team_next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deathEntry.remaining_threads == 0)
|
if (deathEntry.remaining_threads == 0)
|
||||||
@@ -3255,9 +3250,7 @@ team_shutdown_team(Team* team)
|
|||||||
deathEntry.condition.Add(&entry);
|
deathEntry.condition.Add(&entry);
|
||||||
|
|
||||||
teamLocker.Unlock();
|
teamLocker.Unlock();
|
||||||
|
|
||||||
entry.Wait();
|
entry.Wait();
|
||||||
|
|
||||||
teamLocker.Lock();
|
teamLocker.Lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -264,7 +264,6 @@ Thread::Thread(const char* name, thread_id threadID, struct cpu_ent* cpu)
|
|||||||
flags(0),
|
flags(0),
|
||||||
serial_number(-1),
|
serial_number(-1),
|
||||||
hash_next(NULL),
|
hash_next(NULL),
|
||||||
team_next(NULL),
|
|
||||||
priority(-1),
|
priority(-1),
|
||||||
io_priority(-1),
|
io_priority(-1),
|
||||||
cpu(cpu),
|
cpu(cpu),
|
||||||
@@ -708,8 +707,7 @@ ThreadCreationAttributes::InitFromUserAttributes(
|
|||||||
static void
|
static void
|
||||||
insert_thread_into_team(Team *team, Thread *thread)
|
insert_thread_into_team(Team *team, Thread *thread)
|
||||||
{
|
{
|
||||||
thread->team_next = team->thread_list;
|
team->thread_list.Add(thread, false);
|
||||||
team->thread_list = thread;
|
|
||||||
team->num_threads++;
|
team->num_threads++;
|
||||||
|
|
||||||
if (team->num_threads == 1) {
|
if (team->num_threads == 1) {
|
||||||
@@ -727,20 +725,8 @@ insert_thread_into_team(Team *team, Thread *thread)
|
|||||||
static void
|
static void
|
||||||
remove_thread_from_team(Team *team, Thread *thread)
|
remove_thread_from_team(Team *team, Thread *thread)
|
||||||
{
|
{
|
||||||
Thread *temp, *last = NULL;
|
team->thread_list.Remove(thread);
|
||||||
|
|
||||||
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--;
|
team->num_threads--;
|
||||||
break;
|
|
||||||
}
|
|
||||||
last = temp;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1874,7 +1860,7 @@ _dump_thread_info(Thread *thread, bool shortInfo)
|
|||||||
kprintf("serial_number: %" B_PRId64 "\n", thread->serial_number);
|
kprintf("serial_number: %" B_PRId64 "\n", thread->serial_number);
|
||||||
kprintf("name: \"%s\"\n", thread->name);
|
kprintf("name: \"%s\"\n", thread->name);
|
||||||
kprintf("hash_next: %p\nteam_next: %p\n",
|
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",
|
kprintf("priority: %" B_PRId32 " (I/O: %" B_PRId32 ")\n",
|
||||||
thread->priority, thread->io_priority);
|
thread->priority, thread->io_priority);
|
||||||
kprintf("state: %s\n", state_to_text(thread, thread->state));
|
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).
|
// 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
|
// 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.
|
// kernel team, to which threads are added when they are dying.
|
||||||
for (Thread* next = team->thread_list; next != NULL;
|
for (Thread* next = team->thread_list.First(); next != NULL;
|
||||||
next = next->team_next) {
|
next = team->thread_list.GetNext(next)) {
|
||||||
if (next->id <= lastID)
|
if (next->id <= lastID)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user