simplify async tasks

This commit is contained in:
nakst 2021-11-06 16:15:12 +00:00
parent f7894f74a6
commit ee4a0e7a05
9 changed files with 197 additions and 222 deletions

View File

@ -14,10 +14,12 @@ struct ACPIThermalZone : KDevice {
uint64_t pollingFrequency; // Recommended polling frequency of temperature, in tenths of a seconds.
uint64_t currentTemperature;
KMutex refreshMutex;
KAsyncTask refreshTemperatureAsyncTask;
KAsyncTask refreshThresholdsAsyncTask;
};
static void ACPIThermalRefreshTemperature(EsGeneric context) {
ACPIThermalZone *device = (ACPIThermalZone *) context.p;
static void ACPIThermalRefreshTemperature(KAsyncTask *task) {
ACPIThermalZone *device = EsContainerOf(ACPIThermalZone, refreshTemperatureAsyncTask, task);
KACPIObject *object = device->object;
KMutexAcquire(&device->refreshMutex);
KernelLog(LOG_INFO, "ACPIThermal", "temperature", "Taking temperature reading...\n");
@ -31,8 +33,8 @@ static void ACPIThermalRefreshTemperature(EsGeneric context) {
KMutexRelease(&device->refreshMutex);
}
static void ACPIThermalRefreshThresholds(EsGeneric context) {
ACPIThermalZone *device = (ACPIThermalZone *) context.p;
static void ACPIThermalRefreshThresholds(KAsyncTask *task) {
ACPIThermalZone *device = EsContainerOf(ACPIThermalZone, refreshThresholdsAsyncTask, task);
KACPIObject *object = device->object;
KMutexAcquire(&device->refreshMutex);
KernelLog(LOG_INFO, "ACPIThermal", "threshold", "Taking threshold readings...\n");
@ -60,16 +62,16 @@ static void ACPIThermalRefreshThresholds(EsGeneric context) {
}
KMutexRelease(&device->refreshMutex);
ACPIThermalRefreshTemperature(device);
ACPIThermalRefreshTemperature(&device->refreshTemperatureAsyncTask);
}
static void ACPIThermalDeviceNotificationHandler(KACPIObject *, uint32_t value, EsGeneric context) {
ACPIThermalZone *device = (ACPIThermalZone *) context.p;
if (value == 0x80) {
KRegisterAsyncTask(ACPIThermalRefreshTemperature, device);
KRegisterAsyncTask(&device->refreshTemperatureAsyncTask, ACPIThermalRefreshTemperature);
} else if (value == 0x81) {
KRegisterAsyncTask(ACPIThermalRefreshThresholds, device);
KRegisterAsyncTask(&device->refreshThresholdsAsyncTask, ACPIThermalRefreshThresholds);
}
}
@ -80,7 +82,7 @@ static void ACPIThermalDeviceAttach(KDevice *parent) {
device->object = object;
KernelLog(LOG_INFO, "ACPIThermal", "device attached", "Found ACPI thermal zone.\n");
ACPIThermalRefreshThresholds(device);
ACPIThermalRefreshThresholds(&device->refreshThresholdsAsyncTask);
EsError error;

View File

@ -20,6 +20,7 @@ uint8_t acpicaPageBuffer[K_PAGE_SIZE];
KMutex acpicaPageBufferMutex;
char acpiPrintf[4096];
bool acpiOSLayerActive = false;
KAsyncTask powerButtonAsyncTask;
ES_EXTERN_C ACPI_STATUS AcpiOsInitialize() {
if (acpiOSLayerActive) KernelPanic("AcpiOsInitialize - ACPI has already been initialised.\n");
@ -419,11 +420,11 @@ ES_EXTERN_C ACPI_STATUS AcpiOsEnterSleep(UINT8 sleepState, UINT32 registerAValue
}
UINT32 ACPIPowerButtonPressed(void *) {
KRegisterAsyncTask([] (EsGeneric) {
KRegisterAsyncTask(&powerButtonAsyncTask, [] (KAsyncTask *) {
_EsMessageWithObject m = { nullptr, ES_MSG_POWER_BUTTON_PRESSED };
if (scheduler.shutdown) return;
if (desktopProcess) desktopProcess->messageQueue.SendMessage(&m);
}, nullptr, false);
});
return 0;
}

View File

@ -410,8 +410,8 @@ bool AHCIController::HandleIRQ() {
return true;
}
void TimeoutTimerHit(EsGeneric argument) {
AHCIController *controller = (AHCIController *) argument.p;
void TimeoutTimerHit(KAsyncTask *task) {
AHCIController *controller = EsContainerOf(AHCIController, timeoutTimer.asyncTask, task);
uint64_t currentTimeStamp = KGetTimeInMs();

View File

@ -4,6 +4,8 @@
#include <arch/x86_pc.h>
struct PS2Update {
KAsyncTask task;
union {
struct {
volatile int xMovement, yMovement, zMovement;
@ -193,8 +195,8 @@ uint16_t scancodeConversionTable2[] = {
#define PS2_MOUSE_READ (0xEB)
#define PS2_MOUSE_RESOLUTION (0xE8)
void PS2MouseUpdated(EsGeneric _update) {
PS2Update *update = (PS2Update *) _update.p;
void PS2MouseUpdated(KAsyncTask *task) {
PS2Update *update = EsContainerOf(PS2Update, task, task);
KMouseUpdateData data = {
.xMovement = update->xMovement * K_CURSOR_MOVEMENT_SCALE,
@ -206,8 +208,8 @@ void PS2MouseUpdated(EsGeneric _update) {
KMouseUpdate(&data);
}
void PS2KeyboardUpdated(EsGeneric _update) {
PS2Update *update = (PS2Update *) _update.p;
void PS2KeyboardUpdated(KAsyncTask *task) {
PS2Update *update = EsContainerOf(PS2Update, task, task);
KernelLog(LOG_VERBOSE, "PS/2", "keyboard update", "Received scancode %x.\n", update->scancode);
KKeyPress(update->scancode);
}
@ -349,7 +351,7 @@ bool PS2IRQHandler(uintptr_t interruptIndex, void *) {
| ((firstByte & (1 << 2)) ? K_MIDDLE_BUTTON : 0);
update->zMovement = -((int8_t) fourthByte);
KRegisterAsyncTask(PS2MouseUpdated, update, false);
KRegisterAsyncTask(&update->task, PS2MouseUpdated);
firstByte = 0;
secondByte = 0;
@ -366,7 +368,7 @@ bool PS2IRQHandler(uintptr_t interruptIndex, void *) {
ps2.lastUpdatesIndex = (ps2.lastUpdatesIndex + 1) % 16;
KSpinlockRelease(&ps2.lastUpdatesLock);
update->scancode = scancode;
KRegisterAsyncTask(PS2KeyboardUpdated, update, false);
KRegisterAsyncTask(&update->task, PS2KeyboardUpdated);
}
} else {
KernelPanic("PS2IRQHandler - Incorrect interrupt index.\n", interruptIndex);

View File

@ -99,6 +99,7 @@ struct XHCIEndpoint {
KUSBTransferCallback callback;
EsGeneric context;
KAsyncTask callbackAsyncTask;
bool CreateTransferRing();
@ -645,12 +646,12 @@ bool XHCIController::HandleIRQ() {
}
if (endpoint->callback) {
KRegisterAsyncTask([] (EsGeneric argument) {
XHCIEndpoint *endpoint = (XHCIEndpoint *) argument.p;
KRegisterAsyncTask(&endpoint->callbackAsyncTask, [] (KAsyncTask *task) {
XHCIEndpoint *endpoint = EsContainerOf(XHCIEndpoint, callbackAsyncTask, task);
KUSBTransferCallback callback = endpoint->callback;
endpoint->callback = nullptr;
callback((endpoint->lastStatus >> 24) != 1 ? -1 : endpoint->lastStatus & 0xFFFFFF, endpoint->context);
}, endpoint, true);
});
}
break;

View File

@ -70,30 +70,19 @@
#include ARCH_KERNEL_SOURCE
struct AsyncTask {
KAsyncTaskCallback callback;
void *argument;
struct MMSpace *addressSpace;
};
struct CPULocalStorage {
struct Thread *currentThread,
*idleThread,
*asyncTaskThread;
struct InterruptContext *panicContext;
bool irqSwitchThread, schedulerReady, inIRQ;
unsigned processorID;
size_t spinlockCount;
struct ArchCPU *archCPU;
// TODO Have separate interrupt task threads and system worker threads (with no task limit).
#define MAX_ASYNC_TASKS (256)
volatile AsyncTask asyncTasks[MAX_ASYNC_TASKS];
volatile uint8_t asyncTasksRead, asyncTasksWrite;
struct Thread *currentThread; // The currently executing thread on this CPU.
struct Thread *idleThread; // The CPU's idle thread.
struct Thread *asyncTaskThread; // The CPU's async task thread, used to process the asyncTaskList.
struct InterruptContext *panicContext; // The interrupt context saved from a kernel panic IPI.
bool irqSwitchThread; // The CPU should call Scheduler::Yield after the IRQ handler exits.
bool schedulerReady; // The CPU is ready to execute threads from the pre-emptive scheduler.
bool inIRQ; // The CPU is currently executing an IRQ handler registered with KRegisterIRQ.
bool inAsyncTask; // The CPU is currently executing an asynchronous task.
uint32_t processorID; // The scheduler's ID for the process.
size_t spinlockCount; // The number of spinlocks currently acquired.
struct ArchCPU *archCPU; // The architecture layer's data for the CPU.
SimpleList asyncTaskList; // The list of AsyncTasks to be processed.
};
struct PhysicalMemoryRegion {

View File

@ -82,6 +82,8 @@ struct MMSpace {
bool user; // Regions in the space may be accessed from userspace.
uint64_t commit; // An *approximate* commit in pages. TODO Better memory usage tracking.
uint64_t reserve; // The number of reserved pages.
KAsyncTask removeAsyncTask; // The asynchronous task for deallocating the memory space once it's no longer in use.
};
// A physical page of memory.
@ -2252,11 +2254,11 @@ void MMSpaceCloseReference(MMSpace *space) {
return;
}
KRegisterAsyncTask([] (EsGeneric _space) {
MMSpace *space = (MMSpace *) _space.p;
KRegisterAsyncTask(&space->removeAsyncTask, [] (KAsyncTask *task) {
MMSpace *space = EsContainerOf(MMSpace, removeAsyncTask, task);
MMArchFinalizeVAS(space);
scheduler.mmSpacePool.Remove(space);
}, space);
});
}
void MMInitialise() {

View File

@ -102,18 +102,6 @@ struct KMSIInformation {
KMSIInformation KRegisterMSI(KIRQHandler handler, void *context, const char *cOwnerName);
void KUnregisterMSI(uintptr_t tag);
// ---------------------------------------------------------------------------------------------------------------
// Async tasks.
// ---------------------------------------------------------------------------------------------------------------
// Async tasks are executed on the same processor that registered it.
// They can be registered with interrupts disabled (e.g. in IRQ handlers).
// They are executed in the order they were registered.
// They can acquire mutexes, but cannot perform IO.
typedef void (*KAsyncTaskCallback)(EsGeneric argument);
void KRegisterAsyncTask(KAsyncTaskCallback callback, EsGeneric argument, bool needed = true);
// ---------------------------------------------------------------------------------------------------------------
// Common data types, algorithms and things.
// ---------------------------------------------------------------------------------------------------------------
@ -145,6 +133,24 @@ extern "C" uint16_t ProcessorIn16(uint16_t port);
extern "C" void ProcessorOut32(uint16_t port, uint32_t value);
extern "C" uint32_t ProcessorIn32(uint16_t port);
// ---------------------------------------------------------------------------------------------------------------
// Async tasks.
// ---------------------------------------------------------------------------------------------------------------
// Async tasks are executed on the same processor that registered it.
// They can be registered with interrupts disabled (e.g. in IRQ handlers).
// They are executed in the order they were registered.
// They can acquire mutexes, but cannot perform IO.
typedef void (*KAsyncTaskCallback)(struct KAsyncTask *task);
struct KAsyncTask {
SimpleList item;
KAsyncTaskCallback callback;
};
void KRegisterAsyncTask(KAsyncTask *task, KAsyncTaskCallback callback);
// ---------------------------------------------------------------------------------------------------------------
// Kernel core.
// ---------------------------------------------------------------------------------------------------------------
@ -313,6 +319,7 @@ void KSemaphoreSet(KSemaphore *semaphore, uintptr_t units = 1);
struct KTimer {
KEvent event;
KAsyncTask asyncTask;
K_PRIVATE
LinkedItem<KTimer> item;
uint64_t triggerTimeMs;

View File

@ -5,11 +5,6 @@
#define THREAD_PRIORITY_COUNT (2)
void CloseHandleToProcess(void *_thread);
void KillThread(EsGeneric _thread);
void RegisterAsyncTask(KAsyncTaskCallback callback, EsGeneric argument, struct Process *targetProcess,
bool needed /* if false, the task may not be registered if there are many queued tasks */,
bool unlocked = false /* set to true if you haven't acquired the scheduler's lock */);
enum ThreadState : int8_t {
THREAD_ACTIVE, // An active thread. Not necessarily executing; `executing` determines if it executing.
@ -88,6 +83,7 @@ struct Thread {
} blocking;
KEvent killedEvent;
KAsyncTask killAsyncTask;
// If the type of the thread is THREAD_ASYNC_TASK,
// then this is the virtual address space that should be loaded
@ -142,6 +138,7 @@ struct Process {
bool terminating; // This never gets set if TerminateProcess is not called, and instead the process is killed because all its threads exit naturally.
int exitStatus; // TODO Remove this.
KEvent killedEvent;
KAsyncTask removeAsyncTask;
// Executable state:
uint8_t executableState;
@ -266,14 +263,23 @@ struct Scheduler {
Process _kernelProcess;
Process *kernelProcess = &_kernelProcess;
Process *desktopProcess;
extern Scheduler scheduler;
Scheduler scheduler;
KSpinlock asyncTaskSpinlock;
#endif
#ifdef IMPLEMENTATION
Scheduler scheduler;
void KRegisterAsyncTask(KAsyncTask *task, KAsyncTaskCallback callback) {
KSpinlockAcquire(&asyncTaskSpinlock);
if (!task->callback) {
task->callback = callback;
GetLocalStorage()->asyncTaskList.Insert(&task->item, false);
}
KSpinlockRelease(&asyncTaskSpinlock);
}
int8_t Scheduler::GetThreadEffectivePriority(Thread *thread) {
KSpinlockAssertLocked(&lock);
@ -477,6 +483,108 @@ Thread *Scheduler::SpawnThread(const char *cName, uintptr_t startAddress, uintpt
return nullptr;
}
void _RemoveProcess(KAsyncTask *task) {
Process *process = EsContainerOf(Process, removeAsyncTask, task);
GetCurrentThread()->SetAddressSpace(process->vmm);
scheduler.RemoveProcess(process);
}
void CloseHandleToProcess(void *_process) {
KSpinlockAcquire(&scheduler.lock);
Process *process = (Process *) _process;
if (!process->handles) KernelPanic("CloseHandleToProcess - All handles to the process have been closed.\n");
process->handles--;
bool removeProcess = !process->handles;
KernelLog(LOG_VERBOSE, "Scheduler", "close process handle", "Closed handle to process %d; %d handles remain.\n", process->id, process->handles);
if (removeProcess && process->executableStartRequest) {
// This must be done in the correct virtual address space!
KRegisterAsyncTask(&process->removeAsyncTask, _RemoveProcess);
}
KSpinlockRelease(&scheduler.lock);
if (removeProcess && !process->executableStartRequest) {
// The process was never started, so we can't make a RemoveProcess task, because it doesn't have an MMSpace yet.
scheduler.RemoveProcess(process);
}
ProcessorFakeTimerInterrupt(); // Process the asynchronous task.
}
void KillProcess(Process *process) {
KernelLog(LOG_INFO, "Scheduler", "killing process", "Killing process (%d) %x...\n", process->id, process);
process->allThreadsTerminated = true;
scheduler.activeProcessCount--;
bool setProcessKilledEvent = true;
#ifdef ENABLE_POSIX_SUBSYSTEM
if (process->posixForking) {
// If the process is from an incomplete vfork(),
// then the parent process gets to set the killed event
// and the exit status.
setProcessKilledEvent = false;
}
#endif
if (setProcessKilledEvent) {
// We can now also set the killed event on the process.
KEventSet(&process->killedEvent, true);
}
KSpinlockRelease(&scheduler.lock);
// There are no threads left in this process.
// We should destroy the handle table at this point.
// Otherwise, the process might never be freed
// because of a cyclic-dependency.
process->handleTable.Destroy();
// Destroy the virtual memory space.
// Don't actually deallocate it yet though; that is done on an async task queued by RemoveProcess.
// This must be destroyed after the handle table!
MMSpaceDestroy(process->vmm);
// Tell Desktop the process has terminated.
if (!scheduler.shutdown) {
_EsMessageWithObject m;
EsMemoryZero(&m, sizeof(m));
m.message.type = ES_MSG_PROCESS_TERMINATED;
m.message.crash.pid = process->id;
desktopProcess->messageQueue.SendMessage(&m);
}
}
void KillThread(KAsyncTask *task) {
Thread *thread = EsContainerOf(Thread, killAsyncTask, task);
GetCurrentThread()->SetAddressSpace(thread->process->vmm);
KSpinlockAcquire(&scheduler.lock);
scheduler.allThreads.Remove(&thread->allItem);
thread->process->threads.Remove(&thread->processItem);
KernelLog(LOG_INFO, "Scheduler", "killing thread",
"Killing thread (ID %d, %d remain in process %d) %x...\n", thread->id, thread->process->threads.count, thread->process->id, thread);
if (thread->process->threads.count == 0) {
KillProcess(thread->process); // Releases the scheduler's lock.
} else {
KSpinlockRelease(&scheduler.lock);
}
MMFree(kernelMMSpace, (void *) thread->kernelStackBase);
if (thread->userStackBase) MMFree(thread->process->vmm, (void *) thread->userStackBase);
KEventSet(&thread->killedEvent);
// Close the handle that this thread owns of its owner process, and the handle it owns of itself.
CloseHandleToObject(thread->process, KERNEL_OBJECT_PROCESS);
CloseHandleToObject(thread, KERNEL_OBJECT_THREAD);
}
void Scheduler::TerminateProcess(Process *process, int status) {
KSpinlockAcquire(&scheduler.lock);
@ -573,7 +681,7 @@ void Scheduler::TerminateThread(Thread *thread, bool terminatingProcess) {
// The thread is terminatable and it isn't executing.
// Remove it from its queue, and then remove the thread.
thread->item.RemoveFromList();
RegisterAsyncTask(KillThread, thread, thread->process, true);
KRegisterAsyncTask(&thread->killAsyncTask, KillThread);
yield = true;
}
} else if (thread->terminatableState == THREAD_USER_BLOCK_REQUEST) {
@ -823,14 +931,20 @@ void AsyncTaskThread() {
CPULocalStorage *local = GetLocalStorage();
while (true) {
if (local->asyncTasksRead == local->asyncTasksWrite) {
if (!local->asyncTaskList.first) {
ProcessorFakeTimerInterrupt();
} else {
volatile AsyncTask *task = local->asyncTasks + local->asyncTasksRead;
if (task->addressSpace) local->currentThread->SetAddressSpace(task->addressSpace);
task->callback(task->argument);
local->currentThread->SetAddressSpace(nullptr);
local->asyncTasksRead++;
KSpinlockAcquire(&asyncTaskSpinlock);
SimpleList *item = local->asyncTaskList.first;
KAsyncTask *task = EsContainerOf(KAsyncTask, item, item);
KAsyncTaskCallback callback = task->callback;
task->callback = nullptr;
local->inAsyncTask = true;
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.
local->inAsyncTask = false;
}
}
}
@ -862,46 +976,6 @@ void Scheduler::CreateProcessorThreads(CPULocalStorage *local) {
local->asyncTaskThread->type = THREAD_ASYNC_TASK;
}
void RegisterAsyncTask(KAsyncTaskCallback callback, EsGeneric argument, Process *targetProcess, bool needed, bool unlocked) {
if (!unlocked) KSpinlockAssertLocked(&scheduler.lock);
else KSpinlockAcquire(&scheduler.lock);
EsDefer(if (unlocked) KSpinlockRelease(&scheduler.lock));
if (targetProcess == nullptr) {
targetProcess = kernelProcess;
}
CPULocalStorage *local = GetLocalStorage();
int difference = local->asyncTasksWrite - local->asyncTasksRead;
if (difference < 0) difference += MAX_ASYNC_TASKS;
if (difference >= MAX_ASYNC_TASKS / 2 && !needed) {
return;
}
if (difference == MAX_ASYNC_TASKS - 1) {
KernelPanic("RegisterAsyncTask - Maximum number of queued asynchronous tasks reached.\n");
}
// We need to register tasks for terminating processes.
#if 0
if (!targetProcess->handles) {
KernelPanic("RegisterAsyncTask - Process has no handles.\n");
}
#endif
volatile AsyncTask *task = local->asyncTasks + local->asyncTasksWrite;
task->callback = callback;
task->argument = argument.p;
task->addressSpace = targetProcess->vmm;
local->asyncTasksWrite++;
}
void KRegisterAsyncTask(KAsyncTaskCallback callback, EsGeneric argument, bool needed) {
RegisterAsyncTask(callback, argument, kernelProcess, needed, true);
}
void Scheduler::RemoveProcess(Process *process) {
KernelLog(LOG_INFO, "Scheduler", "remove process", "Removing process %d.\n", process->id);
@ -948,11 +1022,8 @@ void Scheduler::RemoveProcess(Process *process) {
// Free the process.
KRegisterAsyncTask([] (EsGeneric _process) {
Process *process = (Process *) _process.p;
MMSpaceCloseReference(process->vmm);
scheduler.processPool.Remove(process);
}, process);
MMSpaceCloseReference(process->vmm);
scheduler.processPool.Remove(process);
if (started) {
// If all processes (except the kernel process) have terminated, set the scheduler's killedEvent.
@ -1106,110 +1177,10 @@ void Scheduler::PauseProcess(Process *process, bool resume) {
}
}
void _RemoveProcess(EsGeneric process) {
scheduler.RemoveProcess((Process *) process.p);
}
void CloseHandleToProcess(void *_process) {
KSpinlockAcquire(&scheduler.lock);
Process *process = (Process *) _process;
if (!process->handles) KernelPanic("CloseHandleToProcess - All handles to the process have been closed.\n");
process->handles--;
bool removeProcess = !process->handles;
KernelLog(LOG_VERBOSE, "Scheduler", "close process handle", "Closed handle to process %d; %d handles remain.\n", process->id, process->handles);
if (removeProcess && process->executableStartRequest) {
// This must be done in the correct virtual address space!
RegisterAsyncTask(_RemoveProcess, process, process, true);
}
KSpinlockRelease(&scheduler.lock);
if (removeProcess && !process->executableStartRequest) {
// The process was never started, so we can't make a RemoveProcess task, because it doesn't have an MMSpace yet.
scheduler.RemoveProcess(process);
}
ProcessorFakeTimerInterrupt(); // Process the asynchronous task.
}
void KillProcess(Process *process) {
KernelLog(LOG_INFO, "Scheduler", "killing process", "Killing process (%d) %x...\n", process->id, process);
process->allThreadsTerminated = true;
scheduler.activeProcessCount--;
bool setProcessKilledEvent = true;
#ifdef ENABLE_POSIX_SUBSYSTEM
if (process->posixForking) {
// If the process is from an incomplete vfork(),
// then the parent process gets to set the killed event
// and the exit status.
setProcessKilledEvent = false;
}
#endif
if (setProcessKilledEvent) {
// We can now also set the killed event on the process.
KEventSet(&process->killedEvent, true);
}
KSpinlockRelease(&scheduler.lock);
// There are no threads left in this process.
// We should destroy the handle table at this point.
// Otherwise, the process might never be freed
// because of a cyclic-dependency.
process->handleTable.Destroy();
// Destroy the virtual memory space.
// Don't actually deallocate it yet though; that is done on an async task queued by RemoveProcess.
// This must be destroyed after the handle table!
MMSpaceDestroy(process->vmm);
// Tell Desktop the process has terminated.
if (!scheduler.shutdown) {
_EsMessageWithObject m;
EsMemoryZero(&m, sizeof(m));
m.message.type = ES_MSG_PROCESS_TERMINATED;
m.message.crash.pid = process->id;
desktopProcess->messageQueue.SendMessage(&m);
}
}
void KillThread(EsGeneric _thread) {
Thread *thread = (Thread *) _thread.p;
KSpinlockAcquire(&scheduler.lock);
scheduler.allThreads.Remove(&thread->allItem);
thread->process->threads.Remove(&thread->processItem);
KernelLog(LOG_INFO, "Scheduler", "killing thread",
"Killing thread (ID %d, %d remain in process %d) %x...\n", thread->id, thread->process->threads.count, thread->process->id, _thread);
if (thread->process->threads.count == 0) {
KillProcess(thread->process); // Releases the scheduler's lock.
} else {
KSpinlockRelease(&scheduler.lock);
}
MMFree(kernelMMSpace, (void *) thread->kernelStackBase);
if (thread->userStackBase) MMFree(thread->process->vmm, (void *) thread->userStackBase);
KEventSet(&thread->killedEvent);
// Close the handle that this thread owns of its owner process, and the handle it owns of itself.
CloseHandleToObject(thread->process, KERNEL_OBJECT_PROCESS);
CloseHandleToObject(thread, KERNEL_OBJECT_THREAD);
}
Thread *Scheduler::PickThread(CPULocalStorage *local) {
KSpinlockAssertLocked(&lock);
if (local->asyncTasksRead != local->asyncTasksWrite
&& local->asyncTaskThread->state == THREAD_ACTIVE) {
if ((local->asyncTaskList.first || local->inAsyncTask) && local->asyncTaskThread->state == THREAD_ACTIVE) {
// If the asynchronous task thread for this processor isn't blocked, and has tasks to process, execute it.
return local->asyncTaskThread;
}
@ -1261,7 +1232,7 @@ void Scheduler::Yield(InterruptContext *context) {
if (killThread) {
local->currentThread->state = THREAD_TERMINATED;
KernelLog(LOG_INFO, "Scheduler", "terminate yielded thread", "Terminated yielded thread %x\n", local->currentThread);
RegisterAsyncTask(KillThread, local->currentThread, local->currentThread->process, true);
KRegisterAsyncTask(&local->currentThread->killAsyncTask, KillThread);
}
// If the thread is waiting for an object to be notified, put it in the relevant blockedThreads list.
@ -1336,7 +1307,7 @@ void Scheduler::Yield(InterruptContext *context) {
KEventSet(&timer->event, true /* scheduler already locked */);
if (timer->callback) {
RegisterAsyncTask(timer->callback, timer->argument, nullptr, true);
KRegisterAsyncTask(&timer->asyncTask, timer->callback);
}
} else {
break; // Timers are kept sorted, so there's no point continuing.