userver: userver/compiler/impl/tls.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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