| /* |
| * QEMU Thread Local Storage for coroutines |
| * |
| * Copyright Red Hat |
| * |
| * SPDX-License-Identifier: LGPL-2.1-or-later |
| * |
| * This work is licensed under the terms of the GNU LGPL, version 2.1 or later. |
| * See the COPYING.LIB file in the top-level directory. |
| * |
| * It is forbidden to access Thread Local Storage in coroutines because |
| * compiler optimizations may cause values to be cached across coroutine |
| * re-entry. Coroutines can run in more than one thread through the course of |
| * their life, leading bugs when stale TLS values from the wrong thread are |
| * used as a result of compiler optimization. |
| * |
| * An example is: |
| * |
| * ..code-block:: c |
| * :caption: A coroutine that may see the wrong TLS value |
| * |
| * static __thread AioContext *current_aio_context; |
| * ... |
| * static void coroutine_fn foo(void) |
| * { |
| * aio_notify(current_aio_context); |
| * qemu_coroutine_yield(); |
| * aio_notify(current_aio_context); // <-- may be stale after yielding! |
| * } |
| * |
| * This header provides macros for safely defining variables in Thread Local |
| * Storage: |
| * |
| * ..code-block:: c |
| * :caption: A coroutine that safely uses TLS |
| * |
| * QEMU_DEFINE_STATIC_CO_TLS(AioContext *, current_aio_context) |
| * ... |
| * static void coroutine_fn foo(void) |
| * { |
| * aio_notify(get_current_aio_context()); |
| * qemu_coroutine_yield(); |
| * aio_notify(get_current_aio_context()); // <-- safe |
| * } |
| */ |
| |
| #ifndef QEMU_COROUTINE_TLS_H |
| #define QEMU_COROUTINE_TLS_H |
| |
| /* |
| * To stop the compiler from caching TLS values we define accessor functions |
| * with __attribute__((noinline)) plus asm volatile("") to prevent |
| * optimizations that override noinline. |
| * |
| * The compiler can still analyze noinline code and make optimizations based on |
| * that knowledge, so an inline asm output operand is used to prevent |
| * optimizations that make assumptions about the address of the TLS variable. |
| * |
| * This is fragile and ultimately needs to be solved by a mechanism that is |
| * guaranteed to work by the compiler (e.g. stackless coroutines), but for now |
| * we use this approach to prevent issues. |
| */ |
| |
| /** |
| * QEMU_DECLARE_CO_TLS: |
| * @type: the variable's C type |
| * @var: the variable name |
| * |
| * Declare an extern variable in Thread Local Storage from a header file: |
| * |
| * .. code-block:: c |
| * :caption: Declaring an extern variable in Thread Local Storage |
| * |
| * QEMU_DECLARE_CO_TLS(int, my_count) |
| * ... |
| * int c = get_my_count(); |
| * set_my_count(c + 1); |
| * *get_ptr_my_count() = 0; |
| * |
| * This is a coroutine-safe replacement for the __thread keyword and is |
| * equivalent to the following code: |
| * |
| * .. code-block:: c |
| * :caption: Declaring a TLS variable using __thread |
| * |
| * extern __thread int my_count; |
| * ... |
| * int c = my_count; |
| * my_count = c + 1; |
| * *(&my_count) = 0; |
| */ |
| #define QEMU_DECLARE_CO_TLS(type, var) \ |
| __attribute__((noinline)) type get_##var(void); \ |
| __attribute__((noinline)) void set_##var(type v); \ |
| __attribute__((noinline)) type *get_ptr_##var(void); |
| |
| /** |
| * QEMU_DEFINE_CO_TLS: |
| * @type: the variable's C type |
| * @var: the variable name |
| * |
| * Define a variable in Thread Local Storage that was previously declared from |
| * a header file with QEMU_DECLARE_CO_TLS(): |
| * |
| * .. code-block:: c |
| * :caption: Defining a variable in Thread Local Storage |
| * |
| * QEMU_DEFINE_CO_TLS(int, my_count) |
| * |
| * This is a coroutine-safe replacement for the __thread keyword and is |
| * equivalent to the following code: |
| * |
| * .. code-block:: c |
| * :caption: Defining a TLS variable using __thread |
| * |
| * __thread int my_count; |
| */ |
| #define QEMU_DEFINE_CO_TLS(type, var) \ |
| static __thread type co_tls_##var; \ |
| type get_##var(void) { asm volatile(""); return co_tls_##var; } \ |
| void set_##var(type v) { asm volatile(""); co_tls_##var = v; } \ |
| type *get_ptr_##var(void) \ |
| { type *ptr = &co_tls_##var; asm volatile("" : "+rm" (ptr)); return ptr; } |
| |
| /** |
| * QEMU_DEFINE_STATIC_CO_TLS: |
| * @type: the variable's C type |
| * @var: the variable name |
| * |
| * Define a static variable in Thread Local Storage: |
| * |
| * .. code-block:: c |
| * :caption: Defining a static variable in Thread Local Storage |
| * |
| * QEMU_DEFINE_STATIC_CO_TLS(int, my_count) |
| * ... |
| * int c = get_my_count(); |
| * set_my_count(c + 1); |
| * *get_ptr_my_count() = 0; |
| * |
| * This is a coroutine-safe replacement for the __thread keyword and is |
| * equivalent to the following code: |
| * |
| * .. code-block:: c |
| * :caption: Defining a static TLS variable using __thread |
| * |
| * static __thread int my_count; |
| * ... |
| * int c = my_count; |
| * my_count = c + 1; |
| * *(&my_count) = 0; |
| */ |
| #define QEMU_DEFINE_STATIC_CO_TLS(type, var) \ |
| static __thread type co_tls_##var; \ |
| static __attribute__((noinline, unused)) \ |
| type get_##var(void) \ |
| { asm volatile(""); return co_tls_##var; } \ |
| static __attribute__((noinline, unused)) \ |
| void set_##var(type v) \ |
| { asm volatile(""); co_tls_##var = v; } \ |
| static __attribute__((noinline, unused)) \ |
| type *get_ptr_##var(void) \ |
| { type *ptr = &co_tls_##var; asm volatile("" : "+rm" (ptr)); return ptr; } |
| |
| #endif /* QEMU_COROUTINE_TLS_H */ |