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 #pragma once 16 17 #include "aemu/base/Compiler.h" 18 19 #ifdef _WIN32 20 # define WIN32_LEAN_AND_MEAN 1 21 # include <windows.h> 22 #else 23 # include <pthread.h> 24 #endif 25 26 namespace gfxstream { 27 namespace guest { 28 29 // A class to model storage of thread-specific values, that can be 30 // destroyed on thread exit. 31 // 32 // Note that on Windows, a thread must call OnThreadExit() explicitly 33 // here to ensure that the values are probably discarded. This is an 34 // unfortunate requirement of the Win32 API, which doesn't support 35 // destructors at all. 36 // 37 // There are various hacks on the web to try to achieve this automatically 38 // (e.g. [1]) but they rely on using the Microsoft build tools, 39 // which doesn't work for us. 40 // 41 // Note another important issue with ThreadStore instances: if you create 42 // one instance in a shared library, you need to make sure that it is 43 // always destroyed before the library is unloaded. Otherwise, future 44 // thread exit will likely crash, due to calling a destructor function 45 // that is no longer in the process' address space. 46 // 47 // Finally, destroying an instance does _not_ free the corresponding values, 48 // because doing so properly requires coordinating all participating threads, 49 // which is impossible to achieve in the most general case. Thus, consider 50 // that thread-local values are always leaked on library unload, or on 51 // program exit. 52 // 53 // [1] http://stackoverflow.com/questions/14538159/about-tls-callback-in-windows 54 55 // ThreadStoreBase is the base class used by all ThreadStore template 56 // instances, used to reduce bloat. 57 class ThreadStoreBase { 58 public: 59 // Type of a function used to destroy a thread-specific value that 60 // was previously assigned by calling set(). 61 typedef void (Destructor)(void* value); 62 63 // Initialize instance so that is hold keys that must be destroyed 64 // on thread exit by calling |destroy|. 65 explicit ThreadStoreBase(Destructor* destroy); 66 67 // NOTE: Destructor don't free the thread-local values, but are required 68 // to avoid crashes (see note above). 69 ~ThreadStoreBase(); 70 71 // Retrieve current thread-specific value from store. 72 #ifdef _WIN32 73 void* get() const; 74 #else get()75 inline void* get() const { 76 return pthread_getspecific(mKey); 77 } 78 #endif 79 80 // Set the new thread-specific value. 81 #ifdef _WIN32 82 void set(void* value); 83 #else set(void * value)84 inline void set(void* value) { 85 pthread_setspecific(mKey, value); 86 } 87 #endif 88 swap(void * value)89 inline void* swap(void* value) { 90 void* old = get(); 91 set(value); 92 return old; 93 } 94 95 #ifdef _WIN32 96 // Each thread should call this function on exit to ensure that 97 // all corresponding TLS values are properly freed. 98 static void OnThreadExit(); 99 #else 100 // Nothing to do on Posix. OnThreadExit()101 static inline void OnThreadExit() {} 102 #endif 103 104 private: 105 // Ensure you can't create an empty ThreadStore instance. 106 ThreadStoreBase(); 107 108 DISALLOW_COPY_AND_ASSIGN(ThreadStoreBase); 109 110 #ifdef _WIN32 111 int mKey; 112 #else 113 pthread_key_t mKey; 114 #endif 115 }; 116 117 // ThreadStore is a template class used to implement a thread-local store 118 // of objects of type |T|. Note that the store owns the objects, and these 119 // are destroyed when a gfxstream::guest::Thread exits. 120 template <typename T> 121 class ThreadStore : public ThreadStoreBase { 122 public: 123 // Create a new ThreadStore instance. ThreadStore()124 ThreadStore() : ThreadStoreBase(myDestructor) {} 125 126 // Retrieve the thread-specific object instance, or NULL if set() 127 // was never called before in the current thread. get()128 T* get() { 129 return static_cast<T*>(ThreadStoreBase::get()); 130 } 131 132 // Set the current thread-specific objet instance for this thread. 133 // |t| is the new object instance. 134 // NOTE: Any previous object instance is deleted. set(T * t)135 void set(T* t) { 136 T* old = static_cast<T*>(swap(t)); 137 delete old; 138 } 139 140 // Swap the current thread-specific object for this thread. 141 // |t| is the new object instance. 142 // Return the previous one. Transfers ownership to the caller. swap(T * t)143 T* swap(T* t) { 144 return static_cast<T*>(ThreadStoreBase::swap(t)); 145 } 146 147 private: myDestructor(void * opaque)148 static void myDestructor(void* opaque) { 149 delete static_cast<T*>(opaque); 150 } 151 }; 152 153 } // namespace guest 154 } // namespace gfxstream 155