pcsx2/common/include/Utilities/TlsVariable.inl
Jake.Stine 912872af80 Introducing a mostly revamped Tracelog and Console log system. Various console log sources can now be toggled on/off on the fly, allowing end users to enable more verbose logging when they encounter problems. Both console and trace sources can be given automatic prefixing.
DevNotes:  DevCon logs are now available in *Release* builds as well as Devel builds, and can be enabled from the Console window's "Sources" menu.  They are disabled by default in Release builds, and are always enabled regardless of the ini setting in devel builds.  Debug logs are still strictly available in debug builds only.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@3609 96395faa-99c1-11dd-bbfe-3dabce05a288
2010-08-06 05:46:09 +00:00

190 lines
5.5 KiB
C++

/* 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." );
}
}