annotate osx/include/kj/threadlocal.h @ 83:ae30d91d2ffe

Replace these with versions built using an older toolset (so as to avoid ABI compatibilities when linking on Ubuntu 14.04 for packaging purposes)
author Chris Cannam
date Fri, 07 Feb 2020 11:51:13 +0000
parents 0994c39f1e94
children
rev   line source
cannam@62 1 // Copyright (c) 2014, Jason Choy <jjwchoy@gmail.com>
cannam@62 2 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
cannam@62 3 // Licensed under the MIT License:
cannam@62 4 //
cannam@62 5 // Permission is hereby granted, free of charge, to any person obtaining a copy
cannam@62 6 // of this software and associated documentation files (the "Software"), to deal
cannam@62 7 // in the Software without restriction, including without limitation the rights
cannam@62 8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
cannam@62 9 // copies of the Software, and to permit persons to whom the Software is
cannam@62 10 // furnished to do so, subject to the following conditions:
cannam@62 11 //
cannam@62 12 // The above copyright notice and this permission notice shall be included in
cannam@62 13 // all copies or substantial portions of the Software.
cannam@62 14 //
cannam@62 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
cannam@62 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
cannam@62 17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
cannam@62 18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
cannam@62 19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
cannam@62 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
cannam@62 21 // THE SOFTWARE.
cannam@62 22
cannam@62 23 #ifndef KJ_THREADLOCAL_H_
cannam@62 24 #define KJ_THREADLOCAL_H_
cannam@62 25
cannam@62 26 #if defined(__GNUC__) && !KJ_HEADER_WARNINGS
cannam@62 27 #pragma GCC system_header
cannam@62 28 #endif
cannam@62 29 // This file declares a macro `KJ_THREADLOCAL_PTR` for declaring thread-local pointer-typed
cannam@62 30 // variables. Use like:
cannam@62 31 // KJ_THREADLOCAL_PTR(MyType) foo = nullptr;
cannam@62 32 // This is equivalent to:
cannam@62 33 // thread_local MyType* foo = nullptr;
cannam@62 34 // This can only be used at the global scope.
cannam@62 35 //
cannam@62 36 // AVOID USING THIS. Use of thread-locals is discouraged because they often have many of the same
cannam@62 37 // properties as singletons: http://www.object-oriented-security.org/lets-argue/singletons
cannam@62 38 //
cannam@62 39 // Also, thread-locals tend to be hostile to event-driven code, which can be particularly
cannam@62 40 // surprising when using fibers (all fibers in the same thread will share the same threadlocals,
cannam@62 41 // even though they do not share a stack).
cannam@62 42 //
cannam@62 43 // That said, thread-locals are sometimes needed for runtime logistics in the KJ framework. For
cannam@62 44 // example, the current exception callback and current EventLoop are stored as thread-local
cannam@62 45 // pointers. Since KJ only ever needs to store pointers, not values, we avoid the question of
cannam@62 46 // whether these values' destructors need to be run, and we avoid the need for heap allocation.
cannam@62 47
cannam@62 48 #include "common.h"
cannam@62 49
cannam@62 50 #if !defined(KJ_USE_PTHREAD_THREADLOCAL) && defined(__APPLE__)
cannam@62 51 #include "TargetConditionals.h"
cannam@62 52 #if TARGET_OS_IPHONE
cannam@62 53 // iOS apparently does not support __thread (nor C++11 thread_local).
cannam@62 54 #define KJ_USE_PTHREAD_TLS 1
cannam@62 55 #endif
cannam@62 56 #endif
cannam@62 57
cannam@62 58 #if KJ_USE_PTHREAD_TLS
cannam@62 59 #include <pthread.h>
cannam@62 60 #endif
cannam@62 61
cannam@62 62 namespace kj {
cannam@62 63
cannam@62 64 #if KJ_USE_PTHREAD_TLS
cannam@62 65 // If __thread is unavailable, we'll fall back to pthreads.
cannam@62 66
cannam@62 67 #define KJ_THREADLOCAL_PTR(type) \
cannam@62 68 namespace { struct KJ_UNIQUE_NAME(_kj_TlpTag); } \
cannam@62 69 static ::kj::_::ThreadLocalPtr< type, KJ_UNIQUE_NAME(_kj_TlpTag)>
cannam@62 70 // Hack: In order to ensure each thread-local results in a unique template instance, we declare
cannam@62 71 // a one-off dummy type to use as the second type parameter.
cannam@62 72
cannam@62 73 namespace _ { // private
cannam@62 74
cannam@62 75 template <typename T, typename>
cannam@62 76 class ThreadLocalPtr {
cannam@62 77 // Hacky type to emulate __thread T*. We need a separate instance of the ThreadLocalPtr template
cannam@62 78 // for every thread-local variable, because we don't want to require a global constructor, and in
cannam@62 79 // order to initialize the TLS on first use we need to use a local static variable (in getKey()).
cannam@62 80 // Each template instance will get a separate such local static variable, fulfilling our need.
cannam@62 81
cannam@62 82 public:
cannam@62 83 ThreadLocalPtr() = default;
cannam@62 84 constexpr ThreadLocalPtr(decltype(nullptr)) {}
cannam@62 85 // Allow initialization to nullptr without a global constructor.
cannam@62 86
cannam@62 87 inline ThreadLocalPtr& operator=(T* val) {
cannam@62 88 pthread_setspecific(getKey(), val);
cannam@62 89 return *this;
cannam@62 90 }
cannam@62 91
cannam@62 92 inline operator T*() const {
cannam@62 93 return get();
cannam@62 94 }
cannam@62 95
cannam@62 96 inline T& operator*() const {
cannam@62 97 return *get();
cannam@62 98 }
cannam@62 99
cannam@62 100 inline T* operator->() const {
cannam@62 101 return get();
cannam@62 102 }
cannam@62 103
cannam@62 104 private:
cannam@62 105 inline T* get() const {
cannam@62 106 return reinterpret_cast<T*>(pthread_getspecific(getKey()));
cannam@62 107 }
cannam@62 108
cannam@62 109 inline static pthread_key_t getKey() {
cannam@62 110 static pthread_key_t key = createKey();
cannam@62 111 return key;
cannam@62 112 }
cannam@62 113
cannam@62 114 static pthread_key_t createKey() {
cannam@62 115 pthread_key_t key;
cannam@62 116 pthread_key_create(&key, 0);
cannam@62 117 return key;
cannam@62 118 }
cannam@62 119 };
cannam@62 120
cannam@62 121 } // namespace _ (private)
cannam@62 122
cannam@62 123 #elif __GNUC__
cannam@62 124
cannam@62 125 #define KJ_THREADLOCAL_PTR(type) static __thread type*
cannam@62 126 // GCC's __thread is lighter-weight than thread_local and is good enough for our purposes.
cannam@62 127
cannam@62 128 #else
cannam@62 129
cannam@62 130 #define KJ_THREADLOCAL_PTR(type) static thread_local type*
cannam@62 131
cannam@62 132 #endif // KJ_USE_PTHREAD_TLS
cannam@62 133
cannam@62 134 } // namespace kj
cannam@62 135
cannam@62 136 #endif // KJ_THREADLOCAL_H_