/[pcsx2_0.9.7]/trunk/common/include/Utilities/TlsVariable.inl
ViewVC logotype

Contents of /trunk/common/include/Utilities/TlsVariable.inl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 62 - (show annotations) (download)
Tue Sep 7 11:08:22 2010 UTC (9 years, 4 months ago) by william
File size: 5606 byte(s)
Auto Commited Import of: pcsx2-0.9.7-r3738-debug in ./trunk
1 /* PCSX2 - PS2 Emulator for PCs
2 * Copyright (C) 2002-2010 PCSX2 Dev Team
3 *
4 * PCSX2 is free software: you can redistribute it and/or modify it under the terms
5 * of the GNU Lesser General Public License as published by the Free Software Found-
6 * ation, either version 3 of the License, or (at your option) any later version.
7 *
8 * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 * PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along with PCSX2.
13 * If not, see <http://www.gnu.org/licenses/>.
14 */
15
16 #pragma once
17
18 #include "Threading.h"
19
20 #if PCSX2_THREAD_LOCAL
21 # define DeclareTls(x) __threadlocal x
22 #else
23 # define DeclareTls(x) Threading::TlsVariable<x>
24 #endif
25
26 namespace Threading
27 {
28 // --------------------------------------------------------------------------------------
29 // TlsVariable - Thread local storage
30 // --------------------------------------------------------------------------------------
31 // Wrapper class for pthread_getspecific, which is pthreads language for "thread local
32 // storage." This class enables code to act as a drop-in replacement for compiler-native
33 // thread local storage (typically specified via __threadlocal). Mac OS/X (Darwin) does
34 // not have TLS, which is the main reason for this class existing.
35 //
36 // Performance considerations: While certainly convenient, performance of this class can
37 // be sub-optimal when the operator overloads are used, since each one will most likely
38 // result in repeated calls to pthread_getspecific. (if the function inlines then it
39 // should actually optimize well enough, but I doubt it does).
40 //
41 template< typename T >
42 class BaseTlsVariable
43 {
44 DeclareNoncopyableObject(BaseTlsVariable<T>);
45
46 protected:
47 pthread_key_t m_thread_key;
48 bool m_IsDisposed;
49
50 public:
51 BaseTlsVariable();
52
53 virtual ~BaseTlsVariable() throw()
54 {
55 Dispose();
56 }
57
58 T* GetPtr() const;
59 T& GetRef() const { return *GetPtr(); }
60
61 operator T&() const { return GetRef(); }
62 T* operator->() const { return GetPtr(); }
63
64 void Dispose()
65 {
66 if (!m_IsDisposed)
67 {
68 m_IsDisposed = true;
69 KillKey();
70 }
71 }
72
73 protected:
74 void CreateKey();
75 void KillKey();
76
77 virtual void CreateInstance( T* result ) const
78 {
79 new (result) T();
80 }
81
82 static void _aligned_delete_and_free( void* ptr )
83 {
84 if (!ptr) return;
85 ((T*)ptr)->~T();
86 _aligned_free(ptr);
87 }
88 };
89
90 template< typename T >
91 class TlsVariable : public BaseTlsVariable<T>
92 {
93 DeclareNoncopyableObject(TlsVariable<T>);
94
95 protected:
96 T m_initval;
97
98 public:
99 TlsVariable() {}
100 TlsVariable( const T& initval )
101 : m_initval(initval) { }
102
103 // This is needed; The C++ standard likes making life suck for programmers.
104 using BaseTlsVariable<T>::GetRef;
105
106 virtual ~TlsVariable() throw()
107 {
108 // disable the parent cleanup. This leaks memory blocks, but its necessary because
109 // TLS is expected to be persistent until the very end of execution on the main thread.
110 // Killing the pthread_key at all will lead to the console logger death, etc.
111
112 // DON'T REMOVE this->, the "official"[ly stupid] C++ standard requires it because of its
113 // insistence that variables be looked up during initial template parsing and not during
114 // instantiation.
115 this->m_IsDisposed = true;
116 }
117
118 TlsVariable<T>& operator=( const T& src )
119 {
120 GetRef() = src;
121 return *this;
122 }
123
124 bool operator==( const T& src ) const { return GetRef() == src; }
125 bool operator!=( const T& src ) const { return GetRef() != src; }
126 bool operator>( const T& src ) const { return GetRef() > src; }
127 bool operator<( const T& src ) const { return GetRef() < src; }
128 bool operator>=( const T& src ) const { return GetRef() >= src; }
129 bool operator<=( const T& src ) const { return GetRef() <= src; }
130
131 T operator+( const T& src ) const { return GetRef() + src; }
132 T operator-( const T& src ) const { return GetRef() - src; }
133
134 void operator+=( const T& src ) { GetRef() += src; }
135 void operator-=( const T& src ) { GetRef() -= src; }
136
137 protected:
138 virtual void CreateInstance( T* result ) const
139 {
140 new (result) T(m_initval);
141 }
142 };
143 };
144
145 template< typename T >
146 Threading::BaseTlsVariable<T>::BaseTlsVariable()
147 {
148 m_IsDisposed = false;
149 CreateKey();
150 }
151
152 template< typename T >
153 void Threading::BaseTlsVariable<T>::KillKey()
154 {
155 if (!m_thread_key) return;
156
157 // Delete the handle for the current thread (which should always be the main/UI thread!)
158 // This is needed because pthreads does *not* clean up the dangling objects when you delete
159 // the key. The TLS for the process main thread will only be deleted when the process
160 // ends; which is too damn late (it shows up int he leaked memory blocks).
161
162 BaseTlsVariable<T>::_aligned_delete_and_free( pthread_getspecific(m_thread_key) );
163
164 pthread_key_delete( m_thread_key );
165 m_thread_key = 0;
166 }
167
168 template< typename T >
169 T* Threading::BaseTlsVariable<T>::GetPtr() const
170 {
171 T* result = (T*)pthread_getspecific( m_thread_key );
172 if( result == NULL )
173 {
174 pthread_setspecific( m_thread_key, result = (T*)_aligned_malloc(sizeof(T), 16) );
175 CreateInstance(result);
176 if( result == NULL )
177 throw Exception::OutOfMemory( L"thread local storage variable instance" );
178 }
179 return result;
180 }
181
182 template< typename T >
183 void Threading::BaseTlsVariable<T>::CreateKey()
184 {
185 if( 0 != pthread_key_create(&m_thread_key, BaseTlsVariable<T>::_aligned_delete_and_free) )
186 {
187 pxFailRel( "Thread Local Storage Error: key creation failed. This will most likely lead to a rapid application crash." );
188 }
189 }

  ViewVC Help
Powered by ViewVC 1.1.22