/* * C11 emulation library * * (C) Copyright yohhoy 2012. * Copyright 2022 Yonggang Luo * Distributed under the Boost Software License, Version 1.0. * * Permission is hereby granted, free of charge, to any person or * organization obtaining a copy of the software and accompanying * documentation covered by this license (the "Software") to use, * reproduce, display, distribute, execute, and transmit the Software, * and to prepare [[derivative work]]s of the Software, and to permit * third-parties to whom the Software is furnished to do so, all * subject to the following: * * The copyright notices in the Software and this entire statement, * including the above license grant, this restriction and the * following disclaimer, must be included in all copies of the * Software, in whole or in part, and all derivative works of the * Software, unless such copies or derivative works are solely in the * form of machine-executable object code generated by a source * language processor. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE * DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER * LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #ifndef KIT_THREADS_H #define KIT_THREADS_H #ifndef KIT_DISABLE_SYSTEM_THREADS # include "time.h" # include # include # include # include # ifdef _MSC_VER # define _Noreturn __declspec(noreturn) # endif # if defined(_WIN32) && !defined(__CYGWIN__) # include /* close */ # include /* _exit */ # else # include # include /* close, _exit */ # endif /*---------------------------- macros ---------------------------*/ # ifndef _Thread_local # if defined(__cplusplus) /* C++11 doesn't need `_Thread_local` keyword or macro */ # elif !defined(__STDC_NO_THREADS__) /* threads are optional in C11, _Thread_local present in this * condition */ # elif defined(_MSC_VER) # define _Thread_local __declspec(thread) # elif defined(__GNUC__) # define _Thread_local __thread # else /* Leave _Thread_local undefined so that use of _Thread_local would * not promote to a non-thread-local global variable */ # endif # endif # if !defined(__cplusplus) /* * C11 thread_local() macro * C++11 and above already have thread_local keyword */ # ifndef thread_local # if _MSC_VER # define thread_local __declspec(thread) # else # define thread_local _Thread_local # endif # endif # endif # ifdef __cplusplus extern "C" { # endif /*---------------------------- types ----------------------------*/ typedef void (*tss_dtor_t)(void *); typedef int (*thrd_start_t)(void *); # if defined(_WIN32) && !defined(__CYGWIN__) typedef struct { void *Ptr; } cnd_t; /* Define thrd_t as struct type intentionally for avoid use of thrd_t * as pointer type */ typedef struct { void *handle; } thrd_t; typedef unsigned long tss_t; typedef struct { void *DebugInfo; long LockCount; long RecursionCount; void *OwningThread; void *LockSemaphore; uintptr_t SpinCount; } mtx_t; /* Mock of CRITICAL_SECTION */ typedef struct { volatile uintptr_t status; } once_flag; // FIXME: temporary non-standard hack to ease transition # define KIT_MTX_INITIALIZER_NP_ \ { (void *) -1, -1, 0, 0, 0, 0 } # define ONCE_FLAG_INIT \ { 0 } # define TSS_DTOR_ITERATIONS 1 # else typedef pthread_cond_t cnd_t; typedef pthread_t thrd_t; typedef pthread_key_t tss_t; typedef pthread_mutex_t mtx_t; typedef pthread_once_t once_flag; // FIXME: temporary non-standard hack to ease transition # define KIT_MTX_INITIALIZER_NP_ PTHREAD_MUTEX_INITIALIZER # define ONCE_FLAG_INIT PTHREAD_ONCE_INIT # ifdef PTHREAD_DESTRUCTOR_ITERATIONS # define TSS_DTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS # else # define TSS_DTOR_ITERATIONS \ 1 // assume TSS dtor MAY be called at least once. # endif # endif /*-------------------- enumeration constants --------------------*/ enum { mtx_plain = 0, mtx_recursive = 1, mtx_timed = 2, }; enum { thrd_success = 0, // succeeded thrd_timedout, // timed out thrd_error, // failed thrd_busy, // resource busy thrd_nomem, // out of memory, thrd_wrong_stack_size }; /*-------------------------- functions --------------------------*/ void call_once(once_flag *, void (*)(void)); int cnd_broadcast(cnd_t *); void cnd_destroy(cnd_t *); int cnd_init(cnd_t *); int cnd_signal(cnd_t *); int cnd_timedwait(cnd_t *__restrict, mtx_t *__restrict mtx_, const struct timespec *__restrict); int cnd_wait(cnd_t *, mtx_t *mtx_); void mtx_destroy(mtx_t *mtx_); int mtx_init(mtx_t *mtx_, int); int mtx_lock(mtx_t *mtx_); int mtx_timedlock(mtx_t *__restrict mtx_, const struct timespec *__restrict); int mtx_trylock(mtx_t *mtx_); int mtx_unlock(mtx_t *mtx_); int thrd_create(thrd_t *, thrd_start_t, void *); int thrd_create_with_stack(thrd_t *, thrd_start_t, void *, ptrdiff_t stack_size); thrd_t thrd_current(void); int thrd_detach(thrd_t); int thrd_equal(thrd_t, thrd_t); # if defined(__cplusplus) [[ noreturn ]] # else _Noreturn # endif void thrd_exit(int); int thrd_join(thrd_t, int *); int thrd_sleep(const struct timespec *, struct timespec *); void thrd_yield(void); # ifdef __cplusplus } # endif #endif /* KIT_DISABLE_SYSTEM_THREADS */ #endif /* KIT_THREADS_H */