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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 61 by william, Tue Sep 7 03:24:11 2010 UTC revision 62 by william, Tue Sep 7 11:08:22 2010 UTC
# Line 1  Line 1 
1  /*  PCSX2 - PS2 Emulator for PCs  /*  PCSX2 - PS2 Emulator for PCs
2   *  Copyright (C) 2002-2010  PCSX2 Dev Team   *  Copyright (C) 2002-2010  PCSX2 Dev Team
3   *   *
4   *  PCSX2 is free software: you can redistribute it and/or modify it under the terms   *  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-   *  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.   *  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;   *  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   *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10   *  PURPOSE.  See the GNU General Public License for more details.   *  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.   *  You should have received a copy of the GNU General Public License along with PCSX2.
13   *  If not, see <http://www.gnu.org/licenses/>.   *  If not, see <http://www.gnu.org/licenses/>.
14   */   */
15    
16  #pragma once  #pragma once
17    
18  #include "Threading.h"  #include "Threading.h"
19    
20  #if PCSX2_THREAD_LOCAL  #if PCSX2_THREAD_LOCAL
21  #       define DeclareTls(x) __threadlocal x  #       define DeclareTls(x) __threadlocal x
22  #else  #else
23  #       define DeclareTls(x) Threading::TlsVariable<x>  #       define DeclareTls(x) Threading::TlsVariable<x>
24  #endif  #endif
25    
26  namespace Threading  namespace Threading
27  {  {
28  // --------------------------------------------------------------------------------------  // --------------------------------------------------------------------------------------
29  //  TlsVariable - Thread local storage  //  TlsVariable - Thread local storage
30  // --------------------------------------------------------------------------------------  // --------------------------------------------------------------------------------------
31  // Wrapper class for pthread_getspecific, which is pthreads language for "thread local  // 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  // 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  // 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.  // not have TLS, which is the main reason for this class existing.
35  //  //
36  // Performance considerations: While certainly convenient, performance of this class can  // 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  // 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  // result in repeated calls to pthread_getspecific.  (if the function inlines then it
39  // should actually optimize well enough, but I doubt it does).  // should actually optimize well enough, but I doubt it does).
40  //  //
41          template< typename T >  template< typename T >
42          class TlsVariable  class BaseTlsVariable
43          {  {
44                  DeclareNoncopyableObject(TlsVariable);          DeclareNoncopyableObject(BaseTlsVariable<T>);
45    
46          protected:  protected:
47                  pthread_key_t   m_thread_key;          pthread_key_t   m_thread_key;
48                  T                               m_initval;          bool                    m_IsDisposed;
49    
50          public:  public:
51                  TlsVariable();          BaseTlsVariable();
52                  TlsVariable( T initval );  
53            virtual ~BaseTlsVariable() throw()
54                  virtual ~TlsVariable() throw();          {
55                  T* GetPtr() const;                  Dispose();
56                  T& GetRef() const { return *GetPtr(); }          }
57    
58                  TlsVariable& operator=( const T& src )          T* GetPtr() const;
59                  {          T& GetRef() const { return *GetPtr(); }
60                          GetRef() = src;  
61                          return *this;          operator T&() const             { return GetRef(); }
62                  }          T* operator->() const   { return GetPtr(); }
63    
64                  bool operator==( const T& src ) const   { return GetRef() == src; }          void Dispose()
65                  bool operator!=( const T& src ) const   { return GetRef() != src; }          {
66                  bool operator>( const T& src ) const    { return GetRef() > src; }                  if (!m_IsDisposed)
67                  bool operator<( const T& src ) const    { return GetRef() < src; }                  {
68                  bool operator>=( const T& src ) const   { return GetRef() >= src; }                          m_IsDisposed = true;
69                  bool operator<=( const T& src ) const   { return GetRef() <= src; }                          KillKey();
70                    }
71                  T operator+( const T& src ) const               { return GetRef() + src; }          }
72                  T operator-( const T& src ) const               { return GetRef() - src; }  
73    protected:
74                  void operator+=( const T& src )                 { GetRef() += src; }          void CreateKey();
75                  void operator-=( const T& src )                 { GetRef() -= src; }          void KillKey();
76    
77                  operator T&() const { return GetRef(); }          virtual void CreateInstance( T* result ) const
78            {
79          protected:                  new (result) T();
80                  void CreateKey();          }
81          };  
82  };          static void _aligned_delete_and_free( void* ptr )
83            {
84  template< typename T >                  if (!ptr) return;
85  Threading::TlsVariable<T>::TlsVariable()                  ((T*)ptr)->~T();
86  {                  _aligned_free(ptr);
87          CreateKey();          }
88  }  };
89    
90  template< typename T >  template< typename T >
91  Threading::TlsVariable<T>::TlsVariable( T initval )  class TlsVariable : public BaseTlsVariable<T>
92  {  {
93          CreateKey();          DeclareNoncopyableObject(TlsVariable<T>);
94          m_initval = initval;  
95  }  protected:
96            T                               m_initval;
97  template< typename T >  
98  Threading::TlsVariable<T>::~TlsVariable() throw()  public:
99  {          TlsVariable() {}
100          if( m_thread_key != NULL )          TlsVariable( const T& initval )
101                  pthread_key_delete( m_thread_key );                  : m_initval(initval) { }
102  }  
103            // This is needed; The C++ standard likes making life suck for programmers.
104  template< typename T >          using BaseTlsVariable<T>::GetRef;
105  T* Threading::TlsVariable<T>::GetPtr() const  
106  {          virtual ~TlsVariable() throw()
107          T* result = (T*)pthread_getspecific( m_thread_key );          {
108          if( result == NULL )                  // 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                  pthread_setspecific( m_thread_key, result = (T*)_aligned_malloc( sizeof(T), 16 ) );                  // Killing the pthread_key at all will lead to the console logger death, etc.
111                  if( result == NULL )                  
112                          throw Exception::OutOfMemory( "Out of memory allocating thread local storage variable." );                  // DON'T REMOVE this->, the "official"[ly stupid] C++ standard requires it because of its
113                  *result = m_initval;                  // insistence that variables be looked up during initial template parsing and not during
114          }                  // instantiation.
115          return result;                  this->m_IsDisposed = true;
116  }          }
117    
118  template< typename T >          TlsVariable<T>& operator=( const T& src )
119  void Threading::TlsVariable<T>::CreateKey()          {
120  {                  GetRef() = src;
121          if( 0 != pthread_key_create(&m_thread_key, _aligned_free) )                  return *this;
122          {          }
123                  pxFailRel( "Thread Local Storage Error: key creation failed." );  
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    }

Legend:
Removed from v.61  
changed lines
  Added in v.62

  ViewVC Help
Powered by ViewVC 1.1.22