2 * QEMU Thread Local Storage for coroutines
6 * SPDX-License-Identifier: LGPL-2.1-or-later
8 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
9 * See the COPYING.LIB file in the top-level directory.
11 * It is forbidden to access Thread Local Storage in coroutines because
12 * compiler optimizations may cause values to be cached across coroutine
13 * re-entry. Coroutines can run in more than one thread through the course of
14 * their life, leading bugs when stale TLS values from the wrong thread are
15 * used as a result of compiler optimization.
20 * :caption: A coroutine that may see the wrong TLS value
22 * static __thread AioContext *current_aio_context;
24 * static void coroutine_fn foo(void)
26 * aio_notify(current_aio_context);
27 * qemu_coroutine_yield();
28 * aio_notify(current_aio_context); // <-- may be stale after yielding!
31 * This header provides macros for safely defining variables in Thread Local
35 * :caption: A coroutine that safely uses TLS
37 * QEMU_DEFINE_STATIC_CO_TLS(AioContext *, current_aio_context)
39 * static void coroutine_fn foo(void)
41 * aio_notify(get_current_aio_context());
42 * qemu_coroutine_yield();
43 * aio_notify(get_current_aio_context()); // <-- safe
47 #ifndef QEMU_COROUTINE_TLS_H
48 #define QEMU_COROUTINE_TLS_H
51 * To stop the compiler from caching TLS values we define accessor functions
52 * with __attribute__((noinline)) plus asm volatile("") to prevent
53 * optimizations that override noinline.
55 * The compiler can still analyze noinline code and make optimizations based on
56 * that knowledge, so an inline asm output operand is used to prevent
57 * optimizations that make assumptions about the address of the TLS variable.
59 * This is fragile and ultimately needs to be solved by a mechanism that is
60 * guaranteed to work by the compiler (e.g. stackless coroutines), but for now
61 * we use this approach to prevent issues.
65 * QEMU_DECLARE_CO_TLS:
66 * @type: the variable's C type
67 * @var: the variable name
69 * Declare an extern variable in Thread Local Storage from a header file:
72 * :caption: Declaring an extern variable in Thread Local Storage
74 * QEMU_DECLARE_CO_TLS(int, my_count)
76 * int c = get_my_count();
77 * set_my_count(c + 1);
78 * *get_ptr_my_count() = 0;
80 * This is a coroutine-safe replacement for the __thread keyword and is
81 * equivalent to the following code:
84 * :caption: Declaring a TLS variable using __thread
86 * extern __thread int my_count;
92 #define QEMU_DECLARE_CO_TLS(type, var) \
93 __attribute__((noinline)) type get_##var(void); \
94 __attribute__((noinline)) void set_##var(type v); \
95 __attribute__((noinline)) type *get_ptr_##var(void);
99 * @type: the variable's C type
100 * @var: the variable name
102 * Define a variable in Thread Local Storage that was previously declared from
103 * a header file with QEMU_DECLARE_CO_TLS():
106 * :caption: Defining a variable in Thread Local Storage
108 * QEMU_DEFINE_CO_TLS(int, my_count)
110 * This is a coroutine-safe replacement for the __thread keyword and is
111 * equivalent to the following code:
114 * :caption: Defining a TLS variable using __thread
116 * __thread int my_count;
118 #define QEMU_DEFINE_CO_TLS(type, var) \
119 static __thread type co_tls_##var; \
120 type get_##var(void) { asm volatile(""); return co_tls_##var; } \
121 void set_##var(type v) { asm volatile(""); co_tls_##var = v; } \
122 type *get_ptr_##var(void) \
123 { type *ptr = &co_tls_##var; asm volatile("" : "+rm" (ptr)); return ptr; }
126 * QEMU_DEFINE_STATIC_CO_TLS:
127 * @type: the variable's C type
128 * @var: the variable name
130 * Define a static variable in Thread Local Storage:
133 * :caption: Defining a static variable in Thread Local Storage
135 * QEMU_DEFINE_STATIC_CO_TLS(int, my_count)
137 * int c = get_my_count();
138 * set_my_count(c + 1);
139 * *get_ptr_my_count() = 0;
141 * This is a coroutine-safe replacement for the __thread keyword and is
142 * equivalent to the following code:
145 * :caption: Defining a static TLS variable using __thread
147 * static __thread int my_count;
153 #define QEMU_DEFINE_STATIC_CO_TLS(type, var) \
154 static __thread type co_tls_##var; \
155 static __attribute__((noinline, unused)) \
156 type get_##var(void) \
157 { asm volatile(""); return co_tls_##var; } \
158 static __attribute__((noinline, unused)) \
159 void set_##var(type v) \
160 { asm volatile(""); co_tls_##var = v; } \
161 static __attribute__((noinline, unused)) \
162 type *get_ptr_##var(void) \
163 { type *ptr = &co_tls_##var; asm volatile("" : "+rm" (ptr)); return ptr; }
165 #endif /* QEMU_COROUTINE_TLS_H */