144 lines
4.9 KiB
C
144 lines
4.9 KiB
C
// ke_process.c - process model
|
|
#include "ke_process.h"
|
|
#include "ke_thread.h"
|
|
#include "mm_virt.h"
|
|
#include "ob_object.h"
|
|
#include <string.h>
|
|
#include <intrin.h>
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Global process list
|
|
// ---------------------------------------------------------------------------
|
|
static LIST_ENTRY gProcessList;
|
|
static SPINLOCK gProcessListLock;
|
|
static uint32_t gNextProcessId = 1;
|
|
|
|
static void ProcessInit(void) {
|
|
static int inited = 0;
|
|
if (!inited) {
|
|
LIST_INIT(&gProcessList);
|
|
gProcessListLock = (SPINLOCK)SPINLOCK_INIT;
|
|
inited = 1;
|
|
}
|
|
}
|
|
|
|
LIST_ENTRY* KeGetProcessList(void) {
|
|
return &gProcessList;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Destructor (called by ObDereferenceObject when RefCount hits zero)
|
|
// ---------------------------------------------------------------------------
|
|
static void ProcessDestroy(OBJECT* obj) {
|
|
PROCESS* proc = CONTAINING_RECORD(obj, PROCESS, Header);
|
|
|
|
// Release all remaining handles.
|
|
for (int i = 1; i < HANDLE_TABLE_SIZE; i++) {
|
|
if (proc->Handles[i]) {
|
|
ObDereferenceObject(proc->Handles[i]);
|
|
proc->Handles[i] = (OBJECT *)0;
|
|
}
|
|
}
|
|
|
|
// Remove from global list.
|
|
uintptr_t flags = KeAcquireSpinlock(&gProcessListLock);
|
|
ListRemove(&proc->GlobalLink);
|
|
KeReleaseSpinlock(&gProcessListLock, flags);
|
|
|
|
// Memory for the struct itself is freed by ObDereferenceObject after
|
|
// Destroy returns.
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// KeCreateProcess
|
|
// ---------------------------------------------------------------------------
|
|
KSTATUS KeCreateProcess(const char* name, PROCESS **out) {
|
|
ProcessInit();
|
|
|
|
if (!name || !out) return STATUS_INVALID_PARAMETER;
|
|
|
|
PROCESS* proc = (PROCESS *)ObAllocateObject(ObjectTypeProcess, sizeof(PROCESS));
|
|
if (!proc) return STATUS_NO_MEMORY;
|
|
|
|
proc->Header.Destroy = ProcessDestroy;
|
|
|
|
proc->ProcessId = _InterlockedExchangeAdd((volatile long *)&gNextProcessId, 1);
|
|
strncpy(proc->Name, name, PROCESS_NAME_MAX - 1);
|
|
proc->Name[PROCESS_NAME_MAX - 1] = '\0';
|
|
|
|
LIST_INIT(&proc->ThreadList);
|
|
proc->ThreadCount = 0;
|
|
proc->HandleLock = (SPINLOCK)SPINLOCK_INIT;
|
|
proc->ExitCode = 0;
|
|
|
|
// Slot 0 is the invalid handle - leave it NULL.
|
|
memset(proc->Handles, 0, sizeof(proc->Handles));
|
|
|
|
LIST_INIT(&proc->GlobalLink);
|
|
|
|
uintptr_t flags = KeAcquireSpinlock(&gProcessListLock);
|
|
ListInsertTail(&gProcessList, &proc->GlobalLink);
|
|
KeReleaseSpinlock(&gProcessListLock, flags);
|
|
|
|
*out = proc;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// KeExitProcess
|
|
// ---------------------------------------------------------------------------
|
|
void KeExitProcess(PROCESS* process, int exitCode) {
|
|
if (!process) return;
|
|
process->ExitCode = exitCode;
|
|
// The last thread exiting via KeExitThread will drop the process refcount.
|
|
// This function is a policy hook; actual cleanup is in ProcessDestroy.
|
|
ObDereferenceObject(&process->Header);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Handle table
|
|
// ---------------------------------------------------------------------------
|
|
KSTATUS KeAllocateHandle(PROCESS* process, OBJECT* object, uint32_t* handleOut) {
|
|
if (!process || !object || !handleOut) return STATUS_INVALID_PARAMETER;
|
|
|
|
uintptr_t flags = KeAcquireSpinlock(&process->HandleLock);
|
|
|
|
for (int i = 1; i < HANDLE_TABLE_SIZE; i++) {
|
|
if (!process->Handles[i]) {
|
|
ObReferenceObject(object);
|
|
process->Handles[i] = object;
|
|
*handleOut = (uint32_t)i;
|
|
KeReleaseSpinlock(&process->HandleLock, flags);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
KeReleaseSpinlock(&process->HandleLock, flags);
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
void KeCloseHandle(PROCESS* process, uint32_t handle) {
|
|
if (!process || handle == 0 || handle >= HANDLE_TABLE_SIZE) return;
|
|
|
|
uintptr_t flags = KeAcquireSpinlock(&process->HandleLock);
|
|
OBJECT* obj = process->Handles[handle];
|
|
if (obj) {
|
|
process->Handles[handle] = (OBJECT *)0;
|
|
KeReleaseSpinlock(&process->HandleLock, flags);
|
|
ObDereferenceObject(obj);
|
|
return;
|
|
}
|
|
KeReleaseSpinlock(&process->HandleLock, flags);
|
|
}
|
|
|
|
OBJECT* KeLookupHandle(PROCESS* process, uint32_t handle) {
|
|
if (!process || handle == 0 || handle >= HANDLE_TABLE_SIZE)
|
|
return (OBJECT *)0;
|
|
|
|
uintptr_t flags = KeAcquireSpinlock(&process->HandleLock);
|
|
OBJECT* obj = process->Handles[handle];
|
|
if (obj) ObReferenceObject(obj);
|
|
KeReleaseSpinlock(&process->HandleLock, flags);
|
|
return obj;
|
|
}
|