userver: userver/compiler/impl/tls.hpp Source File
Loading...
Searching...
No Matches
tls.hpp
1#pragma once
2
3#include <type_traits>
4#include <utility>
5
6USERVER_NAMESPACE_BEGIN
7
8namespace compiler::impl {
9
10/// @brief Each invocation creates a unique thread-local variable that can be
11/// used in a coroutine-safe manner.
12///
13/// The thread-local variable is initialized using the result of the factory.
14///
15/// The returned variable must not be used across coroutine context switches.
16/// That is, after any usage of userver synchronization primitives or clients
17/// (web or db), the reference is invalidated and should not be used.
18template <typename Func>
19__attribute__((noinline)) auto& ThreadLocal(Func&& factory) {
20 // Implementation note: this 'asm' and 'noinline' prevent the compiler
21 // from caching the TLS address across a coroutine context switch.
22 // The general approach is taken from:
23 // https://github.com/qemu/qemu/blob/stable-8.2/include/qemu/coroutine-tls.h#L153
24 using VariableType = std::invoke_result_t<Func&&>;
25
26 thread_local VariableType variable{std::forward<Func>(factory)()};
27 VariableType* ptr = &variable;
28 // clang-format off
29 // NOLINTNEXTLINE(hicpp-no-assembler)
30 asm volatile("" : "+rm" (ptr));
31 // clang-format on
32 return *ptr;
33}
34
35} // namespace compiler::impl
36
37USERVER_NAMESPACE_END