// Copyright 2012-2020 David Robillard // SPDX-License-Identifier: ISC #ifndef ZIX_THREAD_H #define ZIX_THREAD_H #include "zix/common.h" #ifdef _WIN32 # include #else # include #endif #include #ifdef __cplusplus extern "C" { #endif /** @addtogroup zix @{ @name Thread @{ */ #ifdef _WIN32 # define ZIX_THREAD_RESULT 0 # define ZIX_THREAD_FUNC __stdcall typedef HANDLE ZixThread; typedef DWORD ZixThreadResult; #else # define ZIX_THREAD_RESULT NULL # define ZIX_THREAD_FUNC typedef pthread_t ZixThread; typedef void* ZixThreadResult; #endif /** A thread function. For portability reasons, the return type varies between platforms, and the return value is ignored. Thread functions should always return #ZIX_THREAD_RESULT. This allows thread functions to be used directly by the system without any wrapper overhead. "Returning" a result, and communicating with the parent thread in general, can be done through the pointer argument. */ typedef ZixThreadResult(ZIX_THREAD_FUNC* ZixThreadFunc)(void*); /** Initialize `thread` to a new thread. The thread will immediately be launched, calling `function` with `arg` as the only parameter. */ static inline ZixStatus zix_thread_create(ZixThread* thread, size_t stack_size, ZixThreadFunc function, void* arg); /// Join `thread` (block until `thread` exits) static inline ZixStatus zix_thread_join(ZixThread thread); #ifdef _WIN32 static inline ZixStatus zix_thread_create(ZixThread* thread, size_t stack_size, ZixThreadFunc function, void* arg) { *thread = CreateThread(NULL, stack_size, function, arg, 0, NULL); return *thread ? ZIX_STATUS_SUCCESS : ZIX_STATUS_ERROR; } static inline ZixStatus zix_thread_join(ZixThread thread) { return (WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0) ? ZIX_STATUS_SUCCESS : ZIX_STATUS_ERROR; } #else /* !defined(_WIN32) */ static inline ZixStatus zix_thread_create(ZixThread* thread, size_t stack_size, void* (*function)(void*), void* arg) { pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, stack_size); const int ret = pthread_create(thread, NULL, function, arg); pthread_attr_destroy(&attr); return zix_errno_status(ret); } static inline ZixStatus zix_thread_join(ZixThread thread) { return pthread_join(thread, NULL) ? ZIX_STATUS_ERROR : ZIX_STATUS_SUCCESS; } #endif /** @} @} */ #ifdef __cplusplus } /* extern "C" */ #endif #endif /* ZIX_THREAD_H */