]> git.saurik.com Git - wxWidgets.git/blob - include/wx/tls.h
A better fix for wxHash{Map,Set} with g++ 4.7.
[wxWidgets.git] / include / wx / tls.h
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: wx/tls.h
3 // Purpose: Implementation of thread local storage
4 // Author: Vadim Zeitlin
5 // Created: 2008-08-08
6 // RCS-ID: $Id$
7 // Copyright: (c) 2008 Vadim Zeitlin <vadim@wxwidgets.org>
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 #ifndef _WX_TLS_H_
12 #define _WX_TLS_H_
13
14 #include "wx/defs.h"
15
16 // ----------------------------------------------------------------------------
17 // check for compiler support of thread-specific variables
18 // ----------------------------------------------------------------------------
19
20 // when not using threads at all, there is no need for thread-specific
21 // values to be really thread-specific
22 #if !wxUSE_THREADS
23 #define wxHAS_COMPILER_TLS
24 #define wxTHREAD_SPECIFIC_DECL
25 // otherwise try to find the compiler-specific way to handle TLS unless
26 // explicitly disabled by setting wxUSE_COMPILER_TLS to 0 (it is 1 by default).
27 #elif wxUSE_COMPILER_TLS
28 // __thread keyword is not supported correctly by MinGW, at least in some
29 // configurations, see http://sourceforge.net/support/tracker.php?aid=2837047
30 // and when in doubt we prefer to not use it at all.
31 #if defined(HAVE___THREAD_KEYWORD) && !defined(__MINGW32__)
32 #define wxHAS_COMPILER_TLS
33 #define wxTHREAD_SPECIFIC_DECL __thread
34 // MSVC has its own version which might be supported by some other Windows
35 // compilers, to be tested
36 #elif wxCHECK_VISUALC_VERSION(7)
37 #define wxHAS_COMPILER_TLS
38 #define wxTHREAD_SPECIFIC_DECL __declspec(thread)
39 #endif // compilers
40 #endif // wxUSE_COMPILER_TLS
41
42 // ----------------------------------------------------------------------------
43 // define wxTLS_TYPE()
44 // ----------------------------------------------------------------------------
45
46 #ifdef wxHAS_COMPILER_TLS
47 #define wxTLS_TYPE(T) wxTHREAD_SPECIFIC_DECL T
48 #define wxTLS_PTR(var) (&(var))
49 #define wxTLS_VALUE(var) (var)
50 #else // !wxHAS_COMPILER_TLS
51
52 extern "C"
53 {
54 typedef void (*wxTlsDestructorFunction)(void*);
55 }
56
57 #if defined(__WINDOWS__)
58 #include "wx/msw/tls.h"
59 #elif defined(__OS2__)
60 #include "wx/os2/tls.h"
61 #elif defined(__UNIX__)
62 #include "wx/unix/tls.h"
63 #else
64 // TODO: we could emulate TLS for such platforms...
65 #error Neither compiler nor OS support thread-specific variables.
66 #endif
67
68 #include <stdlib.h> // for calloc()
69
70 // wxTlsValue<T> represents a thread-specific value of type T but, unlike
71 // with native compiler thread-specific variables, it behaves like a
72 // (never NULL) pointer to T and so needs to be dereferenced before use
73 //
74 // Note: T must be a POD!
75 //
76 // Note: On Unix, thread-specific T value is freed when the thread exits.
77 // On Windows, thread-specific values are freed later, when given
78 // wxTlsValue<T> is destroyed. The only exception to this is the
79 // value for the main thread, which is always freed when
80 // wxTlsValue<T> is destroyed.
81 template <typename T>
82 class wxTlsValue
83 {
84 public:
85 typedef T ValueType;
86
87 // ctor doesn't do anything, the object is created on first access
88 wxTlsValue() : m_key(free) {}
89
90 // dtor is only called in the main thread context and so is not enough
91 // to free memory allocated by us for the other threads, we use
92 // destructor function when using Pthreads for this (which is not
93 // called for the main thread as it doesn't call pthread_exit() but
94 // just to be safe we also reset the key anyhow)
95 ~wxTlsValue()
96 {
97 if ( m_key.Get() )
98 m_key.Set(NULL); // this deletes the value
99 }
100
101 // access the object creating it on demand
102 ValueType *Get()
103 {
104 void *value = m_key.Get();
105 if ( !value )
106 {
107 // ValueType must be POD to be used in wxHAS_COMPILER_TLS case
108 // anyhow (at least gcc doesn't accept non-POD values being
109 // declared with __thread) so initialize it as a POD too
110 value = calloc(1, sizeof(ValueType));
111
112 if ( !m_key.Set(value) )
113 {
114 free(value);
115
116 // this will probably result in a crash in the caller but
117 // it's arguably better to crash immediately instead of
118 // slowly dying from out-of-memory errors which would
119 // happen as the next access to this object would allocate
120 // another ValueType instance and so on forever
121 value = NULL;
122 }
123 }
124
125 return static_cast<ValueType *>(value);
126 }
127
128 // pointer-like accessors
129 ValueType *operator->() { return Get(); }
130 ValueType& operator*() { return *Get(); }
131
132 private:
133 wxTlsKey m_key;
134
135 DECLARE_NO_COPY_TEMPLATE_CLASS(wxTlsValue, T)
136 };
137
138 #define wxTLS_TYPE(T) wxTlsValue<T>
139 #define wxTLS_PTR(var) ((var).Get())
140 #define wxTLS_VALUE(var) (*(var))
141 #endif // wxHAS_COMPILER_TLS/!wxHAS_COMPILER_TLS
142
143 #endif // _WX_TLS_H_
144