1 // Copyright (C) 2014 The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef EMUGL_COMMON_THREAD_STORE_H 16 #define EMUGL_COMMON_THREAD_STORE_H 17 18 #ifdef _WIN32 19 # define WIN32_LEAN_AND_MEAN 1 20 # include <windows.h> 21 #else 22 # include <pthread.h> 23 #endif 24 25 namespace emugl { 26 27 // A class to model storage of thread-specific values, that can be 28 // destroyed on thread exit. 29 // 30 // Note that on Windows, a thread must call OnThreadExit() explicitly 31 // here to ensure that the values are probably discarded. This is an 32 // unfortunate requirement of the Win32 API, which doesn't support 33 // destructors at all. 34 // 35 // There are various hacks on the web to try to achieve this automatically 36 // (e.g. [1]) but they rely on using the Microsoft build tools, 37 // which doesn't work for us. 38 // 39 // Note another important issue with ThreadStore instances: if you create 40 // one instance in a shared library, you need to make sure that it is 41 // always destroyed before the library is unloaded. Otherwise, future 42 // thread exit will likely crash, due to calling a destructor function 43 // that is no longer in the process' address space. 44 // 45 // Finally, destroying an instance does _not_ free the corresponding values, 46 // because doing so properly requires coordinating all participating threads, 47 // which is impossible to achieve in the most general case. Thus, consider 48 // that thread-local values are always leaked on library unload, or on 49 // program exit. 50 // 51 // [1] http://stackoverflow.com/questions/14538159/about-tls-callback-in-windows 52 53 class ThreadStore { 54 public: 55 // Type of a function used to destroy a thread-specific value that 56 // was previously assigned by calling set(). 57 typedef void (Destructor)(void* value); 58 59 // Initialize instance so that is hold keys that must be destroyed 60 // on thread exit by calling |destroy|. 61 explicit ThreadStore(Destructor* destroy); 62 63 // NOTE: Destructor don't free the thread-local values, but are required 64 // to avoid crashes (see note above). 65 ~ThreadStore(); 66 67 // Retrieve current thread-specific value from store. 68 #ifdef _WIN32 69 void* get() const; 70 #else get()71 inline void* get() const { 72 return pthread_getspecific(mKey); 73 } 74 #endif 75 76 // Set the new thread-specific value. 77 #ifdef _WIN32 78 void set(void* value); 79 #else set(void * value)80 inline void set(void* value) { 81 pthread_setspecific(mKey, value); 82 } 83 #endif 84 85 #ifdef _WIN32 86 // Each thread should call this function on exit to ensure that 87 // all corresponding TLS values are properly freed. 88 static void OnThreadExit(); 89 #else 90 // Nothing to do on Posix. OnThreadExit()91 static inline void OnThreadExit() {} 92 #endif 93 94 private: 95 // Ensure you can't create an empty ThreadStore instance, or simply 96 // copy it in any way. 97 ThreadStore(); 98 ThreadStore(const ThreadStore&); 99 ThreadStore& operator=(const ThreadStore&); 100 101 #ifdef _WIN32 102 int mKey; 103 #else 104 pthread_key_t mKey; 105 #endif 106 }; 107 108 } // namespace emugl 109 110 #endif // EMUGL_COMMON_THREAD_STORE_H 111