lockless thread/process handle counting and id assignment

This commit is contained in:
nakst 2021-11-07 18:35:31 +00:00
parent a2c6737bf5
commit 7f928c523f
5 changed files with 40 additions and 45 deletions

View File

@ -1678,7 +1678,7 @@ void MMBalanceThread() {
pmm.nextProcessToBalance = process->allItem.nextItem ? process->allItem.nextItem->thisItem : nullptr; pmm.nextProcessToBalance = process->allItem.nextItem ? process->allItem.nextItem->thisItem : nullptr;
if (process->handles) { if (process->handles) {
process->handles++; OpenHandleToObject(process, KERNEL_OBJECT_PROCESS, ES_FLAGS_DEFAULT);
break; break;
} }
} }

View File

@ -196,7 +196,7 @@ enum KernelObjectType : uint32_t {
// TODO Rename to KObjectReference and KObjectDereference? // TODO Rename to KObjectReference and KObjectDereference?
void CloseHandleToObject(void *object, KernelObjectType type, uint32_t flags = 0); void CloseHandleToObject(void *object, KernelObjectType type, uint32_t flags = 0);
bool OpenHandleToObject(void *object, KernelObjectType type, uint32_t flags = 0, bool maybeHasNoHandles = false); bool OpenHandleToObject(void *object, KernelObjectType type, uint32_t flags = 0);
// --------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------------
// Module loading. // Module loading.

View File

@ -103,7 +103,7 @@ KMutex objectHandleCountChange;
// TODO Use uint64_t for handle counts, or restrict OpenHandleToObject to some maximum (...but most callers don't check if OpenHandleToObject succeeds). // TODO Use uint64_t for handle counts, or restrict OpenHandleToObject to some maximum (...but most callers don't check if OpenHandleToObject succeeds).
bool OpenHandleToObject(void *object, KernelObjectType type, uint32_t flags, bool maybeHasNoHandles) { bool OpenHandleToObject(void *object, KernelObjectType type, uint32_t flags) {
bool hadNoHandles = false, failed = false; bool hadNoHandles = false, failed = false;
switch (type) { switch (type) {
@ -116,20 +116,11 @@ bool OpenHandleToObject(void *object, KernelObjectType type, uint32_t flags, boo
} break; } break;
case KERNEL_OBJECT_PROCESS: { case KERNEL_OBJECT_PROCESS: {
KSpinlockAcquire(&scheduler.lock); hadNoHandles = 0 == __sync_fetch_and_add(&((Process *) object)->handles, 1);
Process *process = (Process *) object;
if (!process->handles) hadNoHandles = true;
else process->handles++; // NOTE Scheduler::OpenProcess and MMBalanceThread also adjust process handles.
KernelLog(LOG_VERBOSE, "Scheduler", "open process handle", "Opened handle to process %d; %d handles.\n", process->id, process->handles);
KSpinlockRelease(&scheduler.lock);
} break; } break;
case KERNEL_OBJECT_THREAD: { case KERNEL_OBJECT_THREAD: {
KSpinlockAcquire(&scheduler.lock); hadNoHandles = 0 == __sync_fetch_and_add(&((Thread *) object)->handles, 1);
Thread *thread = (Thread *) object;
if (!thread->handles) hadNoHandles = true;
else thread->handles++;
KSpinlockRelease(&scheduler.lock);
} break; } break;
case KERNEL_OBJECT_SHMEM: { case KERNEL_OBJECT_SHMEM: {
@ -208,11 +199,7 @@ bool OpenHandleToObject(void *object, KernelObjectType type, uint32_t flags, boo
} }
if (hadNoHandles) { if (hadNoHandles) {
if (maybeHasNoHandles) { KernelPanic("OpenHandleToObject - Object %x of type %x had no handles.\n", object, type);
return false;
} else {
KernelPanic("OpenHandleToObject - Object %x of type %x had no handles.\n", object, type);
}
} }
return !failed; return !failed;
@ -225,15 +212,12 @@ void CloseHandleToObject(void *object, KernelObjectType type, uint32_t flags) {
} break; } break;
case KERNEL_OBJECT_THREAD: { case KERNEL_OBJECT_THREAD: {
KSpinlockAcquire(&scheduler.lock);
Thread *thread = (Thread *) object; Thread *thread = (Thread *) object;
if (!thread->handles) KernelPanic("CloseHandleToObject - All handles to thread %x have been closed.\n", thread); uintptr_t previous = __sync_fetch_and_sub(&thread->handles, 1);
thread->handles--;
bool removeThread = thread->handles == 0;
// EsPrint("Thread %d has %d handles\n", thread->id, thread->handles);
KSpinlockRelease(&scheduler.lock);
if (removeThread) { if (previous == 0) {
KernelPanic("CloseHandleToObject - All handles to thread %x have been closed.\n", thread);
} else if (previous == 1) {
scheduler.RemoveThread(thread); scheduler.RemoveThread(thread);
} }
} break; } break;

View File

@ -232,26 +232,28 @@ struct Scheduler {
// Variables: // Variables:
KSpinlock lock; KSpinlock lock; // The general lock. TODO Break this up!
KMutex allThreadsMutex; // For accessing the allThreads list.
KEvent killedEvent; // Set during shutdown when all processes have been terminated. KEvent killedEvent; // Set during shutdown when all processes have been terminated.
uintptr_t blockShutdownProcessCount; uintptr_t blockShutdownProcessCount;
size_t activeProcessCount;
LinkedList<Thread> activeThreads[THREAD_PRIORITY_COUNT], pausedThreads;
LinkedList<KTimer> activeTimers;
Pool threadPool, processPool, mmSpacePool; Pool threadPool, processPool, mmSpacePool;
LinkedList<Thread> activeThreads[THREAD_PRIORITY_COUNT];
LinkedList<Thread> pausedThreads;
LinkedList<KTimer> activeTimers;
LinkedList<Thread> allThreads; LinkedList<Thread> allThreads;
LinkedList<Process> allProcesses; LinkedList<Process> allProcesses;
EsObjectID nextThreadID;
EsObjectID nextProcessID;
size_t activeProcessCount;
volatile bool started, panic, shutdown; volatile bool started, panic, shutdown;
uint64_t timeMs; uint64_t timeMs;
uint32_t currentProcessorID; EsObjectID nextThreadID;
EsObjectID nextProcessID;
EsObjectID nextProcessorID;
#ifdef DEBUG_BUILD #ifdef DEBUG_BUILD
EsThreadEventLogEntry *volatile threadEventLog; EsThreadEventLogEntry *volatile threadEventLog;
@ -371,15 +373,19 @@ void Scheduler::MaybeUpdateActiveList(Thread *thread) {
} }
void Scheduler::InsertNewThread(Thread *thread, bool addToActiveList, Process *owner) { void Scheduler::InsertNewThread(Thread *thread, bool addToActiveList, Process *owner) {
KMutexAcquire(&allThreadsMutex);
allThreads.InsertStart(&thread->allItem);
KMutexRelease(&allThreadsMutex);
KSpinlockAcquire(&lock); KSpinlockAcquire(&lock);
EsDefer(KSpinlockRelease(&lock));
// New threads are initialised here. // New threads are initialised here.
thread->id = __sync_fetch_and_add(&nextThreadID, 1); thread->id = __sync_fetch_and_add(&nextThreadID, 1);
thread->process = owner; thread->process = owner;
owner->handles++; // Each thread owns a handles to the owner process. // Each thread owns a handles to the owner process.
// This makes sure the process isn't destroyed before all its threads have been destroyed. // This makes sure the process isn't destroyed before all its threads have been destroyed.
OpenHandleToObject(owner, KERNEL_OBJECT_PROCESS, ES_FLAGS_DEFAULT);
thread->item.thisItem = thread; thread->item.thisItem = thread;
thread->allItem.thisItem = thread; thread->allItem.thisItem = thread;
@ -395,7 +401,8 @@ void Scheduler::InsertNewThread(Thread *thread, bool addToActiveList, Process *o
// Some threads (such as idle threads) do this themselves. // Some threads (such as idle threads) do this themselves.
} }
allThreads.InsertStart(&thread->allItem); KSpinlockRelease(&lock);
// The thread may now be terminated at any moment.
} }
Thread *Scheduler::SpawnThread(const char *cName, uintptr_t startAddress, uintptr_t argument1, uint32_t flags, Process *process, uintptr_t argument2) { Thread *Scheduler::SpawnThread(const char *cName, uintptr_t startAddress, uintptr_t argument1, uint32_t flags, Process *process, uintptr_t argument2) {
@ -490,10 +497,11 @@ void _RemoveProcess(KAsyncTask *task) {
void CloseHandleToProcess(void *_process) { void CloseHandleToProcess(void *_process) {
KSpinlockAcquire(&scheduler.lock); KSpinlockAcquire(&scheduler.lock);
Process *process = (Process *) _process; Process *process = (Process *) _process;
if (!process->handles) KernelPanic("CloseHandleToProcess - All handles to the process have been closed.\n"); uintptr_t previous = __sync_fetch_and_sub(&process->handles, 1);
process->handles--; if (!previous) KernelPanic("CloseHandleToProcess - All handles to process %x have been closed.\n", process);
bool removeProcess = !process->handles; bool removeProcess = previous == 1;
KernelLog(LOG_VERBOSE, "Scheduler", "close process handle", "Closed handle to process %d; %d handles remain.\n", process->id, process->handles); KernelLog(LOG_VERBOSE, "Scheduler", "close process handle", "Closed handle to process %d; %d handles remain.\n", process->id, process->handles);
@ -561,8 +569,11 @@ void KillThread(KAsyncTask *task) {
Thread *thread = EsContainerOf(Thread, killAsyncTask, task); Thread *thread = EsContainerOf(Thread, killAsyncTask, task);
GetCurrentThread()->SetAddressSpace(thread->process->vmm); GetCurrentThread()->SetAddressSpace(thread->process->vmm);
KSpinlockAcquire(&scheduler.lock); KMutexAcquire(&scheduler.allThreadsMutex);
scheduler.allThreads.Remove(&thread->allItem); scheduler.allThreads.Remove(&thread->allItem);
KMutexRelease(&scheduler.allThreadsMutex);
KSpinlockAcquire(&scheduler.lock);
thread->process->threads.Remove(&thread->processItem); thread->process->threads.Remove(&thread->processItem);
KernelLog(LOG_INFO, "Scheduler", "killing thread", KernelLog(LOG_INFO, "Scheduler", "killing thread",
@ -954,7 +965,7 @@ void Scheduler::CreateProcessorThreads(CPULocalStorage *local) {
idleThread->terminatableState = THREAD_IN_SYSCALL; idleThread->terminatableState = THREAD_IN_SYSCALL;
idleThread->cName = "Idle"; idleThread->cName = "Idle";
local->currentThread = local->idleThread = idleThread; local->currentThread = local->idleThread = idleThread;
local->processorID = __sync_fetch_and_add(&currentProcessorID, 1); local->processorID = __sync_fetch_and_add(&nextProcessorID, 1);
if (local->processorID >= K_MAX_PROCESSORS) { if (local->processorID >= K_MAX_PROCESSORS) {
KernelPanic("Scheduler::CreateProcessorThreads - Maximum processor count (%d) exceeded.\n", local->processorID); KernelPanic("Scheduler::CreateProcessorThreads - Maximum processor count (%d) exceeded.\n", local->processorID);
@ -1375,7 +1386,7 @@ Process *Scheduler::OpenProcess(uint64_t id) {
if (process->id == id if (process->id == id
&& process->handles /* if the process has no handles, it's about to be removed */ && process->handles /* if the process has no handles, it's about to be removed */
&& process->type != PROCESS_KERNEL /* the kernel process cannot be opened */) { && process->type != PROCESS_KERNEL /* the kernel process cannot be opened */) {
process->handles++; OpenHandleToObject(process, KERNEL_OBJECT_PROCESS, ES_FLAGS_DEFAULT);
break; break;
} }

View File

@ -1311,7 +1311,7 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_SYSTEM_TAKE_SNAPSHOT) {
} }
SYSCALL_IMPLEMENT(ES_SYSCALL_PROCESSOR_COUNT) { SYSCALL_IMPLEMENT(ES_SYSCALL_PROCESSOR_COUNT) {
SYSCALL_RETURN(scheduler.currentProcessorID, false); SYSCALL_RETURN(scheduler.nextProcessorID, false);
} }
SYSCALL_IMPLEMENT(ES_SYSCALL_PROCESS_OPEN) { SYSCALL_IMPLEMENT(ES_SYSCALL_PROCESS_OPEN) {