// POSIX compatibility support for posix thread. #include #include #include #include "posix_internal.h" // Allocates a join-result slot in process-local POSIX state. static POSIX_PTHREAD_SLOT* PthreadSlotAlloc(uint32_t tid) { POSIX_PROCESS_STATE* process = PosixRuntimeProcessState(); if (!process) return (POSIX_PTHREAD_SLOT*)0; for (uint32_t i = 0; i < POSIX_PTHREAD_TABLE_SIZE; i++) { if (!process->PthreadTable[i].Used) { process->PthreadTable[i] = (POSIX_PTHREAD_SLOT){ tid, (void*)0, true }; return &process->PthreadTable[i]; } } return (POSIX_PTHREAD_SLOT*)0; } // Finds a join-result slot in process-local POSIX state. static POSIX_PTHREAD_SLOT* PthreadSlotFind(uint32_t tid) { POSIX_PROCESS_STATE* process = PosixRuntimeProcessState(); if (!process) return (POSIX_PTHREAD_SLOT*)0; for (uint32_t i = 0; i < POSIX_PTHREAD_TABLE_SIZE; i++) { if (process->PthreadTable[i].Used && process->PthreadTable[i].Tid == tid) return &process->PthreadTable[i]; } return (POSIX_PTHREAD_SLOT*)0; } // Trampoline - this is what actually runs as the new thread. typedef struct { void* (*Fn)(void*); void* Arg; uint64_t SignalMask; } 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 tid = SysGetCurrentTid(); if (PosixRuntimeAttachThreadWithSignalMask(tr->SignalMask) != NTLSTATUS_SUCCESS) { free(tr); SysExitThread(ENOMEM); } // 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. POSIX_PTHREAD_SLOT* slot = PthreadSlotFind(tid); if (!slot) slot = PthreadSlotAlloc(tid); free(tr); void* retval = fn(arg); // Store retval for pthread_join. if (slot) slot->RetVal = retval; PosixRuntimeDetachThread(); SysExitThread(0); } // pthread API. __declspec(dllexport) int pthread_create(pthread_t* t, const pthread_attr_t* attr, void* (*fn)(void*), void* arg) { (void)attr; PTHREAD_TRAMP* tr = (PTHREAD_TRAMP*)malloc(sizeof(PTHREAD_TRAMP)); if (!tr) return ENOMEM; tr->Fn = fn; tr->Arg = arg; POSIX_THREAD_STATE* parentThread = PosixRuntimeThreadState(); if (!parentThread) { free(tr); return EIO; } tr->SignalMask = parentThread->SignalBlocked; uint32_t tid = 0; uint32_t handle = 0; SYS_CREATE_THREAD_REQUEST req = { sizeof(SYS_CREATE_THREAD_REQUEST), (uintptr_t)PthreadTrampoline, (uintptr_t)tr, 1, 0, &handle, &tid }; KSTATUS 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; } __declspec(dllexport) int pthread_join(pthread_t t, void** retval) { KSTATUS s = SysWait(t.Handle, SYS_WAIT_FLAG_NONE); if (s != 0) return ESRCH; POSIX_PTHREAD_SLOT* slot = PthreadSlotFind(t.Tid); if (retval) *retval = slot ? slot->RetVal : (void*)0; if (slot) slot->Used = false; SysCloseHandle(t.Handle); return 0; } __declspec(dllexport) void pthread_exit(void* retval) { uint32_t tid = SysGetCurrentTid(); POSIX_PTHREAD_SLOT* slot = PthreadSlotFind(tid); if (slot) slot->RetVal = retval; PosixRuntimeDetachThread(); SysExitThread(0); while (1); // unreachable } __declspec(dllexport) int pthread_mutex_init(pthread_mutex_t* m, const pthread_mutexattr_t* attr) { (void)attr; uint32_t h; KSTATUS s = SysCreateMutex(&h); if (s != 0) return ENOMEM; m->Handle = h; return 0; } __declspec(dllexport) int pthread_mutex_destroy(pthread_mutex_t* m) { SysCloseHandle(m->Handle); m->Handle = 0; return 0; } __declspec(dllexport) int pthread_mutex_lock(pthread_mutex_t* m) { KSTATUS s = SysWait(m->Handle, SYS_WAIT_FLAG_NONE); return s == 0 ? 0 : EINVAL; } __declspec(dllexport) int pthread_mutex_trylock(pthread_mutex_t* m) { KSTATUS s = SysTryAcquireMutex(m->Handle); return s == 0 ? 0 : EAGAIN; } __declspec(dllexport) int pthread_mutex_unlock(pthread_mutex_t* m) { KSTATUS s = SysReleaseMutex(m->Handle); return s == 0 ? 0 : EINVAL; }