YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/util/threadlocal.h
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
//
18
// The following only applies to changes made to this file as part of YugaByte development.
19
//
20
// Portions Copyright (c) YugaByte, Inc.
21
//
22
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
23
// in compliance with the License.  You may obtain a copy of the License at
24
//
25
// http://www.apache.org/licenses/LICENSE-2.0
26
//
27
// Unless required by applicable law or agreed to in writing, software distributed under the License
28
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
29
// or implied.  See the License for the specific language governing permissions and limitations
30
// under the License.
31
//
32
#ifndef YB_UTIL_THREADLOCAL_H_
33
#define YB_UTIL_THREADLOCAL_H_
34
35
// Block-scoped static thread local implementation.
36
//
37
// Usage is similar to a C++11 thread_local. The BLOCK_STATIC_THREAD_LOCAL macro
38
// defines a thread-local pointer to the specified type, which is lazily
39
// instantiated by any thread entering the block for the first time. The
40
// constructor for the type T is invoked at macro execution time, as expected,
41
// and its destructor is invoked when the corresponding thread's Runnable
42
// returns, or when the thread exits.
43
//
44
// Inspired by Poco <http://pocoproject.org/docs/Poco.ThreadLocal.html>,
45
// Andrew Tomazos <http://stackoverflow.com/questions/12049684/>, and
46
// the C++11 thread_local API.
47
//
48
// Example usage:
49
//
50
// // Invokes a 3-arg constructor on SomeClass:
51
// BLOCK_STATIC_THREAD_LOCAL(SomeClass, instance, arg1, arg2, arg3);
52
// instance->DoSomething();
53
//
54
231M
#define BLOCK_STATIC_THREAD_LOCAL(T, t, ...)                                    \
55
231M
static __thread T* t;                                                           \
56
231M
do {                                                                            \
57
231M
  if (PREDICT_FALSE(t == NULL)) {                                               \
58
743k
    t = new T(__VA_ARGS__);                                                     \
59
743k
    threadlocal::internal::PerThreadDestructorList* dtor_list =                 \
60
743k
        new threadlocal::internal::PerThreadDestructorList();                   \
61
743k
    dtor_list->destructor = threadlocal::internal::Destroy<T>;                  \
62
743k
    dtor_list->arg = t;                                                         \
63
743k
    threadlocal::internal::AddDestructor(dtor_list);                            \
64
743k
  }                                                                             \
65
231M
} while (false)
66
67
// Class-scoped static thread local implementation.
68
//
69
// Very similar in implementation to the above block-scoped version, but
70
// requires a bit more syntax and vigilance to use properly.
71
//
72
// DECLARE_STATIC_THREAD_LOCAL(Type, instance_var_) must be placed in the
73
// class header, as usual for variable declarations.
74
//
75
// Because these variables are static, they must also be defined in the impl
76
// file with DEFINE_STATIC_THREAD_LOCAL(Type, Classname, instance_var_),
77
// which is very much like defining any static member, i.e. int Foo::member_.
78
//
79
// Finally, each thread must initialize the instance before using it by calling
80
// INIT_STATIC_THREAD_LOCAL(Type, instance_var_, ...). This is a cheap
81
// call, and may be invoked at the top of any method which may reference a
82
// thread-local variable.
83
//
84
// Due to all of these requirements, you should probably declare TLS members
85
// as private.
86
//
87
// Example usage:
88
//
89
// // foo.h
90
// #include "yb/utils/file.h"
91
// class Foo {
92
//  public:
93
//   void DoSomething(std::string s);
94
//  private:
95
//   DECLARE_STATIC_THREAD_LOCAL(utils::File, file_);
96
// };
97
//
98
// // foo.cc
99
// #include "yb/foo.h"
100
// DEFINE_STATIC_THREAD_LOCAL(utils::File, Foo, file_);
101
// void Foo::WriteToFile(std::string s) {
102
//   // Call constructor if necessary.
103
//   INIT_STATIC_THREAD_LOCAL(utils::File, file_, "/tmp/file_location.txt");
104
//   file_->Write(s);
105
// }
106
107
// Goes in the class declaration (usually in a header file).
108
// dtor must be destructed _after_ t, so it gets defined first.
109
// Uses a mangled variable name for dtor since it must also be a member of the
110
// class.
111
#define DECLARE_STATIC_THREAD_LOCAL(T, t)                                                     \
112
static __thread T* t
113
114
// You must also define the instance in the .cc file.
115
#define DEFINE_STATIC_THREAD_LOCAL(T, Class, t)                                               \
116
__thread T* Class::t
117
118
// Must be invoked at least once by each thread that will access t.
119
24
#define INIT_STATIC_THREAD_LOCAL(T, t, ...)                                       \
120
24
do {                                                                              \
121
24
  if (PREDICT_FALSE(t == NULL)) {                                                 \
122
8
    t = new T(__VA_ARGS__);                                                       \
123
8
    threadlocal::internal::PerThreadDestructorList* dtor_list =                   \
124
8
        new threadlocal::internal::PerThreadDestructorList();                     \
125
8
    dtor_list->destructor = threadlocal::internal::Destroy<T>;                    \
126
8
    dtor_list->arg = t;                                                           \
127
8
    threadlocal::internal::AddDestructor(dtor_list);                              \
128
8
  }                                                                               \
129
24
} while (false)
130
131
// Internal implementation below.
132
133
namespace yb {
134
namespace threadlocal {
135
namespace internal {
136
137
// List of destructors for all thread locals instantiated on a given thread.
138
struct PerThreadDestructorList {
139
  void (*destructor)(void*);
140
  void* arg;
141
  PerThreadDestructorList* next;
142
};
143
144
// Add a destructor to the list.
145
void AddDestructor(PerThreadDestructorList* p);
146
147
// Destroy the passed object of type T.
148
template<class T>
149
285k
static void Destroy(void* t) {
150
  // With tcmalloc, this should be pretty cheap (same thread as new).
151
285k
  delete reinterpret_cast<T*>(t);
152
285k
}
mt-threadlocal-test.cc:_ZN2yb11threadlocal8internalL7DestroyINS0_7CounterEEEvPv
Line
Count
Source
149
24
static void Destroy(void* t) {
150
  // With tcmalloc, this should be pretty cheap (same thread as new).
151
24
  delete reinterpret_cast<T*>(t);
152
24
}
mt-threadlocal-test.cc:_ZN2yb11threadlocal8internalL7DestroyINSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEEEvPv
Line
Count
Source
149
8
static void Destroy(void* t) {
150
  // With tcmalloc, this should be pretty cheap (same thread as new).
151
8
  delete reinterpret_cast<T*>(t);
152
8
}
thread_restrictions.cc:_ZN2yb11threadlocal8internalL7DestroyINS_12_GLOBAL__N_123LocalThreadRestrictionsEEEvPv
Line
Count
Source
149
285k
static void Destroy(void* t) {
150
  // With tcmalloc, this should be pretty cheap (same thread as new).
151
285k
  delete reinterpret_cast<T*>(t);
152
285k
}
153
154
} // namespace internal
155
} // namespace threadlocal
156
} // namespace yb
157
158
#endif // YB_UTIL_THREADLOCAL_H_