diff --git a/Makefile b/Makefile index 32c0d56..7747c50 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ include common.mk all: server -$(BUILD_DIR)/common/util/thread.o: $(BUILD_DIR)/common/util/thread.posix.o +$(BUILD_DIR)/common/util/thread.o: $(BUILD_DIR)/common/util/thread.std.o cp $< $@ server: $(BUILD_DIR)/server/main.o $(BUILD_DIR)/common/util/hash_table.o $(BUILD_DIR)/common/util/byte_stream.o $(BUILD_DIR)/common/util/thread.o diff --git a/src/common/util/thread.std.c b/src/common/util/thread.std.c new file mode 100644 index 0000000..1198611 --- /dev/null +++ b/src/common/util/thread.std.c @@ -0,0 +1,135 @@ +#include "thread.h" + +#include +#include +#include + +typedef struct { + ThreadEntry entry; + ThreadResult error_result; +} NativeEntryArg; + +inline static thrd_t +get_handle(Thread wrapper) +{ + assert(wrapper.opaque != NULL); + return *(thrd_t*) wrapper.opaque; +} + +inline static bool +new_uninitialized(Thread *th) +{ + thrd_t *data = T_ALLOC(1, thrd_t); + if (!data) { + return false; + } + *th = (Thread) { .opaque = data }; + return true; +} + +inline static void +initialize_handle(Thread *th, thrd_t handle) +{ + assert(th != NULL); + assert(th->opaque != NULL); + *(thrd_t*) th->opaque = handle; + return; +} + +inline static Thread +delete_handle(Thread th) +{ + if (!th.opaque) { + return THREAD_NONE; + } + free(th.opaque); + return THREAD_NONE; +} + +static int +run_entry(void *arg) +{ + assert(arg != NULL); + NativeEntryArg casted_arg = *(NativeEntryArg*) arg; + ThreadEntry entry = casted_arg.entry; + uint32_t error_result = casted_arg.error_result.value; + free(arg); + if (!entry.callback) { + return error_result; + } + ThreadResult result = entry.callback(entry.env); + return result.value; +} + +Thread +thread_spawn(ThreadEntry entry, ThreadResult error_result) +{ + NativeEntryArg *native_arg = T_ALLOC(1, NativeEntryArg); + if (!native_arg) { + return THREAD_NONE; + } + *native_arg = (NativeEntryArg) { + .entry = entry, + .error_result = error_result, + }; + Thread th; + thrd_t handle; + int error; + if (!new_uninitialized(&th)) { + free(native_arg); + return THREAD_NONE; + } + error = thrd_create(&handle, &run_entry, native_arg); // calls free(native_arg) if error == 0 + if (error != thrd_success) { +#ifdef ENOMEM + if (error == thrd_nomem) { + errno = ENOMEM; + } +#endif + free(native_arg); + return delete_handle(th); + } + initialize_handle(&th, handle); + return th; +} + +Thread +thread_delete_handle(Thread th) +{ + return delete_handle(th); +} + +bool +thread_join(Thread th, ThreadResult *result_ptr) +{ + if (!th.opaque) { +#ifdef EINVAL + errno = EINVAL; +#endif + return false; + } + thrd_t handle = get_handle(th); + int32_t *retval = NULL; + if (result_ptr) { + result_ptr->pointer = NULL; + retval = (int32_t*) &result_ptr->value; + } + int error = thrd_join(handle, retval); + if (error != thrd_success) { + return false; + } + return true; +} + +void +thread_exit(ThreadResult result) +{ + thrd_exit(result.value); +} + +bool +thread_yield() +{ + thrd_yield(); + return true; +}