[tls] Remove support for pthread tls (#31040)
* [tls] Remove support for pthread tls * fix * fix * fix * lalala * fix * fix * Clean up deployment target changes * additional clean up of deployment target * regen podspec for updated file list * remove destination change * deployment target override for ios cpp test * fix? * fix run test script & update test destination * [tls] Remove support for pthread tls * fix * fix * fix * lalala * fix * fix * Clean up deployment target changes * additional clean up of deployment target * regen podspec for updated file list * remove destination change * deployment target override for ios cpp test * fix? * fix run test script & update test destination * merge * fix * final script fix for proper destination & target * more deployment target fix * objc ios test script fix Co-authored-by: Denny C. Dai <dennycd@me.com> Co-authored-by: dennycd <dennycd@google.com>pull/31100/head^2
parent
c3714eced8
commit
f15ba1ffc7
36 changed files with 65 additions and 395 deletions
@ -1,156 +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_H |
||||
#define GRPC_CORE_LIB_GPR_TLS_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <type_traits> |
||||
|
||||
/** Thread local storage.
|
||||
|
||||
Usage is the same as C++ thread_local. Declaring a thread local: |
||||
static GPR_THREAD_LOCAL(uint32_t) foo; |
||||
|
||||
ALL functions here may be implemented as macros. */ |
||||
|
||||
namespace grpc_core { |
||||
|
||||
// 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 TlsTypeConstrainer { |
||||
static_assert(std::is_trivial<T>::value, |
||||
"TLS support is limited to trivial types"); |
||||
|
||||
public: |
||||
using Type = T; |
||||
}; |
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
#if defined(GPR_PTHREAD_TLS) |
||||
|
||||
#include <pthread.h> |
||||
|
||||
#include <algorithm> |
||||
#include <array> |
||||
#include <cstring> |
||||
|
||||
namespace grpc_core { |
||||
|
||||
template <typename T> |
||||
class PthreadTlsImpl : TlsTypeConstrainer<T> { |
||||
public: |
||||
PthreadTlsImpl(const PthreadTlsImpl&) = delete; |
||||
PthreadTlsImpl& operator=(const PthreadTlsImpl&) = delete; |
||||
|
||||
// Achtung! This class emulates C++ `thread_local` using pthread keys. Each
|
||||
// instance of this class is a stand in for a C++ `thread_local`. Think of
|
||||
// each `thread_local` as a *global* pthread_key_t and a type tag. An
|
||||
// important consequence of this is that the lifetime of a `pthread_key_t`
|
||||
// is precisely the lifetime of an instance of this class. To understand why
|
||||
// this is, consider the following scenario given a fictional implementation
|
||||
// of this class which creates and destroys its `pthread_key_t` each time
|
||||
// a given block of code runs (all actions take place on a single thread):
|
||||
//
|
||||
// - instance 1 (type tag = T*) is initialized, is assigned `pthread_key_t` 1
|
||||
// - instance 2 (type tag = int) is initialized, is assigned `pthread_key_t` 2
|
||||
// - instances 1 and 2 store and retrieve values; all is well
|
||||
// - instances 1 and 2 are de-initialized; their keys are released to the pool
|
||||
//
|
||||
// - another run commences
|
||||
// - instance 1 receives key 2
|
||||
// - a value is read from instance 1, it observes a value of type int, but
|
||||
// interprets it as T*; undefined behavior, kaboom
|
||||
//
|
||||
// To properly ensure these invariants are upheld the `pthread_key_t` must be
|
||||
// `const`, which means it can only be released in the destructor. This is a
|
||||
// a violation of the style guide, since these objects are always static (see
|
||||
// footnote) but this code is used in sufficiently narrow circumstances to
|
||||
// justify the deviation.
|
||||
//
|
||||
// https://google.github.io/styleguide/cppguide.html#Static_and_Global_Variables
|
||||
PthreadTlsImpl() |
||||
: keys_([]() { |
||||
typename std::remove_const<decltype(PthreadTlsImpl::keys_)>::type |
||||
keys; |
||||
for (pthread_key_t& key : keys) { |
||||
if (0 != pthread_key_create(&key, nullptr)) abort(); |
||||
} |
||||
return keys; |
||||
}()) {} |
||||
PthreadTlsImpl(T t) : PthreadTlsImpl() { *this = t; } |
||||
~PthreadTlsImpl() { |
||||
for (pthread_key_t key : keys_) { |
||||
if (0 != pthread_key_delete(key)) abort(); |
||||
} |
||||
} |
||||
|
||||
operator T() const { |
||||
T t; |
||||
char* dst = reinterpret_cast<char*>(&t); |
||||
for (pthread_key_t key : keys_) { |
||||
uintptr_t src = uintptr_t(pthread_getspecific(key)); |
||||
size_t remaining = reinterpret_cast<char*>(&t + 1) - dst; |
||||
size_t step = std::min(sizeof(src), remaining); |
||||
memcpy(dst, &src, step); |
||||
dst += step; |
||||
} |
||||
return t; |
||||
} |
||||
|
||||
T operator->() const { |
||||
static_assert(std::is_pointer<T>::value, |
||||
"operator-> only usable on pointers"); |
||||
return this->operator T(); |
||||
} |
||||
|
||||
T operator=(T t) { |
||||
char* src = reinterpret_cast<char*>(&t); |
||||
for (pthread_key_t key : keys_) { |
||||
uintptr_t dst; |
||||
size_t remaining = reinterpret_cast<char*>(&t + 1) - src; |
||||
size_t step = std::min(sizeof(dst), remaining); |
||||
memcpy(&dst, src, step); |
||||
if (0 != pthread_setspecific(key, reinterpret_cast<void*>(dst))) abort(); |
||||
src += step; |
||||
} |
||||
return t; |
||||
} |
||||
|
||||
private: |
||||
const std::array<pthread_key_t, |
||||
(sizeof(T) + sizeof(void*) - 1) / sizeof(void*)> |
||||
keys_; |
||||
}; |
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
#define GPR_THREAD_LOCAL(type) grpc_core::PthreadTlsImpl<type> |
||||
|
||||
#else |
||||
|
||||
#define GPR_THREAD_LOCAL(type) \ |
||||
thread_local typename grpc_core::TlsTypeConstrainer<type>::Type |
||||
|
||||
#endif |
||||
|
||||
#endif /* GRPC_CORE_LIB_GPR_TLS_H */ |
@ -1,67 +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. |
||||
* |
||||
*/ |
||||
|
||||
/* Test of gpr thread local storage support. */ |
||||
|
||||
#include "src/core/lib/gpr/tls.h" |
||||
|
||||
#include <array> |
||||
|
||||
#include <gtest/gtest.h> |
||||
|
||||
#include "src/core/lib/gprpp/thd.h" |
||||
#include "test/core/util/test_config.h" |
||||
|
||||
struct BiggerThanMachineWord { |
||||
size_t a, b; |
||||
uint8_t c; |
||||
}; |
||||
|
||||
static GPR_THREAD_LOCAL(BiggerThanMachineWord) test_var; |
||||
// Fails to compile: static GPR_THREAD_LOCAL(std::unique_ptr<char>) non_trivial;
|
||||
|
||||
namespace { |
||||
void thd_body(void*) { |
||||
for (size_t i = 0; i < 100000; i++) { |
||||
BiggerThanMachineWord next = {i, i, uint8_t(i)}; |
||||
test_var = next; |
||||
BiggerThanMachineWord read = test_var; |
||||
ASSERT_EQ(read.a, i); |
||||
ASSERT_EQ(read.b, i); |
||||
ASSERT_EQ(read.c, uint8_t(i)) << i; |
||||
} |
||||
} |
||||
|
||||
TEST(ThreadLocal, ReadWrite) { |
||||
std::array<grpc_core::Thread, 100> threads; |
||||
for (grpc_core::Thread& th : threads) { |
||||
th = grpc_core::Thread("grpc_tls_test", thd_body, nullptr); |
||||
th.Start(); |
||||
} |
||||
for (grpc_core::Thread& th : threads) { |
||||
th.Join(); |
||||
} |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char* argv[]) { |
||||
grpc::testing::TestEnvironment env(&argc, argv); |
||||
::testing::InitGoogleTest(&argc, argv); |
||||
return RUN_ALL_TESTS(); |
||||
} |
Loading…
Reference in new issue