Implement type safety for TLS (#26942)

* Implement type safety for TLS

This is mostly free when compiler support is available, but requires
careful templating when implemented using pthread.

Significantly slimmed the tls.h interface; it now only defines the "TLS
keyword" for each supported compiler, delegating enforcement of correct
usage (i.e. must be static) to the compiler itself.

Implemented implicit conversion for the pthread wrapper so it can be
used (mostly) the same as native support. Notable exception to this is
that static_cast<void*> is needed when printing a pointer stored in TLS
as %p.

* Use GPR_THREAD_LOCAL macros consistently
pull/26974/head
Tamir Duberstein 4 years ago committed by GitHub
parent 59d7f38184
commit 00c03c55ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      BUILD
  2. 1
      CMakeLists.txt
  3. 1
      Makefile
  4. 5
      build_autogenerated.yaml
  5. 1
      config.m4
  6. 1
      config.w32
  7. 8
      gRPC-C++.podspec
  8. 9
      gRPC-Core.podspec
  9. 5
      grpc.gemspec
  10. 1
      grpc.gyp
  11. 5
      package.xml
  12. 3
      src/core/lib/gpr/log_linux.cc
  13. 143
      src/core/lib/gpr/tls.h
  14. 52
      src/core/lib/gpr/tls_gcc.h
  15. 54
      src/core/lib/gpr/tls_msvc.h
  16. 30
      src/core/lib/gpr/tls_pthread.cc
  17. 56
      src/core/lib/gpr/tls_pthread.h
  18. 48
      src/core/lib/gpr/tls_stdcpp.h
  19. 11
      src/core/lib/gprpp/thd_windows.cc
  20. 33
      src/core/lib/iomgr/ev_epoll1_linux.cc
  21. 34
      src/core/lib/iomgr/ev_epollex_linux.cc
  22. 32
      src/core/lib/iomgr/ev_poll_posix.cc
  23. 9
      src/core/lib/iomgr/exec_ctx.cc
  24. 30
      src/core/lib/iomgr/exec_ctx.h
  25. 11
      src/core/lib/iomgr/executor.cc
  26. 14
      src/core/lib/iomgr/timer_generic.cc
  27. 5
      src/core/lib/profiling/basic_timers.cc
  28. 32
      src/core/lib/surface/completion_queue.cc
  29. 1
      src/python/grpcio/grpc_core_dependencies.py
  30. 14
      test/core/gpr/tls_test.cc
  31. 18
      test/cpp/end2end/nonblocking_test.cc
  32. 5
      tools/doxygen/Doxyfile.c++.internal
  33. 5
      tools/doxygen/Doxyfile.core.internal

@ -638,7 +638,6 @@ grpc_cc_library(
"src/core/lib/gpr/time_posix.cc",
"src/core/lib/gpr/time_precise.cc",
"src/core/lib/gpr/time_windows.cc",
"src/core/lib/gpr/tls_pthread.cc",
"src/core/lib/gpr/tmpfile_msys.cc",
"src/core/lib/gpr/tmpfile_posix.cc",
"src/core/lib/gpr/tmpfile_windows.cc",
@ -667,10 +666,6 @@ grpc_cc_library(
"src/core/lib/gpr/string_windows.h",
"src/core/lib/gpr/time_precise.h",
"src/core/lib/gpr/tls.h",
"src/core/lib/gpr/tls_gcc.h",
"src/core/lib/gpr/tls_msvc.h",
"src/core/lib/gpr/tls_pthread.h",
"src/core/lib/gpr/tls_stdcpp.h",
"src/core/lib/gpr/tmpfile.h",
"src/core/lib/gpr/useful.h",
"src/core/lib/gprpp/arena.h",

1
CMakeLists.txt generated

@ -1387,7 +1387,6 @@ add_library(gpr
src/core/lib/gpr/time_posix.cc
src/core/lib/gpr/time_precise.cc
src/core/lib/gpr/time_windows.cc
src/core/lib/gpr/tls_pthread.cc
src/core/lib/gpr/tmpfile_msys.cc
src/core/lib/gpr/tmpfile_posix.cc
src/core/lib/gpr/tmpfile_windows.cc

1
Makefile generated

@ -943,7 +943,6 @@ LIBGPR_SRC = \
src/core/lib/gpr/time_posix.cc \
src/core/lib/gpr/time_precise.cc \
src/core/lib/gpr/time_windows.cc \
src/core/lib/gpr/tls_pthread.cc \
src/core/lib/gpr/tmpfile_msys.cc \
src/core/lib/gpr/tmpfile_posix.cc \
src/core/lib/gpr/tmpfile_windows.cc \

@ -308,10 +308,6 @@ libs:
- src/core/lib/gpr/string_windows.h
- src/core/lib/gpr/time_precise.h
- src/core/lib/gpr/tls.h
- src/core/lib/gpr/tls_gcc.h
- src/core/lib/gpr/tls_msvc.h
- src/core/lib/gpr/tls_pthread.h
- src/core/lib/gpr/tls_stdcpp.h
- src/core/lib/gpr/tmpfile.h
- src/core/lib/gpr/useful.h
- src/core/lib/gprpp/arena.h
@ -373,7 +369,6 @@ libs:
- src/core/lib/gpr/time_posix.cc
- src/core/lib/gpr/time_precise.cc
- src/core/lib/gpr/time_windows.cc
- src/core/lib/gpr/tls_pthread.cc
- src/core/lib/gpr/tmpfile_msys.cc
- src/core/lib/gpr/tmpfile_posix.cc
- src/core/lib/gpr/tmpfile_windows.cc

1
config.m4 generated

@ -415,7 +415,6 @@ if test "$PHP_GRPC" != "no"; then
src/core/lib/gpr/time_posix.cc \
src/core/lib/gpr/time_precise.cc \
src/core/lib/gpr/time_windows.cc \
src/core/lib/gpr/tls_pthread.cc \
src/core/lib/gpr/tmpfile_msys.cc \
src/core/lib/gpr/tmpfile_posix.cc \
src/core/lib/gpr/tmpfile_windows.cc \

1
config.w32 generated

@ -381,7 +381,6 @@ if (PHP_GRPC != "no") {
"src\\core\\lib\\gpr\\time_posix.cc " +
"src\\core\\lib\\gpr\\time_precise.cc " +
"src\\core\\lib\\gpr\\time_windows.cc " +
"src\\core\\lib\\gpr\\tls_pthread.cc " +
"src\\core\\lib\\gpr\\tmpfile_msys.cc " +
"src\\core\\lib\\gpr\\tmpfile_posix.cc " +
"src\\core\\lib\\gpr\\tmpfile_windows.cc " +

8
gRPC-C++.podspec generated

@ -539,10 +539,6 @@ Pod::Spec.new do |s|
'src/core/lib/gpr/string_windows.h',
'src/core/lib/gpr/time_precise.h',
'src/core/lib/gpr/tls.h',
'src/core/lib/gpr/tls_gcc.h',
'src/core/lib/gpr/tls_msvc.h',
'src/core/lib/gpr/tls_pthread.h',
'src/core/lib/gpr/tls_stdcpp.h',
'src/core/lib/gpr/tmpfile.h',
'src/core/lib/gpr/useful.h',
'src/core/lib/gprpp/arena.h',
@ -1205,10 +1201,6 @@ Pod::Spec.new do |s|
'src/core/lib/gpr/string_windows.h',
'src/core/lib/gpr/time_precise.h',
'src/core/lib/gpr/tls.h',
'src/core/lib/gpr/tls_gcc.h',
'src/core/lib/gpr/tls_msvc.h',
'src/core/lib/gpr/tls_pthread.h',
'src/core/lib/gpr/tls_stdcpp.h',
'src/core/lib/gpr/tmpfile.h',
'src/core/lib/gpr/useful.h',
'src/core/lib/gprpp/arena.h',

9
gRPC-Core.podspec generated

@ -905,11 +905,6 @@ Pod::Spec.new do |s|
'src/core/lib/gpr/time_precise.h',
'src/core/lib/gpr/time_windows.cc',
'src/core/lib/gpr/tls.h',
'src/core/lib/gpr/tls_gcc.h',
'src/core/lib/gpr/tls_msvc.h',
'src/core/lib/gpr/tls_pthread.cc',
'src/core/lib/gpr/tls_pthread.h',
'src/core/lib/gpr/tls_stdcpp.h',
'src/core/lib/gpr/tmpfile.h',
'src/core/lib/gpr/tmpfile_msys.cc',
'src/core/lib/gpr/tmpfile_posix.cc',
@ -1793,10 +1788,6 @@ Pod::Spec.new do |s|
'src/core/lib/gpr/string_windows.h',
'src/core/lib/gpr/time_precise.h',
'src/core/lib/gpr/tls.h',
'src/core/lib/gpr/tls_gcc.h',
'src/core/lib/gpr/tls_msvc.h',
'src/core/lib/gpr/tls_pthread.h',
'src/core/lib/gpr/tls_stdcpp.h',
'src/core/lib/gpr/tmpfile.h',
'src/core/lib/gpr/useful.h',
'src/core/lib/gprpp/arena.h',

5
grpc.gemspec generated

@ -818,11 +818,6 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/gpr/time_precise.h )
s.files += %w( src/core/lib/gpr/time_windows.cc )
s.files += %w( src/core/lib/gpr/tls.h )
s.files += %w( src/core/lib/gpr/tls_gcc.h )
s.files += %w( src/core/lib/gpr/tls_msvc.h )
s.files += %w( src/core/lib/gpr/tls_pthread.cc )
s.files += %w( src/core/lib/gpr/tls_pthread.h )
s.files += %w( src/core/lib/gpr/tls_stdcpp.h )
s.files += %w( src/core/lib/gpr/tmpfile.h )
s.files += %w( src/core/lib/gpr/tmpfile_msys.cc )
s.files += %w( src/core/lib/gpr/tmpfile_posix.cc )

1
grpc.gyp generated

@ -445,7 +445,6 @@
'src/core/lib/gpr/time_posix.cc',
'src/core/lib/gpr/time_precise.cc',
'src/core/lib/gpr/time_windows.cc',
'src/core/lib/gpr/tls_pthread.cc',
'src/core/lib/gpr/tmpfile_msys.cc',
'src/core/lib/gpr/tmpfile_posix.cc',
'src/core/lib/gpr/tmpfile_windows.cc',

5
package.xml generated

@ -798,11 +798,6 @@
<file baseinstalldir="/" name="src/core/lib/gpr/time_precise.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gpr/time_windows.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/gpr/tls.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gpr/tls_gcc.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gpr/tls_msvc.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gpr/tls_pthread.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/gpr/tls_pthread.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gpr/tls_stdcpp.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gpr/tmpfile.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/gpr/tmpfile_msys.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/gpr/tmpfile_posix.cc" role="src" />

@ -42,6 +42,7 @@
#include <string>
#include "absl/strings/str_format.h"
#include "src/core/lib/gpr/tls.h"
#include "src/core/lib/gprpp/examine_stack.h"
int gpr_should_log_stacktrace(gpr_log_severity severity);
@ -74,7 +75,7 @@ void gpr_default_log(gpr_log_func_args* args) {
time_t timer;
gpr_timespec now = gpr_now(GPR_CLOCK_REALTIME);
struct tm tm;
static __thread long tid = 0;
static GPR_THREAD_LOCAL(long) tid = 0;
if (tid == 0) tid = sys_gettid();
timer = static_cast<time_t>(now.tv_sec);

@ -21,52 +21,143 @@
#include <grpc/support/port_platform.h>
/** Thread local storage.
A minimal wrapper that should be implementable across many compilers,
and implementable efficiently across most modern compilers.
#include <type_traits>
Thread locals have type intptr_t.
/** Thread local storage.
Declaring a thread local variable 'foo':
GPR_TLS_DECL(foo);
Thread locals always have static scope.
Usage is the same as C++ thread_local. Declaring a thread local:
static GPR_THREAD_LOCAL(uint32_t) foo;
Declaring a thread local class variable 'foo':
GPR_TLS_CLASS_DECL(foo);
Initializing a thread local (must be done at library initialization time):
gpr_tls_init(foo);
Defining the thread local class variable:
GPR_TLS_CLASS_DEF(foo);
Destroying a thread local:
gpr_tls_destroy(foo);
Initializing a thread local (must be done at library initialization
time):
gpr_tls_init(&foo);
ALL functions here may be implemented as macros. */
Destroying a thread local:
gpr_tls_destroy(&foo);
namespace grpc_core {
Setting a thread local (returns new_value):
gpr_tls_set(&foo, new_value);
// This class is never instantiated. It exists to statically ensure that all
// TLS usage is compatible with the most restrictive implementation, allowing
// developers to write correct code regardless of the platform they develop on.
template <typename T, typename = typename std::enable_if<(
std::is_trivially_destructible<T>::value &&
sizeof(T) <= sizeof(void*) &&
alignof(void*) % alignof(T) == 0)>::type>
class TlsTypeConstrainer {
static_assert(std::is_trivially_destructible<T>::value &&
sizeof(T) <= sizeof(void*) &&
alignof(void*) % alignof(T) == 0,
"unsupported type for TLS");
Accessing a thread local:
current_value = gpr_tls_get(&foo);
public:
using Type = T;
};
ALL functions here may be implemented as macros. */
} // namespace grpc_core
#ifdef GPR_STDCPP_TLS
#include "src/core/lib/gpr/tls_stdcpp.h"
#define GPR_THREAD_LOCAL(type) \
thread_local grpc_core::TlsTypeConstrainer<type>::Type
#endif
#ifdef GPR_GCC_TLS
#include "src/core/lib/gpr/tls_gcc.h"
#define GPR_THREAD_LOCAL(type) \
__thread grpc_core::TlsTypeConstrainer<type>::Type
#endif
#ifdef GPR_MSVC_TLS
#include "src/core/lib/gpr/tls_msvc.h"
#define GPR_THREAD_LOCAL(type) \
__declspec(thread) grpc_core::TlsTypeConstrainer<type>::Type
#endif
#ifdef GPR_PTHREAD_TLS
#include "src/core/lib/gpr/tls_pthread.h"
#include <grpc/support/log.h> /* for GPR_ASSERT */
#include <pthread.h>
namespace grpc_core {
template <typename T>
class PthreadTlsImpl : TlsTypeConstrainer<T> {
public:
PthreadTlsImpl() = default;
PthreadTlsImpl(const PthreadTlsImpl&) = delete;
PthreadTlsImpl& operator=(const PthreadTlsImpl&) = delete;
void Init() { GPR_ASSERT(0 == pthread_key_create(&key_, nullptr)); }
void Destroy() { GPR_ASSERT(0 == pthread_key_delete(key_)); }
operator T() const { return Cast<T>(pthread_getspecific(key_)); }
T operator=(T t) {
GPR_ASSERT(0 == pthread_setspecific(key_, Cast<T>(t)));
return t;
}
private:
// TODO(C++17): Replace these helpers with constexpr if statements inline.
template <typename V>
static typename std::enable_if<std::is_pointer<V>::value, V>::type Cast(
void* object) {
return static_cast<V>(object);
}
template <typename V>
static typename std::enable_if<
!std::is_pointer<V>::value && std::is_integral<V>::value, V>::type
Cast(void* object) {
return reinterpret_cast<uintptr_t>(object);
}
template <typename V>
static void* Cast(
typename std::enable_if<std::is_pointer<V>::value, V>::type t) {
return t;
}
template <typename V>
static void* Cast(typename std::enable_if<!std::is_pointer<V>::value &&
std::is_integral<V>::value,
V>::type t) {
return reinterpret_cast<void*>(uintptr_t(t));
}
pthread_key_t key_;
};
// This class is never instantiated. It exists to statically ensure that all
// TLS usage is compatible with the most restrictive implementation, allowing
// developers to write correct code regardless of the platform they develop on.
template <typename T>
class TriviallyDestructibleAsserter {
// This type is often used as a global; since the type itself is hidden by the
// macros, enforce compliance with the style guide here rather than at the
// caller. See
// https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables.
static_assert(std::is_trivially_destructible<T>::value,
"TLS wrapper must be trivially destructible");
public:
using Type = T;
};
} // namespace grpc_core
#define GPR_THREAD_LOCAL(type) \
grpc_core::TriviallyDestructibleAsserter< \
grpc_core::PthreadTlsImpl<type>>::Type
#define gpr_tls_init(tls) (tls).Init()
#define gpr_tls_destroy(tls) (tls).Destroy()
#else
#define gpr_tls_init(tls) \
do { \
} while (0)
#define gpr_tls_destroy(tls) \
do { \
} while (0)
#endif
#endif /* GRPC_CORE_LIB_GPR_TLS_H */

@ -1,52 +0,0 @@
/*
*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPC_CORE_LIB_GPR_TLS_GCC_H
#define GRPC_CORE_LIB_GPR_TLS_GCC_H
#include <grpc/support/port_platform.h>
#include <stdbool.h>
#include <grpc/support/log.h>
/** Thread local storage based on gcc compiler primitives.
#include tls.h to use this - and see that file for documentation */
struct gpr_gcc_thread_local {
intptr_t value;
};
#define GPR_TLS_DECL(name) \
static __thread struct gpr_gcc_thread_local name = {0}
#define GPR_TLS_CLASS_DECL(name) \
static __thread struct gpr_gcc_thread_local name
#define GPR_TLS_CLASS_DEF(name) __thread struct gpr_gcc_thread_local name = {0}
#define gpr_tls_init(tls) \
do { \
} while (0)
#define gpr_tls_destroy(tls) \
do { \
} while (0)
#define gpr_tls_set(tls, new_value) (((tls)->value) = (new_value))
#define gpr_tls_get(tls) ((tls)->value)
#endif /* GRPC_CORE_LIB_GPR_TLS_GCC_H */

@ -1,54 +0,0 @@
/*
*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPC_CORE_LIB_GPR_TLS_MSVC_H
#define GRPC_CORE_LIB_GPR_TLS_MSVC_H
/** Thread local storage based on ms visual c compiler primitives.
#include <grpc/support/port_platform.h>
#include tls.h to use this - and see that file for documentation */
#include <cstdint>
struct gpr_msvc_thread_local {
intptr_t value;
};
/** Use GPR_TLS_DECL to declare tls static variables outside a class */
#define GPR_TLS_DECL(name) \
static __declspec(thread) struct gpr_msvc_thread_local name = {0}
/** Use GPR_TLS_CLASS_DECL to declare tls static variable members of a class.
* GPR_TLS_CLASS_DEF needs to be called to define this member. */
#define GPR_TLS_CLASS_DECL(name) \
static __declspec(thread) struct gpr_msvc_thread_local name
#define GPR_TLS_CLASS_DEF(name) \
__declspec(thread) struct gpr_msvc_thread_local name = {0}
#define gpr_tls_init(tls) \
do { \
} while (0)
#define gpr_tls_destroy(tls) \
do { \
} while (0)
#define gpr_tls_set(tls, new_value) (((tls)->value) = (new_value))
#define gpr_tls_get(tls) ((tls)->value)
#endif /* GRPC_CORE_LIB_GPR_TLS_MSVC_H */

@ -1,30 +0,0 @@
/*
*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <grpc/support/port_platform.h>
#ifdef GPR_PTHREAD_TLS
#include "src/core/lib/gpr/tls.h"
intptr_t gpr_tls_set(struct gpr_pthread_thread_local* tls, intptr_t value) {
GPR_ASSERT(0 == pthread_setspecific(tls->key, (void*)value));
return value;
}
#endif /* GPR_PTHREAD_TLS */

@ -1,56 +0,0 @@
/*
*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPC_CORE_LIB_GPR_TLS_PTHREAD_H
#define GRPC_CORE_LIB_GPR_TLS_PTHREAD_H
#include <grpc/support/port_platform.h>
#include <grpc/support/log.h> /* for GPR_ASSERT */
#include <pthread.h>
/** Thread local storage based on pthread library calls.
#include tls.h to use this - and see that file for documentation */
struct gpr_pthread_thread_local {
pthread_key_t key;
};
/** Use GPR_TLS_DECL to declare tls static variables outside a class */
#define GPR_TLS_DECL(name) static struct gpr_pthread_thread_local name = {0}
/** Use GPR_TLS_CLASS_DECL to declare tls static variable members of a class.
* GPR_TLS_CLASS_DEF needs to be called to define this member. */
#define GPR_TLS_CLASS_DECL(name) static struct gpr_pthread_thread_local name
/** Use GPR_TLS_CLASS_DEF to declare tls static variable members of a class.
* GPR_TLS_CLASS_DEF needs to be called to define this member. */
#define GPR_TLS_CLASS_DEF(name) struct gpr_pthread_thread_local name = {0}
#define gpr_tls_init(tls) GPR_ASSERT(0 == pthread_key_create(&(tls)->key, NULL))
#define gpr_tls_destroy(tls) pthread_key_delete((tls)->key)
#define gpr_tls_get(tls) ((intptr_t)pthread_getspecific((tls)->key))
#ifdef __cplusplus
extern "C" {
#endif
intptr_t gpr_tls_set(struct gpr_pthread_thread_local* tls, intptr_t value);
#ifdef __cplusplus
}
#endif
#endif /* GRPC_CORE_LIB_GPR_TLS_PTHREAD_H */

@ -1,48 +0,0 @@
/*
*
* Copyright 2020 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#ifndef GRPC_CORE_LIB_GPR_TLS_STDCPP_H
#define GRPC_CORE_LIB_GPR_TLS_STDCPP_H
#include <grpc/support/port_platform.h>
/** Thread local storage based on C++ thread_local.
#include tls.h to use this - and see that file for documentation */
/** Use GPR_TLS_DECL to declare tls static variables outside a class */
#define GPR_TLS_DECL(name) thread_local static intptr_t name = 0
/** Use GPR_TLS_CLASS_DECL to declare tls static variable members of a class.
* GPR_TLS_CLASS_DEF needs to be called to define this member. */
#define GPR_TLS_CLASS_DECL(name) thread_local static intptr_t name
#define GPR_TLS_CLASS_DEF(name) thread_local intptr_t name = 0
#define gpr_tls_init(tls) \
do { \
} while (0)
#define gpr_tls_destroy(tls) \
do { \
} while (0)
#define gpr_tls_set(tls, new_value) (*(tls) = (new_value))
#define gpr_tls_get(tls) (*(tls))
#endif /* GRPC_CORE_LIB_GPR_TLS_STDCPP_H */

@ -29,16 +29,9 @@
#include <grpc/support/thd_id.h>
#include <string.h>
#include "src/core/lib/gpr/tls.h"
#include "src/core/lib/gprpp/memory.h"
#if defined(_MSC_VER)
#define thread_local __declspec(thread)
#elif defined(__GNUC__)
#define thread_local __thread
#else
#error "Unknown compiler - please file a bug report"
#endif
namespace {
class ThreadInternalsWindows;
struct thd_info {
@ -49,7 +42,7 @@ struct thd_info {
bool joinable; /* whether it is joinable */
};
thread_local struct thd_info* g_thd_info;
GPR_THREAD_LOCAL(struct thd_info*) g_thd_info;
class ThreadInternalsWindows
: public grpc_core::internal::ThreadInternalsInterface {

@ -464,8 +464,8 @@ static void fd_has_errors(grpc_fd* fd) { fd->error_closure->SetReady(); }
* Pollset Definitions
*/
GPR_TLS_DECL(g_current_thread_pollset);
GPR_TLS_DECL(g_current_thread_worker);
static GPR_THREAD_LOCAL(grpc_pollset*) g_current_thread_pollset;
static GPR_THREAD_LOCAL(grpc_pollset_worker*) g_current_thread_worker;
/* The designated poller */
static gpr_atm g_active_poller;
@ -515,8 +515,8 @@ static size_t choose_neighborhood(void) {
}
static grpc_error_handle pollset_global_init(void) {
gpr_tls_init(&g_current_thread_pollset);
gpr_tls_init(&g_current_thread_worker);
gpr_tls_init(g_current_thread_pollset);
gpr_tls_init(g_current_thread_worker);
gpr_atm_no_barrier_store(&g_active_poller, 0);
global_wakeup_fd.read_fd = -1;
grpc_error_handle err = grpc_wakeup_fd_init(&global_wakeup_fd);
@ -538,8 +538,8 @@ static grpc_error_handle pollset_global_init(void) {
}
static void pollset_global_shutdown(void) {
gpr_tls_destroy(&g_current_thread_pollset);
gpr_tls_destroy(&g_current_thread_worker);
gpr_tls_destroy(g_current_thread_pollset);
gpr_tls_destroy(g_current_thread_worker);
if (global_wakeup_fd.read_fd != -1) grpc_wakeup_fd_destroy(&global_wakeup_fd);
for (size_t i = 0; i < g_num_neighborhoods; i++) {
gpr_mu_destroy(&g_neighborhoods[i].mu);
@ -1027,8 +1027,8 @@ static grpc_error_handle pollset_work(grpc_pollset* ps,
}
if (begin_worker(ps, &worker, worker_hdl, deadline)) {
gpr_tls_set(&g_current_thread_pollset, (intptr_t)ps);
gpr_tls_set(&g_current_thread_worker, (intptr_t)&worker);
g_current_thread_pollset = ps;
g_current_thread_worker = &worker;
GPR_ASSERT(!ps->shutting_down);
GPR_ASSERT(!ps->seen_inactive);
@ -1055,13 +1055,13 @@ static grpc_error_handle pollset_work(grpc_pollset* ps,
gpr_mu_lock(&ps->mu); /* lock */
gpr_tls_set(&g_current_thread_worker, 0);
g_current_thread_worker = nullptr;
} else {
gpr_tls_set(&g_current_thread_pollset, (intptr_t)ps);
g_current_thread_pollset = ps;
}
end_worker(ps, &worker, worker_hdl);
gpr_tls_set(&g_current_thread_pollset, 0);
g_current_thread_pollset = nullptr;
return error;
}
@ -1074,9 +1074,8 @@ static grpc_error_handle pollset_kick(grpc_pollset* pollset,
std::vector<std::string> log;
log.push_back(absl::StrFormat(
"PS:%p KICK:%p curps=%p curworker=%p root=%p", pollset, specific_worker,
reinterpret_cast<void*>(gpr_tls_get(&g_current_thread_pollset)),
reinterpret_cast<void*>(gpr_tls_get(&g_current_thread_worker)),
pollset->root_worker));
static_cast<void*>(g_current_thread_pollset),
static_cast<void*>(g_current_thread_worker), pollset->root_worker));
if (pollset->root_worker != nullptr) {
log.push_back(absl::StrFormat(
" {kick_state=%s next=%p {kick_state=%s}}",
@ -1092,8 +1091,7 @@ static grpc_error_handle pollset_kick(grpc_pollset* pollset,
}
if (specific_worker == nullptr) {
if (gpr_tls_get(&g_current_thread_pollset) !=
reinterpret_cast<intptr_t>(pollset)) {
if (g_current_thread_pollset != pollset) {
grpc_pollset_worker* root_worker = pollset->root_worker;
if (root_worker == nullptr) {
GRPC_STATS_INC_POLLSET_KICKED_WITHOUT_POLLER();
@ -1185,8 +1183,7 @@ static grpc_error_handle pollset_kick(grpc_pollset* pollset,
gpr_log(GPR_INFO, " .. specific worker already kicked");
}
goto done;
} else if (gpr_tls_get(&g_current_thread_worker) ==
reinterpret_cast<intptr_t>(specific_worker)) {
} else if (g_current_thread_worker == specific_worker) {
GRPC_STATS_INC_POLLSET_KICK_OWN_THREAD();
if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) {
gpr_log(GPR_INFO, " .. mark %p kicked", specific_worker);

@ -643,20 +643,20 @@ static grpc_error_handle pollable_add_fd(pollable* p, grpc_fd* fd) {
* Pollset Definitions
*/
GPR_TLS_DECL(g_current_thread_pollset);
GPR_TLS_DECL(g_current_thread_worker);
static GPR_THREAD_LOCAL(grpc_pollset*) g_current_thread_pollset;
static GPR_THREAD_LOCAL(grpc_pollset_worker*) g_current_thread_worker;
/* Global state management */
static grpc_error_handle pollset_global_init(void) {
gpr_tls_init(&g_current_thread_pollset);
gpr_tls_init(&g_current_thread_worker);
gpr_tls_init(g_current_thread_pollset);
gpr_tls_init(g_current_thread_worker);
return pollable_create(PO_EMPTY, &g_empty_pollable);
}
static void pollset_global_shutdown(void) {
POLLABLE_UNREF(g_empty_pollable, "g_empty_pollable");
gpr_tls_destroy(&g_current_thread_pollset);
gpr_tls_destroy(&g_current_thread_worker);
gpr_tls_destroy(g_current_thread_pollset);
gpr_tls_destroy(g_current_thread_worker);
}
/* pollset->mu must be held while calling this function */
@ -693,8 +693,7 @@ static grpc_error_handle kick_one_worker(grpc_pollset_worker* specific_worker) {
GRPC_STATS_INC_POLLSET_KICKED_AGAIN();
return GRPC_ERROR_NONE;
}
if (gpr_tls_get(&g_current_thread_worker) ==
reinterpret_cast<intptr_t>(specific_worker)) {
if (g_current_thread_worker == specific_worker) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) {
gpr_log(GPR_INFO, "PS:%p kicked_specific_but_awake", p);
}
@ -731,14 +730,13 @@ static grpc_error_handle pollset_kick(grpc_pollset* pollset,
GRPC_STATS_INC_POLLSET_KICK();
if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) {
gpr_log(GPR_INFO,
"PS:%p kick %p tls_pollset=%" PRIxPTR " tls_worker=%" PRIxPTR
" pollset.root_worker=%p",
pollset, specific_worker, gpr_tls_get(&g_current_thread_pollset),
gpr_tls_get(&g_current_thread_worker), pollset->root_worker);
"PS:%p kick %p tls_pollset=%p tls_worker=%p pollset.root_worker=%p",
pollset, specific_worker,
static_cast<void*>(g_current_thread_pollset),
static_cast<void*>(g_current_thread_worker), pollset->root_worker);
}
if (specific_worker == nullptr) {
if (gpr_tls_get(&g_current_thread_pollset) !=
reinterpret_cast<intptr_t>(pollset)) {
if (g_current_thread_pollset != pollset) {
if (pollset->root_worker == nullptr) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_polling_trace)) {
gpr_log(GPR_INFO, "PS:%p kicked_any_without_poller", pollset);
@ -1132,8 +1130,8 @@ static grpc_error_handle pollset_work(grpc_pollset* pollset,
pollset->kicked_without_poller = false;
} else {
if (begin_worker(pollset, WORKER_PTR, worker_hdl, deadline)) {
gpr_tls_set(&g_current_thread_pollset, (intptr_t)pollset);
gpr_tls_set(&g_current_thread_worker, (intptr_t)WORKER_PTR);
g_current_thread_pollset = pollset;
g_current_thread_worker = WORKER_PTR;
if (WORKER_PTR->pollable_obj->event_cursor ==
WORKER_PTR->pollable_obj->event_count) {
append_error(&error, pollable_epoll(WORKER_PTR->pollable_obj, deadline),
@ -1144,8 +1142,8 @@ static grpc_error_handle pollset_work(grpc_pollset* pollset,
pollable_process_events(pollset, WORKER_PTR->pollable_obj, false),
err_desc);
grpc_core::ExecCtx::Get()->Flush();
gpr_tls_set(&g_current_thread_pollset, 0);
gpr_tls_set(&g_current_thread_worker, 0);
g_current_thread_pollset = nullptr;
g_current_thread_worker = nullptr;
}
end_worker(pollset, WORKER_PTR, worker_hdl);
}

@ -706,8 +706,8 @@ static void fd_end_poll(grpc_fd_watcher* watcher, int got_read, int got_write) {
* pollset_posix.c
*/
GPR_TLS_DECL(g_current_thread_poller);
GPR_TLS_DECL(g_current_thread_worker);
static GPR_THREAD_LOCAL(grpc_pollset*) g_current_thread_poller;
static GPR_THREAD_LOCAL(grpc_pollset_worker*) g_current_thread_worker;
static void remove_worker(grpc_pollset* /*p*/, grpc_pollset_worker* worker) {
worker->prev->next = worker->next;
@ -776,8 +776,7 @@ static grpc_error_handle pollset_kick_ext(grpc_pollset* p,
&error, grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd));
}
p->kicked_without_pollers = true;
} else if (gpr_tls_get(&g_current_thread_worker) !=
reinterpret_cast<intptr_t>(specific_worker)) {
} else if (g_current_thread_worker != specific_worker) {
GPR_TIMER_MARK("different_thread_worker", 0);
if ((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) != 0) {
specific_worker->reevaluate_polling_on_wakeup = true;
@ -794,20 +793,17 @@ static grpc_error_handle pollset_kick_ext(grpc_pollset* p,
kick_append_error(&error,
grpc_wakeup_fd_wakeup(&specific_worker->wakeup_fd->fd));
}
} else if (gpr_tls_get(&g_current_thread_poller) !=
reinterpret_cast<intptr_t>(p)) {
} else if (g_current_thread_poller != p) {
GPR_ASSERT((flags & GRPC_POLLSET_REEVALUATE_POLLING_ON_WAKEUP) == 0);
GPR_TIMER_MARK("kick_anonymous", 0);
specific_worker = pop_front_worker(p);
if (specific_worker != nullptr) {
if (gpr_tls_get(&g_current_thread_worker) ==
reinterpret_cast<intptr_t>(specific_worker)) {
if (g_current_thread_worker == specific_worker) {
GPR_TIMER_MARK("kick_anonymous_not_self", 0);
push_back_worker(p, specific_worker);
specific_worker = pop_front_worker(p);
if ((flags & GRPC_POLLSET_CAN_KICK_SELF) == 0 &&
gpr_tls_get(&g_current_thread_worker) ==
reinterpret_cast<intptr_t>(specific_worker)) {
g_current_thread_worker == specific_worker) {
push_back_worker(p, specific_worker);
specific_worker = nullptr;
}
@ -836,14 +832,14 @@ static grpc_error_handle pollset_kick(grpc_pollset* p,
/* global state management */
static grpc_error_handle pollset_global_init(void) {
gpr_tls_init(&g_current_thread_poller);
gpr_tls_init(&g_current_thread_worker);
gpr_tls_init(g_current_thread_poller);
gpr_tls_init(g_current_thread_worker);
return GRPC_ERROR_NONE;
}
static void pollset_global_shutdown(void) {
gpr_tls_destroy(&g_current_thread_poller);
gpr_tls_destroy(&g_current_thread_worker);
gpr_tls_destroy(g_current_thread_poller);
gpr_tls_destroy(g_current_thread_worker);
}
/* main interface */
@ -959,7 +955,7 @@ static grpc_error_handle pollset_work(grpc_pollset* pollset,
re-evaluate our pollers (this allows poll() based pollers to
ensure they don't miss wakeups) */
keep_polling = 1;
gpr_tls_set(&g_current_thread_poller, (intptr_t)pollset);
g_current_thread_poller = pollset;
while (keep_polling) {
keep_polling = 0;
if (!pollset->kicked_without_pollers ||
@ -967,7 +963,7 @@ static grpc_error_handle pollset_work(grpc_pollset* pollset,
if (!added_worker) {
push_front_worker(pollset, &worker);
added_worker = 1;
gpr_tls_set(&g_current_thread_worker, (intptr_t)&worker);
g_current_thread_worker = &worker;
}
GPR_TIMER_SCOPE("maybe_work_and_unlock", 0);
#define POLLOUT_CHECK (POLLOUT | POLLHUP | POLLERR)
@ -1115,10 +1111,10 @@ static grpc_error_handle pollset_work(grpc_pollset* pollset,
keep_polling = 1;
}
}
gpr_tls_set(&g_current_thread_poller, 0);
g_current_thread_poller = nullptr;
if (added_worker) {
remove_worker(pollset, &worker);
gpr_tls_set(&g_current_thread_worker, 0);
g_current_thread_worker = nullptr;
}
/* release wakeup fd to the local pool */
worker.wakeup_fd->next = pollset->local_wakeup_cache;

@ -131,13 +131,14 @@ grpc_millis grpc_cycle_counter_to_millis_round_up(gpr_cycle_counter cycles) {
}
namespace grpc_core {
GPR_TLS_CLASS_DEF(ExecCtx::exec_ctx_);
GPR_TLS_CLASS_DEF(ApplicationCallbackExecCtx::callback_exec_ctx_);
GPR_THREAD_LOCAL(ExecCtx*) ExecCtx::exec_ctx_;
GPR_THREAD_LOCAL(ApplicationCallbackExecCtx*)
ApplicationCallbackExecCtx::callback_exec_ctx_;
// WARNING: for testing purposes only!
void ExecCtx::TestOnlyGlobalInit(gpr_timespec new_val) {
g_start_time = new_val;
gpr_tls_init(&exec_ctx_);
gpr_tls_init(exec_ctx_);
}
void ExecCtx::GlobalInit(void) {
@ -148,7 +149,7 @@ void ExecCtx::GlobalInit(void) {
g_start_time = gpr_now(GPR_CLOCK_MONOTONIC);
const gpr_cycle_counter cycle_after = gpr_get_cycle_counter();
g_start_cycle = (cycle_before + cycle_after) / 2;
gpr_tls_init(&exec_ctx_);
gpr_tls_init(exec_ctx_);
}
bool ExecCtx::Flush() {

@ -216,16 +216,12 @@ class ExecCtx {
static void GlobalInit(void);
/** Global shutdown for ExecCtx. Called by iomgr. */
static void GlobalShutdown(void) { gpr_tls_destroy(&exec_ctx_); }
static void GlobalShutdown(void) { gpr_tls_destroy(exec_ctx_); }
/** Gets pointer to current exec_ctx. */
static ExecCtx* Get() {
return reinterpret_cast<ExecCtx*>(gpr_tls_get(&exec_ctx_));
}
static ExecCtx* Get() { return exec_ctx_; }
static void Set(ExecCtx* exec_ctx) {
gpr_tls_set(&exec_ctx_, reinterpret_cast<intptr_t>(exec_ctx));
}
static void Set(ExecCtx* exec_ctx) { exec_ctx_ = exec_ctx; }
static void Run(const DebugLocation& location, grpc_closure* closure,
grpc_error_handle error);
@ -251,7 +247,7 @@ class ExecCtx {
bool now_is_valid_ = false;
grpc_millis now_ = 0;
GPR_TLS_CLASS_DECL(exec_ctx_);
static GPR_THREAD_LOCAL(ExecCtx*) exec_ctx_;
ExecCtx* last_exec_ctx_ = Get();
};
@ -313,8 +309,7 @@ class ApplicationCallbackExecCtx {
}
~ApplicationCallbackExecCtx() {
if (reinterpret_cast<ApplicationCallbackExecCtx*>(
gpr_tls_get(&callback_exec_ctx_)) == this) {
if (Get() == this) {
while (head_ != nullptr) {
auto* f = head_;
head_ = f->internal_next;
@ -323,7 +318,7 @@ class ApplicationCallbackExecCtx {
}
(*f->functor_run)(f, f->internal_success);
}
gpr_tls_set(&callback_exec_ctx_, reinterpret_cast<intptr_t>(nullptr));
callback_exec_ctx_ = nullptr;
if (!(GRPC_APP_CALLBACK_EXEC_CTX_FLAG_IS_INTERNAL_THREAD & flags_)) {
grpc_core::Fork::DecExecCtxCount();
}
@ -335,17 +330,14 @@ class ApplicationCallbackExecCtx {
uintptr_t Flags() { return flags_; }
static ApplicationCallbackExecCtx* Get() {
return reinterpret_cast<ApplicationCallbackExecCtx*>(
gpr_tls_get(&callback_exec_ctx_));
}
static ApplicationCallbackExecCtx* Get() { return callback_exec_ctx_; }
static void Set(ApplicationCallbackExecCtx* exec_ctx, uintptr_t flags) {
if (Get() == nullptr) {
if (!(GRPC_APP_CALLBACK_EXEC_CTX_FLAG_IS_INTERNAL_THREAD & flags)) {
grpc_core::Fork::IncExecCtxCount();
}
gpr_tls_set(&callback_exec_ctx_, reinterpret_cast<intptr_t>(exec_ctx));
callback_exec_ctx_ = exec_ctx;
}
}
@ -365,10 +357,10 @@ class ApplicationCallbackExecCtx {
}
/** Global initialization for ApplicationCallbackExecCtx. Called by init. */
static void GlobalInit(void) { gpr_tls_init(&callback_exec_ctx_); }
static void GlobalInit(void) { gpr_tls_init(callback_exec_ctx_); }
/** Global shutdown for ApplicationCallbackExecCtx. Called by init. */
static void GlobalShutdown(void) { gpr_tls_destroy(&callback_exec_ctx_); }
static void GlobalShutdown(void) { gpr_tls_destroy(callback_exec_ctx_); }
static bool Available() { return Get() != nullptr; }
@ -376,7 +368,7 @@ class ApplicationCallbackExecCtx {
uintptr_t flags_{0u};
grpc_completion_queue_functor* head_{nullptr};
grpc_completion_queue_functor* tail_{nullptr};
GPR_TLS_CLASS_DECL(callback_exec_ctx_);
static GPR_THREAD_LOCAL(ApplicationCallbackExecCtx*) callback_exec_ctx_;
};
} // namespace grpc_core

@ -53,7 +53,7 @@
namespace grpc_core {
namespace {
GPR_TLS_DECL(g_this_thread_state);
static GPR_THREAD_LOCAL(ThreadState*) g_this_thread_state;
Executor* executors[static_cast<size_t>(ExecutorType::NUM_EXECUTORS)];
@ -214,7 +214,7 @@ void Executor::Shutdown() { SetThreading(false); }
void Executor::ThreadMain(void* arg) {
ThreadState* ts = static_cast<ThreadState*>(arg);
gpr_tls_set(&g_this_thread_state, reinterpret_cast<intptr_t>(ts));
g_this_thread_state = ts;
grpc_core::ExecCtx exec_ctx(GRPC_EXEC_CTX_FLAG_IS_INTERNAL_THREAD);
@ -248,7 +248,7 @@ void Executor::ThreadMain(void* arg) {
subtract_depth = RunClosures(ts->name, closures);
}
gpr_tls_set(&g_this_thread_state, reinterpret_cast<intptr_t>(nullptr));
g_this_thread_state = nullptr;
}
void Executor::Enqueue(grpc_closure* closure, grpc_error_handle error,
@ -283,8 +283,7 @@ void Executor::Enqueue(grpc_closure* closure, grpc_error_handle error,
return;
}
ThreadState* ts =
reinterpret_cast<ThreadState*>(gpr_tls_get(&g_this_thread_state));
ThreadState* ts = g_this_thread_state;
if (ts == nullptr) {
ts = &thd_state_[GPR_HASH_POINTER(grpc_core::ExecCtx::Get(),
cur_thread_count)];
@ -465,6 +464,6 @@ void Executor::SetThreadingDefault(bool enable) {
executors[static_cast<size_t>(ExecutorType::DEFAULT)]->SetThreading(enable);
}
void grpc_executor_global_init() { gpr_tls_init(&g_this_thread_state); }
void grpc_executor_global_init() { gpr_tls_init(g_this_thread_state); }
} // namespace grpc_core

@ -223,7 +223,7 @@ static void validate_non_pending_timer(grpc_timer* t) {
* has last-seen. This is an optimization to prevent the thread from checking
* shared_mutables.min_timer (which requires acquiring shared_mutables.mu lock,
* an expensive operation) */
GPR_TLS_DECL(g_last_seen_min_timer);
static GPR_THREAD_LOCAL(grpc_millis) g_last_seen_min_timer;
#endif
struct shared_mutables {
@ -270,8 +270,8 @@ static void timer_list_init() {
g_shared_mutables.min_timer = grpc_core::ExecCtx::Get()->Now();
#if GPR_ARCH_64
gpr_tls_init(&g_last_seen_min_timer);
gpr_tls_set(&g_last_seen_min_timer, 0);
gpr_tls_init(g_last_seen_min_timer);
g_last_seen_min_timer = 0;
#endif
for (i = 0; i < g_num_shards; i++) {
@ -303,7 +303,7 @@ static void timer_list_shutdown() {
gpr_mu_destroy(&g_shared_mutables.mu);
#if GPR_ARCH_64
gpr_tls_destroy(&g_last_seen_min_timer);
gpr_tls_destroy(g_last_seen_min_timer);
#endif
gpr_free(g_shards);
@ -454,7 +454,7 @@ static void timer_init(grpc_timer* timer, grpc_millis deadline,
static void timer_consume_kick(void) {
#if GPR_ARCH_64
/* Force re-evaluation of last seen min */
gpr_tls_set(&g_last_seen_min_timer, 0);
g_last_seen_min_timer = 0;
#endif
}
@ -592,7 +592,7 @@ static grpc_timer_check_result run_some_expired_timers(
// safe since we know that both are pointer types and 64-bit wide
grpc_millis min_timer = static_cast<grpc_millis>(
gpr_atm_no_barrier_load((gpr_atm*)(&g_shared_mutables.min_timer)));
gpr_tls_set(&g_last_seen_min_timer, min_timer);
g_last_seen_min_timer = min_timer;
#else
// On 32-bit systems, gpr_atm_no_barrier_load does not work on 64-bit types
// (like grpc_millis). So all reads and writes to g_shared_mutables.min_timer
@ -679,7 +679,7 @@ static grpc_timer_check_result timer_check(grpc_millis* next) {
#if GPR_ARCH_64
/* fetch from a thread-local first: this avoids contention on a globally
mutable cacheline in the common case */
grpc_millis min_timer = gpr_tls_get(&g_last_seen_min_timer);
grpc_millis min_timer = g_last_seen_min_timer;
#else
// On 32-bit systems, we currently do not have thread local support for 64-bit
// types. In this case, directly read from g_shared_mutables.min_timer.

@ -31,6 +31,7 @@
#include <stdio.h>
#include <string.h>
#include "src/core/lib/gpr/tls.h"
#include "src/core/lib/gprpp/global_config.h"
#include "src/core/lib/profiling/timers.h"
@ -61,7 +62,7 @@ typedef struct gpr_timer_log_list {
gpr_timer_log* tail;
} gpr_timer_log_list;
static __thread gpr_timer_log* g_thread_log;
static GPR_THREAD_LOCAL(gpr_timer_log*) g_thread_log;
static gpr_once g_once_init = GPR_ONCE_INIT;
static FILE* output_file;
static const char* output_filename_or_null = NULL;
@ -71,7 +72,7 @@ static gpr_timer_log_list g_in_progress_logs;
static gpr_timer_log_list g_done_logs;
static int g_shutdown;
static pthread_t g_writing_thread;
static __thread int g_thread_id;
static GPR_THREAD_LOCAL(int) g_thread_id;
static int g_next_thread_id;
static int g_writing_enabled = 1;

@ -58,8 +58,8 @@ namespace {
// with a cq cache will go into that cache, and
// will only be returned on the thread that initialized the cache.
// NOTE: Only one event will ever be cached.
GPR_TLS_DECL(g_cached_event);
GPR_TLS_DECL(g_cached_cq);
static GPR_THREAD_LOCAL(grpc_cq_completion*) g_cached_event;
static GPR_THREAD_LOCAL(grpc_completion_queue*) g_cached_cq;
struct plucker {
grpc_pollset_worker** worker;
@ -440,25 +440,22 @@ grpc_core::TraceFlag grpc_cq_pluck_trace(false, "queue_pluck");
static void on_pollset_shutdown_done(void* arg, grpc_error_handle error);
void grpc_cq_global_init() {
gpr_tls_init(&g_cached_event);
gpr_tls_init(&g_cached_cq);
gpr_tls_init(g_cached_event);
gpr_tls_init(g_cached_cq);
}
void grpc_completion_queue_thread_local_cache_init(grpc_completion_queue* cq) {
if (reinterpret_cast<grpc_completion_queue*>(gpr_tls_get(&g_cached_cq)) ==
nullptr) {
gpr_tls_set(&g_cached_event, (intptr_t)0);
gpr_tls_set(&g_cached_cq, (intptr_t)cq);
if (g_cached_cq == nullptr) {
g_cached_event = nullptr;
g_cached_cq = cq;
}
}
int grpc_completion_queue_thread_local_cache_flush(grpc_completion_queue* cq,
void** tag, int* ok) {
grpc_cq_completion* storage =
reinterpret_cast<grpc_cq_completion*>(gpr_tls_get(&g_cached_event));
grpc_cq_completion* storage = g_cached_event;
int ret = 0;
if (storage != nullptr && reinterpret_cast<grpc_completion_queue*>(
gpr_tls_get(&g_cached_cq)) == cq) {
if (storage != nullptr && g_cached_cq == cq) {
*tag = storage->tag;
grpc_core::ExecCtx exec_ctx;
*ok = (storage->next & static_cast<uintptr_t>(1)) == 1;
@ -473,8 +470,8 @@ int grpc_completion_queue_thread_local_cache_flush(grpc_completion_queue* cq,
GRPC_CQ_INTERNAL_UNREF(cq, "shutting_down");
}
}
gpr_tls_set(&g_cached_event, (intptr_t)0);
gpr_tls_set(&g_cached_cq, (intptr_t)0);
g_cached_event = nullptr;
g_cached_cq = nullptr;
return ret;
}
@ -715,11 +712,8 @@ static void cq_end_op_for_next(
cq_check_tag(cq, tag, true); /* Used in debug builds only */
if (reinterpret_cast<grpc_completion_queue*>(gpr_tls_get(&g_cached_cq)) ==
cq &&
reinterpret_cast<grpc_cq_completion*>(gpr_tls_get(&g_cached_event)) ==
nullptr) {
gpr_tls_set(&g_cached_event, (intptr_t)storage);
if (g_cached_cq == cq && g_cached_event == nullptr) {
g_cached_event = storage;
} else {
/* Add the completion to the queue */
bool is_first = cqd->queue.Push(storage);

@ -390,7 +390,6 @@ CORE_SOURCE_FILES = [
'src/core/lib/gpr/time_posix.cc',
'src/core/lib/gpr/time_precise.cc',
'src/core/lib/gpr/time_windows.cc',
'src/core/lib/gpr/tls_pthread.cc',
'src/core/lib/gpr/tmpfile_msys.cc',
'src/core/lib/gpr/tmpfile_posix.cc',
'src/core/lib/gpr/tmpfile_windows.cc',

@ -31,18 +31,18 @@
#define NUM_THREADS 100
GPR_TLS_DECL(test_var);
static GPR_THREAD_LOCAL(intptr_t) test_var;
static void thd_body(void* /*arg*/) {
intptr_t i;
GPR_ASSERT(gpr_tls_get(&test_var) == 0);
GPR_ASSERT(test_var == 0);
for (i = 0; i < 100000; i++) {
gpr_tls_set(&test_var, i);
GPR_ASSERT(gpr_tls_get(&test_var) == i);
test_var = i;
GPR_ASSERT(test_var == i);
}
gpr_tls_set(&test_var, 0);
test_var = 0;
}
/* ------------------------------------------------- */
@ -52,7 +52,7 @@ int main(int argc, char* argv[]) {
grpc::testing::TestEnvironment env(argc, argv);
gpr_tls_init(&test_var);
gpr_tls_init(test_var);
for (auto& th : threads) {
th = grpc_core::Thread("grpc_tls_test", thd_body, nullptr);
@ -62,7 +62,7 @@ int main(int argc, char* argv[]) {
th.Join();
}
gpr_tls_destroy(&test_var);
gpr_tls_destroy(test_var);
return 0;
}

@ -44,7 +44,7 @@
// non-blocking (not polls from resolver, timer thread, etc), and only when the
// thread is waiting on polls caused by CompletionQueue::AsyncNext (not for
// picking a port or other reasons).
GPR_TLS_DECL(g_is_nonblocking_poll);
static GPR_THREAD_LOCAL(bool) g_is_nonblocking_poll;
namespace {
@ -52,7 +52,7 @@ int maybe_assert_non_blocking_poll(struct pollfd* pfds, nfds_t nfds,
int timeout) {
// Only assert that this poll should have zero timeout if we're in the
// middle of a zero-timeout CQ Next.
if (gpr_tls_get(&g_is_nonblocking_poll)) {
if (g_is_nonblocking_poll) {
GPR_ASSERT(timeout == 0);
}
return poll(pfds, nfds, timeout);
@ -82,15 +82,15 @@ class NonblockingTest : public ::testing::Test {
bool LoopForTag(void** tag, bool* ok) {
// Temporarily set the thread-local nonblocking poll flag so that the polls
// caused by this loop are indeed sent by the library with zero timeout.
intptr_t orig_val = gpr_tls_get(&g_is_nonblocking_poll);
gpr_tls_set(&g_is_nonblocking_poll, static_cast<intptr_t>(true));
bool orig_val = g_is_nonblocking_poll;
g_is_nonblocking_poll = true;
for (;;) {
auto r = cq_->AsyncNext(tag, ok, gpr_time_0(GPR_CLOCK_REALTIME));
if (r == CompletionQueue::SHUTDOWN) {
gpr_tls_set(&g_is_nonblocking_poll, orig_val);
g_is_nonblocking_poll = orig_val;
return false;
} else if (r == CompletionQueue::GOT_EVENT) {
gpr_tls_set(&g_is_nonblocking_poll, orig_val);
g_is_nonblocking_poll = orig_val;
return true;
}
}
@ -201,15 +201,15 @@ int main(int argc, char** argv) {
grpc::testing::TestEnvironment env(argc, argv);
::testing::InitGoogleTest(&argc, argv);
gpr_tls_init(&g_is_nonblocking_poll);
gpr_tls_init(g_is_nonblocking_poll);
// Start the nonblocking poll thread-local variable as false because the
// thread that issues RPCs starts by picking a port (which has non-zero
// timeout).
gpr_tls_set(&g_is_nonblocking_poll, static_cast<intptr_t>(false));
g_is_nonblocking_poll = false;
int ret = RUN_ALL_TESTS();
gpr_tls_destroy(&g_is_nonblocking_poll);
gpr_tls_destroy(g_is_nonblocking_poll);
return ret;
#else // GRPC_POSIX_SOCKET
(void)argc;

@ -1751,11 +1751,6 @@ src/core/lib/gpr/time_precise.cc \
src/core/lib/gpr/time_precise.h \
src/core/lib/gpr/time_windows.cc \
src/core/lib/gpr/tls.h \
src/core/lib/gpr/tls_gcc.h \
src/core/lib/gpr/tls_msvc.h \
src/core/lib/gpr/tls_pthread.cc \
src/core/lib/gpr/tls_pthread.h \
src/core/lib/gpr/tls_stdcpp.h \
src/core/lib/gpr/tmpfile.h \
src/core/lib/gpr/tmpfile_msys.cc \
src/core/lib/gpr/tmpfile_posix.cc \

@ -1589,11 +1589,6 @@ src/core/lib/gpr/time_precise.cc \
src/core/lib/gpr/time_precise.h \
src/core/lib/gpr/time_windows.cc \
src/core/lib/gpr/tls.h \
src/core/lib/gpr/tls_gcc.h \
src/core/lib/gpr/tls_msvc.h \
src/core/lib/gpr/tls_pthread.cc \
src/core/lib/gpr/tls_pthread.h \
src/core/lib/gpr/tls_stdcpp.h \
src/core/lib/gpr/tmpfile.h \
src/core/lib/gpr/tmpfile_msys.cc \
src/core/lib/gpr/tmpfile_posix.cc \

Loading…
Cancel
Save