diff --git a/kernel/memory.cpp b/kernel/memory.cpp index 7a02bee..4fb3728 100644 --- a/kernel/memory.cpp +++ b/kernel/memory.cpp @@ -1688,7 +1688,7 @@ void MMBalanceThread() { // For every memory region... MMSpace *space = process->vmm; - GetCurrentThread()->SetAddressSpace(space); + scheduler.SetTemporaryAddressSpace(space); KMutexAcquire(&space->reserveMutex); LinkedItem *item = pmm.nextRegionToBalance ? &pmm.nextRegionToBalance->itemNonGuard : space->usedRegionsNonGuard.firstItem; @@ -1746,7 +1746,7 @@ void MMBalanceThread() { } KMutexRelease(&space->reserveMutex); - GetCurrentThread()->SetAddressSpace(nullptr); + scheduler.SetTemporaryAddressSpace(nullptr); CloseHandleToObject(process, KERNEL_OBJECT_PROCESS); } } diff --git a/kernel/scheduler.cpp b/kernel/scheduler.cpp index 8f2c43c..8b2e6b6 100644 --- a/kernel/scheduler.cpp +++ b/kernel/scheduler.cpp @@ -30,24 +30,19 @@ enum ThreadTerminatableState : int8_t { }; struct Thread { - void SetAddressSpace(MMSpace *space); // Set a temporary address space for the thread. - // Used by the asynchronous task threads, - // and the memory manager's balancer. - // ** Must be the first item in the structure; see MMArchSafeCopy. ** bool inSafeCopy; - LinkedItem item; // Entry in relevent thread queue or blockedThreads list for mutexes/writer locks. - LinkedItem allItem; // Entry in the allThreads list. - LinkedItem processItem; // Entry in the process's list of threads. - LinkedItem *blockedItems; // Entries in the blockedThreads lists for events (not mutexes). + LinkedItem item; // Entry in relevent thread queue or blockedThreads list for mutexes/writer locks. + LinkedItem allItem; // Entry in the allThreads list. + LinkedItem processItem; // Entry in the process's list of threads. struct Process *process; EsObjectID id; volatile uintptr_t cpuTimeSlices; volatile size_t handles; - int executingProcessorID; + uint32_t executingProcessorID; uintptr_t userStackBase; uintptr_t kernelStackBase; @@ -65,7 +60,7 @@ struct Thread { volatile ThreadTerminatableState terminatableState; volatile bool executing; volatile bool terminating; // Set when a request to terminate the thread has been registered. - volatile bool paused; // Set to pause a thread, usually when it has crashed or being debugged. The scheduler will skip threads marked as paused when deciding what to run. + volatile bool paused; // Set to pause a thread. Paused threads are not executed (unless the terminatableState prevents that). volatile bool receivedYieldIPI; // Used to terminate a thread executing on a different processor. union { @@ -77,6 +72,7 @@ struct Thread { }; struct { + LinkedItem *eventItems; // Entries in the blockedThreads lists (one per event). KEvent *volatile events[ES_MAX_WAIT_COUNT]; volatile size_t eventCount; }; @@ -214,6 +210,9 @@ struct Scheduler { void WaitMutex(KMutex *mutex); uintptr_t WaitEvents(KEvent **events, size_t count); // Returns index of notified object. + // Set a temporary address space for the current thread. Used by some asynchronous tasks, and the memory manager's balancer. + void SetTemporaryAddressSpace(MMSpace *space); + void Shutdown(); // Internal functions: @@ -500,7 +499,7 @@ Thread *Scheduler::SpawnThread(const char *cName, uintptr_t startAddress, uintpt void _RemoveProcess(KAsyncTask *task) { Process *process = EsContainerOf(Process, removeAsyncTask, task); - GetCurrentThread()->SetAddressSpace(process->vmm); + scheduler.SetTemporaryAddressSpace(process->vmm); scheduler.RemoveProcess(process); } @@ -578,7 +577,7 @@ void KillProcess(Process *process) { void KillThread(KAsyncTask *task) { Thread *thread = EsContainerOf(Thread, killAsyncTask, task); - GetCurrentThread()->SetAddressSpace(thread->process->vmm); + scheduler.SetTemporaryAddressSpace(thread->process->vmm); KMutexAcquire(&scheduler.allThreadsMutex); scheduler.allThreads.Remove(&thread->allItem); @@ -923,18 +922,15 @@ Process *Scheduler::SpawnProcess(ProcessType processType) { return process; } -void Thread::SetAddressSpace(MMSpace *space) { - if (this != GetCurrentThread()) { - KernelPanic("Thread::SetAddressSpace - Cannot change another thread's address space.\n"); - } - - KSpinlockAcquire(&scheduler.lock); - MMSpace *oldSpace = temporaryAddressSpace ?: kernelMMSpace; - temporaryAddressSpace = space; +void Scheduler::SetTemporaryAddressSpace(MMSpace *space) { + KSpinlockAcquire(&lock); + Thread *thread = GetCurrentThread(); + MMSpace *oldSpace = thread->temporaryAddressSpace ?: kernelMMSpace; + thread->temporaryAddressSpace = space; MMSpace *newSpace = space ?: kernelMMSpace; MMSpaceOpenReference(newSpace); ProcessorSetAddressSpace(&newSpace->data); - KSpinlockRelease(&scheduler.lock); + KSpinlockRelease(&lock); MMSpaceCloseReference(oldSpace); } @@ -954,7 +950,7 @@ void AsyncTaskThread() { item->Remove(); KSpinlockRelease(&asyncTaskSpinlock); callback(task); // This may cause the task to be deallocated. - local->currentThread->SetAddressSpace(nullptr); // The task may have modified the address space. + scheduler.SetTemporaryAddressSpace(nullptr); // The task may have modified the address space. local->inAsyncTask = false; } } @@ -1250,7 +1246,7 @@ void Scheduler::Yield(InterruptContext *context) { if (!unblocked) { for (uintptr_t i = 0; i < local->currentThread->blocking.eventCount; i++) { - local->currentThread->blocking.events[i]->blockedThreads.InsertEnd(&local->currentThread->blockedItems[i]); + local->currentThread->blocking.events[i]->blockedThreads.InsertEnd(&local->currentThread->blocking.eventItems[i]); } } } @@ -1278,26 +1274,31 @@ void Scheduler::Yield(InterruptContext *context) { } } - // Notify any triggered timers. - - LinkedItem *_timer = activeTimers.firstItem; + if (!local->processorID) { + // Update the scheduler's time. + timeMs = ArchGetTimeMs(); + globalData->schedulerTimeMs = timeMs; - while (_timer) { - KTimer *timer = _timer->thisItem; - LinkedItem *next = _timer->nextItem; + // Notify the necessary timers. + LinkedItem *_timer = activeTimers.firstItem; - if (timer->triggerTimeMs <= timeMs) { - activeTimers.Remove(_timer); - KEventSet(&timer->event, true /* scheduler already locked */); + while (_timer) { + KTimer *timer = _timer->thisItem; + LinkedItem *next = _timer->nextItem; - if (timer->callback) { - KRegisterAsyncTask(&timer->asyncTask, timer->callback); + if (timer->triggerTimeMs <= timeMs) { + activeTimers.Remove(_timer); + KEventSet(&timer->event, true /* scheduler already locked */); + + if (timer->callback) { + KRegisterAsyncTask(&timer->asyncTask, timer->callback); + } + } else { + break; // Timers are kept sorted, so there's no point continuing. } - } else { - break; // Timers are kept sorted, so there's no point continuing. - } - _timer = next; + _timer = next; + } } // Get the next thread to execute. @@ -1322,12 +1323,6 @@ void Scheduler::Yield(InterruptContext *context) { // Prepare the next timer interrupt. ArchNextTimer(1 /* ms */); - if (!local->processorID) { - // Update the scheduler's time. - timeMs = ArchGetTimeMs(); - globalData->schedulerTimeMs = timeMs; - } - InterruptContext *newContext = newThread->interruptContext; MMSpace *addressSpace = newThread->temporaryAddressSpace ?: newThread->process->vmm; MMSpaceOpenReference(addressSpace); diff --git a/kernel/synchronisation.cpp b/kernel/synchronisation.cpp index 915162b..1401e60 100644 --- a/kernel/synchronisation.cpp +++ b/kernel/synchronisation.cpp @@ -666,13 +666,13 @@ uintptr_t Scheduler::WaitEvents(KEvent **events, size_t count) { Thread *thread = GetCurrentThread(); thread->blocking.eventCount = count; - LinkedItem blockedItems[count]; // Max size 16 * 32 = 512. - EsMemoryZero(blockedItems, count * sizeof(LinkedItem)); - thread->blockedItems = blockedItems; - EsDefer(thread->blockedItems = nullptr); + LinkedItem eventItems[count]; // Max size 16 * 32 = 512. + EsMemoryZero(eventItems, count * sizeof(LinkedItem)); + thread->blocking.eventItems = eventItems; + EsDefer(thread->blocking.eventItems = nullptr); for (uintptr_t i = 0; i < count; i++) { - thread->blockedItems[i].thisItem = thread; + eventItems[i].thisItem = thread; thread->blocking.events[i] = events[i]; } @@ -741,8 +741,8 @@ void Scheduler::UnblockThread(Thread *unblockedThread, Thread *previousMutexOwne } } else if (unblockedThread->state == THREAD_WAITING_EVENT) { for (uintptr_t i = 0; i < unblockedThread->blocking.eventCount; i++) { - if (unblockedThread->blockedItems[i].list) { - unblockedThread->blockedItems[i].RemoveFromList(); + if (unblockedThread->blocking.eventItems[i].list) { + unblockedThread->blocking.eventItems[i].RemoveFromList(); } } } else if (unblockedThread->state == THREAD_WAITING_WRITER_LOCK) {