// POSIX compatibility support for posix thread. #include #include #include #include "posix.h" // 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]; // Implements the pthread Slot Alloc operation. 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; } // Implements the pthread Slot Find operation. 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 } PTHREAD_TRAMP; // Implements the pthread Trampoline operation. 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 = SysGetCurrentTid(); // Create the join slot from inside the new thread. KeCreateThread makes the // thread runnable before the creator regains control, so the old design // raced on tr->Tid and could observe zero/stale memory. PTHREAD_SLOT* slot = PthreadSlotFind(pid, tid); if (!slot) slot = PthreadSlotAlloc(pid, tid); free(tr); void* retval = fn(arg); // Store retval for pthread_join. if (slot) slot->RetVal = retval; SysExitThread(0); } // pthread API. __declspec(dllexport) 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*)malloc(sizeof(PTHREAD_TRAMP)); if (!tr) return ENOMEM; tr->Fn = fn; tr->Arg = arg; tr->Pid = pid; uint32_t tid = 0; uint32_t handle = 0; SYS_CREATE_THREAD_REQUEST req = { (uintptr_t)PthreadTrampoline, (uintptr_t)tr, 1, 0, &handle, &tid }; uint32_t s = SysCreateThread(&req); if (s != 0) { free(tr); return EAGAIN; } // The trampoline allocates the retval slot itself after it knows its real // TID, avoiding the creator/new-thread race. if (t) { t->Handle = handle; t->Tid = tid; } else { SysCloseHandle(handle); } return 0; } // Implements the pthread join operation. __declspec(dllexport) int pthread_join(pthread_t t, void** retval) { uint32_t pid = SysGetCurrentPid(); uint32_t s = SysWait(t.Handle, SYS_WAIT_FLAG_NONE); if (s != 0) return ESRCH; PTHREAD_SLOT* slot = PthreadSlotFind(pid, t.Tid); if (retval) *retval = slot ? slot->RetVal : (void*)0; if (slot) slot->Used = false; SysCloseHandle(t.Handle); return 0; } // Implements the pthread exit operation. __declspec(dllexport) 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 } // Implements the pthread mutex init operation. __declspec(dllexport) int pthread_mutex_init(pthread_mutex_t* m, const pthread_mutexattr_t* attr) { (void)attr; uint32_t h; uint32_t s = SysCreateMutex(&h); if (s != 0) return ENOMEM; m->Handle = h; return 0; } // Implements the pthread mutex destroy operation. __declspec(dllexport) int pthread_mutex_destroy(pthread_mutex_t* m) { SysCloseHandle(m->Handle); m->Handle = 0; return 0; } // Implements the pthread mutex lock operation. __declspec(dllexport) int pthread_mutex_lock(pthread_mutex_t* m) { uint32_t s = SysWait(m->Handle, SYS_WAIT_FLAG_NONE); return s == 0 ? 0 : EINVAL; } // Implements the pthread mutex trylock operation. __declspec(dllexport) int pthread_mutex_trylock(pthread_mutex_t* m) { uint32_t s = SysTryAcquireMutex(m->Handle); return s == 0 ? 0 : EAGAIN; } // Implements the pthread mutex unlock operation. __declspec(dllexport) int pthread_mutex_unlock(pthread_mutex_t* m) { uint32_t s = SysReleaseMutex(m->Handle); return s == 0 ? 0 : EINVAL; }