mirror of
https://github.com/gperftools/gperftools
synced 2025-02-20 06:06:50 +00:00
introduce tcmalloc::kInvalidTLSKey
The intention is to initialize tls-key variable with this invalid value. This will help us avoid separate "tls ready" flag and possible memory ordering issues around distinct tls key and tls-ready variables. On windows we use TLS_OUT_OF_INDEXES values which is properly "impossible" tls index value. On POSIX systems we add theoretically unportable, but practically portable assumption that tls keys are integers. And we make value of -1 be that invalid key.
This commit is contained in:
parent
65ce9e899e
commit
46d9a6293a
@ -41,33 +41,27 @@ namespace tcmalloc {
|
||||
|
||||
using TlsKey = DWORD;
|
||||
|
||||
constexpr inline TlsKey kInvalidTLSKey = TLS_OUT_OF_INDEXES;
|
||||
|
||||
ATTRIBUTE_VISIBILITY_HIDDEN TlsKey WinTlsKeyCreate(void (*destr_fn)(void*)); /* windows/port.cc */
|
||||
|
||||
ATTRIBUTE_VISIBILITY_HIDDEN inline int CreateTlsKey(TlsKey *pkey, void (*destructor)(void*)) {
|
||||
TlsKey key = WinTlsKeyCreate(destructor);
|
||||
|
||||
if (key != TLS_OUT_OF_INDEXES) {
|
||||
*(pkey) = key;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
if (key == TLS_OUT_OF_INDEXES) {
|
||||
return GetLastError();
|
||||
}
|
||||
}
|
||||
ATTRIBUTE_VISIBILITY_HIDDEN inline void* GetTlsValue(TlsKey key) {
|
||||
DWORD err = GetLastError();
|
||||
void* rv = TlsGetValue(key);
|
||||
|
||||
if (err) SetLastError(err);
|
||||
return rv;
|
||||
*(pkey) = key;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ATTRIBUTE_VISIBILITY_HIDDEN inline void* GetTlsValue(TlsKey key) {
|
||||
return TlsGetValue(key);
|
||||
}
|
||||
|
||||
ATTRIBUTE_VISIBILITY_HIDDEN inline int SetTlsValue(TlsKey key, const void* value) {
|
||||
if (TlsSetValue(key, (LPVOID)value)) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return GetLastError();
|
||||
}
|
||||
return !TlsSetValue(key, (LPVOID)value);
|
||||
}
|
||||
|
||||
ATTRIBUTE_VISIBILITY_HIDDEN inline uintptr_t SelfThreadId() {
|
||||
@ -76,7 +70,6 @@ ATTRIBUTE_VISIBILITY_HIDDEN inline uintptr_t SelfThreadId() {
|
||||
return static_cast<uintptr_t>(GetCurrentThreadId());
|
||||
}
|
||||
|
||||
|
||||
} // namespace tcmalloc
|
||||
|
||||
#else
|
||||
@ -88,15 +81,50 @@ namespace tcmalloc {
|
||||
|
||||
using TlsKey = pthread_key_t;
|
||||
|
||||
// I've checked several implementations and they're all implementing
|
||||
// pthread_key_t as some kind of integer type. Sometimes signed,
|
||||
// sometimes unsigned, and occasionally of different width
|
||||
// (basically, int or long).
|
||||
//
|
||||
// Notably, however, POSIX is explicitly _not_ requiring
|
||||
// pthread_key_t to be of some integer type. So we're somewhat into
|
||||
// non-portable territory here. But in practice we should be okay,
|
||||
// not just given current practice, but also keeping in mind how to
|
||||
// "reasonably" implement thread-specific values. Some applies, sadly, to
|
||||
// C11 tss_t type.
|
||||
//
|
||||
// Another potentially tricky aspect is what values to consider
|
||||
// invalid. POSIX also says nothing about this, sadly. Solaris has
|
||||
// nonportable PTHREAD_ONCE_KEY_NP, which would be sensible to have
|
||||
// in standard (even without pthread_key_create_once_np), but we
|
||||
// have what we have. It's value is (int)(-1). And, indeed, -1 seems
|
||||
// like most sensible value.
|
||||
constexpr inline TlsKey kInvalidTLSKey = static_cast<TlsKey>(~uintptr_t{0});
|
||||
static_assert(sizeof(pthread_key_t) <= sizeof(uintptr_t));
|
||||
|
||||
ATTRIBUTE_VISIBILITY_HIDDEN inline int CreateTlsKey(TlsKey *pkey, void (*destructor)(void*)) {
|
||||
return pthread_key_create(pkey, destructor);
|
||||
int err = pthread_key_create(pkey, destructor);
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
// It is super-implausible that we'll be able to create "invalid"
|
||||
// tls key value, but just in case, we check and re-create if we end
|
||||
// up getting one.
|
||||
if (*pkey != kInvalidTLSKey) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return CreateTlsKey(pkey, destructor);
|
||||
}
|
||||
|
||||
ATTRIBUTE_VISIBILITY_HIDDEN inline void* GetTlsValue(TlsKey key) {
|
||||
return pthread_getspecific(key);
|
||||
}
|
||||
|
||||
ATTRIBUTE_VISIBILITY_HIDDEN inline int SetTlsValue(TlsKey key, const void* value) {
|
||||
return pthread_setspecific(key, value);
|
||||
}
|
||||
|
||||
ATTRIBUTE_VISIBILITY_HIDDEN inline uintptr_t SelfThreadId() {
|
||||
// Most platforms (with notable exception of windows C runtime) can
|
||||
// use address of errno as a quick and portable and recursion-free
|
||||
|
Loading…
Reference in New Issue
Block a user