/[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

--- trunk/common/include/Utilities/TlsVariable.inl	2010/09/07 06:28:05	61
+++ trunk/common/include/Utilities/TlsVariable.inl	2010/09/07 11:08:22	62
@@ -1,125 +1,189 @@
-/*  PCSX2 - PS2 Emulator for PCs
- *  Copyright (C) 2002-2010  PCSX2 Dev Team
- *
- *  PCSX2 is free software: you can redistribute it and/or modify it under the terms
- *  of the GNU Lesser General Public License as published by the Free Software Found-
- *  ation, either version 3 of the License, or (at your option) any later version.
- *
- *  PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- *  PURPOSE.  See the GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License along with PCSX2.
- *  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#pragma once
-
-#include "Threading.h"
-
-#if PCSX2_THREAD_LOCAL
-#	define DeclareTls(x) __threadlocal x
-#else
-#	define DeclareTls(x) Threading::TlsVariable<x>
-#endif
-
-namespace Threading
-{
-// --------------------------------------------------------------------------------------
-//  TlsVariable - Thread local storage
-// --------------------------------------------------------------------------------------
-// Wrapper class for pthread_getspecific, which is pthreads language for "thread local
-// storage."  This class enables code to act as a drop-in replacement for compiler-native
-// thread local storage (typically specified via __threadlocal).  Mac OS/X (Darwin) does
-// not have TLS, which is the main reason for this class existing.
-//
-// Performance considerations: While certainly convenient, performance of this class can
-// be sub-optimal when the operator overloads are used, since each one will most likely
-// result in repeated calls to pthread_getspecific.  (if the function inlines then it
-// should actually optimize well enough, but I doubt it does).
-//
-	template< typename T >
-	class TlsVariable
-	{
-		DeclareNoncopyableObject(TlsVariable);
-
-	protected:
-		pthread_key_t	m_thread_key;
-		T				m_initval;
-
-	public:
-		TlsVariable();
-		TlsVariable( T initval );
-
-		virtual ~TlsVariable() throw();
-		T* GetPtr() const;
-		T& GetRef() const { return *GetPtr(); }
-
-		TlsVariable& operator=( const T& src )
-		{
-			GetRef() = src;
-			return *this;
-		}
-
-		bool operator==( const T& src ) const	{ return GetRef() == src; }
-		bool operator!=( const T& src ) const	{ return GetRef() != src; }
-		bool operator>( const T& src ) const	{ return GetRef() > src; }
-		bool operator<( const T& src ) const	{ return GetRef() < src; }
-		bool operator>=( const T& src ) const	{ return GetRef() >= src; }
-		bool operator<=( const T& src ) const	{ return GetRef() <= src; }
-
-		T operator+( const T& src ) const		{ return GetRef() + src; }
-		T operator-( const T& src ) const		{ return GetRef() - src; }
-
-		void operator+=( const T& src )			{ GetRef() += src; }
-		void operator-=( const T& src )			{ GetRef() -= src; }
-
-		operator T&() const { return GetRef(); }
-
-	protected:
-		void CreateKey();
-	};
-};
-
-template< typename T >
-Threading::TlsVariable<T>::TlsVariable()
-{
-	CreateKey();
-}
-
-template< typename T >
-Threading::TlsVariable<T>::TlsVariable( T initval )
-{
-	CreateKey();
-	m_initval = initval;
-}
-
-template< typename T >
-Threading::TlsVariable<T>::~TlsVariable() throw()
-{
-	if( m_thread_key != NULL )
-		pthread_key_delete( m_thread_key );
-}
-
-template< typename T >
-T* Threading::TlsVariable<T>::GetPtr() const
-{
-	T* result = (T*)pthread_getspecific( m_thread_key );
-	if( result == NULL )
-	{
-		pthread_setspecific( m_thread_key, result = (T*)_aligned_malloc( sizeof(T), 16 ) );
-		if( result == NULL )
-			throw Exception::OutOfMemory( "Out of memory allocating thread local storage variable." );
-		*result = m_initval;
-	}
-	return result;
-}
-
-template< typename T >
-void Threading::TlsVariable<T>::CreateKey()
-{
-	if( 0 != pthread_key_create(&m_thread_key, _aligned_free) )
-	{
-		pxFailRel( "Thread Local Storage Error: key creation failed." );
-	}
-}
+/*  PCSX2 - PS2 Emulator for PCs
+ *  Copyright (C) 2002-2010  PCSX2 Dev Team
+ *
+ *  PCSX2 is free software: you can redistribute it and/or modify it under the terms
+ *  of the GNU Lesser General Public License as published by the Free Software Found-
+ *  ation, either version 3 of the License, or (at your option) any later version.
+ *
+ *  PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ *  PURPOSE.  See the GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along with PCSX2.
+ *  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "Threading.h"
+
+#if PCSX2_THREAD_LOCAL
+#	define DeclareTls(x) __threadlocal x
+#else
+#	define DeclareTls(x) Threading::TlsVariable<x>
+#endif
+
+namespace Threading
+{
+// --------------------------------------------------------------------------------------
+//  TlsVariable - Thread local storage
+// --------------------------------------------------------------------------------------
+// Wrapper class for pthread_getspecific, which is pthreads language for "thread local
+// storage."  This class enables code to act as a drop-in replacement for compiler-native
+// thread local storage (typically specified via __threadlocal).  Mac OS/X (Darwin) does
+// not have TLS, which is the main reason for this class existing.
+//
+// Performance considerations: While certainly convenient, performance of this class can
+// be sub-optimal when the operator overloads are used, since each one will most likely
+// result in repeated calls to pthread_getspecific.  (if the function inlines then it
+// should actually optimize well enough, but I doubt it does).
+//
+template< typename T >
+class BaseTlsVariable
+{
+	DeclareNoncopyableObject(BaseTlsVariable<T>);
+
+protected:
+	pthread_key_t	m_thread_key;
+	bool			m_IsDisposed;
+
+public:
+	BaseTlsVariable();
+
+	virtual ~BaseTlsVariable() throw()
+	{
+		Dispose();
+	}
+
+	T* GetPtr() const;
+	T& GetRef() const { return *GetPtr(); }
+
+	operator T&() const		{ return GetRef(); }
+	T* operator->() const	{ return GetPtr(); }
+
+	void Dispose()
+	{
+		if (!m_IsDisposed)
+		{
+			m_IsDisposed = true;
+			KillKey();
+		}
+	}
+
+protected:
+	void CreateKey();
+	void KillKey();
+
+	virtual void CreateInstance( T* result ) const
+	{
+		new (result) T();
+	}
+
+	static void _aligned_delete_and_free( void* ptr )
+	{
+		if (!ptr) return;
+		((T*)ptr)->~T();
+		_aligned_free(ptr);
+	}
+};
+
+template< typename T >
+class TlsVariable : public BaseTlsVariable<T>
+{
+	DeclareNoncopyableObject(TlsVariable<T>);
+
+protected:
+	T				m_initval;
+
+public:
+	TlsVariable() {}
+	TlsVariable( const T& initval )
+		: m_initval(initval) { }
+
+	// This is needed; The C++ standard likes making life suck for programmers.
+	using BaseTlsVariable<T>::GetRef;
+
+	virtual ~TlsVariable() throw()
+	{
+		// disable the parent cleanup.  This leaks memory blocks, but its necessary because
+		// TLS is expected to be persistent until the very end of execution on the main thread.
+		// Killing the pthread_key at all will lead to the console logger death, etc.
+		
+		// DON'T REMOVE this->, the "official"[ly stupid] C++ standard requires it because of its
+		// insistence that variables be looked up during initial template parsing and not during
+		// instantiation.
+		this->m_IsDisposed = true;
+	}
+
+	TlsVariable<T>& operator=( const T& src )
+	{
+		GetRef() = src;
+		return *this;
+	}
+
+	bool operator==( const T& src ) const	{ return GetRef() == src; }
+	bool operator!=( const T& src ) const	{ return GetRef() != src; }
+	bool operator>( const T& src ) const	{ return GetRef() > src; }
+	bool operator<( const T& src ) const	{ return GetRef() < src; }
+	bool operator>=( const T& src ) const	{ return GetRef() >= src; }
+	bool operator<=( const T& src ) const	{ return GetRef() <= src; }
+
+	T operator+( const T& src ) const		{ return GetRef() + src; }
+	T operator-( const T& src ) const		{ return GetRef() - src; }
+
+	void operator+=( const T& src )			{ GetRef() += src; }
+	void operator-=( const T& src )			{ GetRef() -= src; }
+	
+protected:
+	virtual void CreateInstance( T* result ) const
+	{
+		new (result) T(m_initval);
+	}
+};
+};
+
+template< typename T >
+Threading::BaseTlsVariable<T>::BaseTlsVariable()
+{
+	m_IsDisposed = false;
+	CreateKey();
+}
+
+template< typename T >
+void Threading::BaseTlsVariable<T>::KillKey()
+{
+	if (!m_thread_key) return;
+
+	// Delete the handle for the current thread (which should always be the main/UI thread!)
+	// This is needed because pthreads does *not* clean up the dangling objects when you delete
+	// the key.  The TLS for the process main thread will only be deleted when the process
+	// ends; which is too damn late (it shows up int he leaked memory blocks).
+
+	BaseTlsVariable<T>::_aligned_delete_and_free( pthread_getspecific(m_thread_key) );
+
+	pthread_key_delete( m_thread_key );
+	m_thread_key = 0;
+}
+
+template< typename T >
+T* Threading::BaseTlsVariable<T>::GetPtr() const
+{
+	T* result = (T*)pthread_getspecific( m_thread_key );
+	if( result == NULL )
+	{
+		pthread_setspecific( m_thread_key, result = (T*)_aligned_malloc(sizeof(T), 16) );
+		CreateInstance(result);
+		if( result == NULL )
+			throw Exception::OutOfMemory( L"thread local storage variable instance" );
+	}
+	return result;
+}
+
+template< typename T >
+void Threading::BaseTlsVariable<T>::CreateKey()
+{
+	if( 0 != pthread_key_create(&m_thread_key, BaseTlsVariable<T>::_aligned_delete_and_free) )
+	{
+		pxFailRel( "Thread Local Storage Error: key creation failed.  This will most likely lead to a rapid application crash." );
+	}
+}

 

  ViewVC Help
Powered by ViewVC 1.1.22