Home | History | Annotate | Download | only in common
      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
     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
     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.
     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