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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 62 - (hide annotations) (download)
Tue Sep 7 11:08:22 2010 UTC (9 years, 10 months ago) by william
File size: 5606 byte(s)
Auto Commited Import of: pcsx2-0.9.7-r3738-debug in ./trunk
1 william 62 /* 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