libGimbal 0.1.0
C17-Based Extended Standard Library and Cross-Language Runtime Framework
Loading...
Searching...
No Matches
gimbal_tls.h
Go to the documentation of this file.
1/*! \file
2 * \brief Thread-local variable management
3 * \ingroup core
4 *
5 * This file provides a pair of macros serving as an abstraction layer
6 * between a platform's preferred thread-local storage mechanism, and
7 * the application.
8 *
9 * Where supported, GBL_TLS() will use real, compiler-enabled static
10 * TLS by simply declaring the variable with the "thread_local" keyword
11 * and proceeding to access it normally.
12 *
13 * If this preferred path is not available, using the same semantics, the
14 * back-end emulate this behavior by creating OS-level TLS storage using
15 * TinyCThread's C11 TLS API, which uses dynamically allocated storage
16 * and key-based lookups.
17 *
18 * \author 2023 Falco Girgis
19 * \copyright MIT License
20 */
21
22#ifndef GIMBAL_TLS_H
23#define GIMBAL_TLS_H
24
25#include <tinycthread.h>
26#include "../preprocessor/gimbal_compiler.h"
27
28/*! \def GBL_TLS(type, name, init)
29 *
30 * Defines a thread-local variable using the given information,
31 * and either using compiler or OS-level TLS depending on the
32 * platform.
33 *
34 * \param type variable type
35 * \param name variable name
36 * \param init variable initializer
37 *
38 * \sa GBL_TLS_LOAD()
39 */
40#if !defined(GBL_PSP) && !GBL_TLS_EMULATED
41# define GBL_TLS(type, name, ...) GBL_THREAD_LOCAL type name = __VA_ARGS__
42#else
43# define GBL_TLS(type, name, ...)
44 tss_t name;
45 static void tls_##name##_init_(void) {
46 int res = tss_create(&name, free);
47 GBL_ASSERT(res == thrd_success,
48 "Failed to create "#type" TLS for "#name);
49 }
50 static type* tls_##name##_load_(void) {
51 static once_flag once = ONCE_FLAG_INIT;
52 call_once(&once, tls_##name##_init_);
53 type* pPtr = tss_get(name);
54 if(!pPtr) {
55 pPtr = malloc(sizeof(type));
56 type temp = __VA_ARGS__;
57 memcpy(pPtr, &temp, sizeof(type));
58 const int res = tss_set(name, pPtr);
59 GBL_ASSERT(res == thrd_success,
60 "Failed to set "#type" TLS for "#name);
61 }
62 return pPtr;
63 }
64#endif
65
66/*! \def GBL_TLS_LOAD(name)
67 *
68 * Fetches a pointer to a thread-local variable that was
69 * previously declared with GBL_TLS()
70 *
71 * \param name variable name
72 * \return pointer address of the given TLS variable
73 *
74 * \sa GBL_TLS()
75 */
76#if !defined(GBL_PSP) && !GBL_TLS_EMULATED
77# define GBL_TLS_LOAD(name) &name
78#else
79# define GBL_TLS_LOAD(name) tls_##name##_load_()
80#endif
81
82#endif // GIMBAL_TLS_H
#define GBL_THREAD_LOCAL