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