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#if defined(GBL_PSP)
29# define GBL_TLS_EMULATED 1
30#endif
31
32/*! \def GBL_TLS(type, name, init)
33 *
34 * Defines a thread-local variable using the given information,
35 * and either using compiler or OS-level TLS depending on the
36 * platform.
37 *
38 * \param type variable type
39 * \param name variable name
40 * \param init variable initializer
41 *
42 * \sa GBL_TLS_LOAD()
43 */
44#if !GBL_TLS_EMULATED
45# define GBL_TLS(type, name, ...) GBL_THREAD_LOCAL type name = __VA_ARGS__
46#else
47# define GBL_TLS(type, name, ...)
48 tss_t name;
49 static void tls_##name##_init_(void) {
50 int res = tss_create(&name, free);
51 GBL_ASSERT(res == thrd_success,
52 "Failed to create "#type" TLS for "#name);
53 }
54 static type* tls_##name##_load_(void) {
55 static once_flag once = ONCE_FLAG_INIT;
56 call_once(&once, tls_##name##_init_);
57 type* pPtr = tss_get(name);
58 if(!pPtr) {
59 pPtr = malloc(sizeof(type));
60 type temp = __VA_ARGS__;
61 memcpy(pPtr, &temp, sizeof(type));
62 const int res = tss_set(name, pPtr);
63 GBL_ASSERT(res == thrd_success,
64 "Failed to set "#type" TLS for "#name);
65 }
66 return pPtr;
67 }
68#endif
69
70/*! \def GBL_TLS_LOAD(name)
71 *
72 * Fetches a pointer to a thread-local variable that was
73 * previously declared with GBL_TLS()
74 *
75 * \param name variable name
76 * \return pointer address of the given TLS variable
77 *
78 * \sa GBL_TLS()
79 */
80#if !GBL_TLS_EMULATED
81# define GBL_TLS_LOAD(name) &name
82#else
83# define GBL_TLS_LOAD(name) tls_##name##_load_()
84#endif
85
86#endif // GIMBAL_TLS_H
#define GBL_THREAD_LOCAL