// posix_thread.c - pthread_create, pthread_join, pthread_exit, pthread_mutex_* #include #include "posix.h" extern uint32_t SysGetCurrentPid(void); extern uint32_t SysGetCurrentTid(void); extern uint32_t SysCreateThread(uint64_t entry, uint64_t arg, uint32_t priority, uint32_t* tidOut); extern uint32_t SysWaitThread(uint32_t tid); extern void SysExitThread(int code); extern void* SysAlloc(size_t size); extern void SysFree(void* ptr, size_t size); extern uint32_t SysMutexCreate(uint32_t* handleOut); extern uint32_t SysMutexAcquire(uint32_t handle); extern uint32_t SysMutexTryAcquire(uint32_t handle); extern uint32_t SysMutexRelease(uint32_t handle); extern void SysCloseHandle(uint32_t handle); // Thread return-value table (PID-keyed like the fd table) #define PTHREAD_TABLE_PIDS 32 #define PTHREAD_TABLE_SIZE 32 typedef struct { uint32_t Tid; void* RetVal; bool Used; } PTHREAD_SLOT; static PTHREAD_SLOT gPthreadTable[PTHREAD_TABLE_PIDS][PTHREAD_TABLE_SIZE]; static PTHREAD_SLOT* PthreadSlotAlloc(uint32_t pid, uint32_t tid) { PTHREAD_SLOT* table = gPthreadTable[pid % PTHREAD_TABLE_PIDS]; for (int i = 0; i < PTHREAD_TABLE_SIZE; i++) { if (!table[i].Used) { table[i] = (PTHREAD_SLOT){ tid, (void*)0, true }; return &table[i]; } } return (PTHREAD_SLOT*)0; } static PTHREAD_SLOT* PthreadSlotFind(uint32_t pid, uint32_t tid) { PTHREAD_SLOT* table = gPthreadTable[pid % PTHREAD_TABLE_PIDS]; for (int i = 0; i < PTHREAD_TABLE_SIZE; i++) if (table[i].Used && table[i].Tid == tid) return &table[i]; return (PTHREAD_SLOT*)0; } // --------------------------------------------------------------------------- // Trampoline - this is what actually runs as the new thread // --------------------------------------------------------------------------- typedef struct { void* (*Fn)(void*); void* Arg; uint32_t Pid; // owner pid, for the retval table uint32_t Tid; // filled in by pthread_create after KeCreateThread returns } PTHREAD_TRAMP; static void PthreadTrampoline(uintptr_t raw) { PTHREAD_TRAMP* tr = (PTHREAD_TRAMP*)raw; void* (*fn)(void*) = tr->Fn; void* arg = tr->Arg; uint32_t pid = tr->Pid; uint32_t tid = tr->Tid; SysFree(tr, sizeof(PTHREAD_TRAMP)); void* retval = fn(arg); // Store retval for pthread_join. If the slot isn't there (join was called // before the thread was even created, which shouldn't happen) just drop it. PTHREAD_SLOT* slot = PthreadSlotFind(pid, tid); if (slot) slot->RetVal = retval; SysExitThread(0); } // --------------------------------------------------------------------------- // pthread API // --------------------------------------------------------------------------- int pthread_create(pthread_t* t, const pthread_attr_t* attr, void* (*fn)(void*), void* arg) { (void)attr; uint32_t pid = SysGetCurrentPid(); PTHREAD_TRAMP* tr = (PTHREAD_TRAMP*)SysAlloc(sizeof(PTHREAD_TRAMP)); if (!tr) return ENOMEM; tr->Fn = fn; tr->Arg = arg; tr->Pid = pid; tr->Tid = 0; // filled below uint32_t tid = 0; uint32_t s = SysCreateThread((uint64_t)PthreadTrampoline, (uint64_t)tr, 1 /*PriorityNormal*/, &tid); if (s != 0) { SysFree(tr, sizeof(PTHREAD_TRAMP)); return EAGAIN; } tr->Tid = tid; // safe: trampoline reads Tid after SysCreateThread returns // Reserve a retval slot before the trampoline can exit PthreadSlotAlloc(pid, tid); t->Tid = tid; return 0; } int pthread_join(pthread_t t, void** retval) { uint32_t pid = SysGetCurrentPid(); uint32_t s = SysWaitThread(t.Tid); // STATUS_NOT_FOUND (0x22) means already dead - treat as success if (s != 0 && s != 0x0022) return ESRCH; PTHREAD_SLOT* slot = PthreadSlotFind(pid, t.Tid); if (retval) *retval = slot ? slot->RetVal : (void*)0; if (slot) slot->Used = false; return 0; } void pthread_exit(void* retval) { uint32_t pid = SysGetCurrentPid(); uint32_t tid = SysGetCurrentTid(); PTHREAD_SLOT* slot = PthreadSlotFind(pid, tid); if (slot) slot->RetVal = retval; SysExitThread(0); while (1); // unreachable } int pthread_mutex_init(pthread_mutex_t* m, const pthread_mutexattr_t* attr) { (void)attr; uint32_t h; uint32_t s = SysMutexCreate(&h); if (s != 0) return ENOMEM; m->Handle = h; return 0; } int pthread_mutex_destroy(pthread_mutex_t* m) { SysCloseHandle(m->Handle); m->Handle = 0; return 0; } int pthread_mutex_lock(pthread_mutex_t* m) { uint32_t s = SysMutexAcquire(m->Handle); return s == 0 ? 0 : EINVAL; } int pthread_mutex_trylock(pthread_mutex_t* m) { uint32_t s = SysMutexTryAcquire(m->Handle); return s == 0 ? 0 : EAGAIN; } int pthread_mutex_unlock(pthread_mutex_t* m) { uint32_t s = SysMutexRelease(m->Handle); return s == 0 ? 0 : EINVAL; }