Files
nt-lite/code/user/personalities/posix/posix_thread.c
T

169 lines
4.8 KiB
C

// POSIX compatibility support for posix thread.
#include <stddef.h>
#include <stdlib.h>
#include <ntlite/syscall.h>
#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;
}