149 lines
4.1 KiB
C
149 lines
4.1 KiB
C
/**
|
|
* Copyright (c) 2020 Paul-Louis Ageneau
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
#ifndef JUICE_THREAD_H
|
|
#define JUICE_THREAD_H
|
|
|
|
#ifdef _WIN32
|
|
|
|
#ifndef _WIN32_WINNT
|
|
#define _WIN32_WINNT 0x0601 // Windows 7
|
|
#endif
|
|
#ifndef __MSVCRT_VERSION__
|
|
#define __MSVCRT_VERSION__ 0x0601
|
|
#endif
|
|
|
|
#include <windows.h>
|
|
|
|
typedef HRESULT(WINAPI *pfnSetThreadDescription)(HANDLE, PCWSTR); // for thread_set_name_self()
|
|
|
|
typedef HANDLE mutex_t;
|
|
typedef HANDLE thread_t;
|
|
typedef DWORD thread_return_t;
|
|
#define THREAD_CALL __stdcall
|
|
|
|
#define MUTEX_INITIALIZER NULL
|
|
|
|
#define MUTEX_PLAIN 0x0
|
|
#define MUTEX_RECURSIVE 0x0 // mutexes are recursive on Windows
|
|
|
|
static inline int mutex_init_impl(mutex_t *m) {
|
|
return ((*(m) = CreateMutex(NULL, FALSE, NULL)) != NULL ? 0 : (int)GetLastError());
|
|
}
|
|
|
|
static inline int mutex_lock_impl(volatile mutex_t *m) {
|
|
// Atomically initialize the mutex on first lock
|
|
if (*(m) == NULL) {
|
|
HANDLE cm = CreateMutex(NULL, FALSE, NULL);
|
|
if (cm == NULL)
|
|
return (int)GetLastError();
|
|
if (InterlockedCompareExchangePointer(m, cm, NULL) != NULL)
|
|
CloseHandle(cm);
|
|
}
|
|
return WaitForSingleObject(*m, INFINITE) != WAIT_FAILED ? 0 : (int)GetLastError();
|
|
}
|
|
|
|
#define mutex_init(m, flags) mutex_init_impl(m)
|
|
#define mutex_lock(m) mutex_lock_impl(m)
|
|
#define mutex_unlock(m) (void)ReleaseMutex(*(m))
|
|
#define mutex_destroy(m) (void)CloseHandle(*(m))
|
|
|
|
static inline void thread_join_impl(thread_t t, thread_return_t *res) {
|
|
WaitForSingleObject(t, INFINITE);
|
|
if (res)
|
|
GetExitCodeThread(t, res);
|
|
CloseHandle(t);
|
|
}
|
|
|
|
#define thread_init(t, func, arg) \
|
|
((*(t) = CreateThread(NULL, 0, func, arg, 0, NULL)) != NULL ? 0 : (int)GetLastError())
|
|
#define thread_join(t, res) thread_join_impl(t, res)
|
|
|
|
#else // POSIX
|
|
|
|
#include <pthread.h>
|
|
|
|
#if defined(__linux__)
|
|
#include <sys/prctl.h> // for prctl(PR_SET_NAME)
|
|
#endif
|
|
#if defined(__FreeBSD__)
|
|
#include <pthread_np.h> // for pthread_set_name_np
|
|
#endif
|
|
|
|
typedef pthread_mutex_t mutex_t;
|
|
typedef pthread_t thread_t;
|
|
typedef void *thread_return_t;
|
|
#define THREAD_CALL
|
|
|
|
#define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
|
|
|
|
#define MUTEX_PLAIN PTHREAD_MUTEX_NORMAL
|
|
#define MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE
|
|
|
|
static inline int mutex_init_impl(mutex_t *m, int flags) {
|
|
pthread_mutexattr_t mutexattr;
|
|
pthread_mutexattr_init(&mutexattr);
|
|
pthread_mutexattr_settype(&mutexattr, flags);
|
|
int ret = pthread_mutex_init(m, &mutexattr);
|
|
pthread_mutexattr_destroy(&mutexattr);
|
|
return ret;
|
|
}
|
|
|
|
#define mutex_init(m, flags) mutex_init_impl(m, flags)
|
|
#define mutex_lock(m) pthread_mutex_lock(m)
|
|
#define mutex_unlock(m) (void)pthread_mutex_unlock(m)
|
|
#define mutex_destroy(m) (void)pthread_mutex_destroy(m)
|
|
|
|
#define thread_init(t, func, arg) pthread_create(t, NULL, func, arg)
|
|
#define thread_join(t, res) (void)pthread_join(t, res)
|
|
|
|
#endif // ifdef _WIN32
|
|
|
|
static inline void thread_set_name_self(const char *name) {
|
|
#if defined(_WIN32)
|
|
wchar_t wname[256];
|
|
if (MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, name, -1, wname, 256) > 0) {
|
|
HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll");
|
|
if (kernel32) {
|
|
pfnSetThreadDescription pSetThreadDescription =
|
|
(pfnSetThreadDescription)GetProcAddress(kernel32, "SetThreadDescription");
|
|
if (pSetThreadDescription) {
|
|
pSetThreadDescription(GetCurrentThread(), wname);
|
|
}
|
|
}
|
|
}
|
|
#elif defined(__linux__)
|
|
prctl(PR_SET_NAME, name);
|
|
#elif defined(__APPLE__)
|
|
pthread_setname_np(name);
|
|
#elif defined(__FreeBSD__)
|
|
pthread_set_name_np(pthread_self(), name);
|
|
#else
|
|
(void)name;
|
|
#endif
|
|
}
|
|
|
|
#if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__)
|
|
|
|
#include <stdatomic.h>
|
|
#define atomic(T) _Atomic(T)
|
|
#define atomic_ptr(T) _Atomic(T *)
|
|
|
|
#else // no atomics
|
|
|
|
// Since we don't need compare-and-swap, just assume store and load are atomic
|
|
#define atomic(T) volatile T
|
|
#define atomic_ptr(T) T *volatile
|
|
#define atomic_store(a, v) (void)(*(a) = (v))
|
|
#define atomic_load(a) (*(a))
|
|
#define ATOMIC_VAR_INIT(v) (v)
|
|
|
|
#endif // if atomics
|
|
|
|
#endif // JUICE_THREAD_H
|