2012-06-14 09:06:06 -04:00
2012-09-23 17:23:33 -04:00
// IsThread.cpp
2012-06-14 09:06:06 -04:00
// Implements the cIsThread class representing an OS-independent wrapper for a class that implements a thread.
// This class will eventually suupersede the old cThread class
# include "Globals.h"
2012-09-23 17:23:33 -04:00
# include "IsThread.h"
2012-06-14 09:06:06 -04:00
2014-10-23 18:58:01 -04:00
# if defined(_MSC_VER) && defined(_DEBUG)
2015-12-19 09:30:32 -05:00
// Code adapted from MSDN: https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
2014-10-23 18:58:01 -04:00
const DWORD MS_VC_EXCEPTION = 0x406D1388 ;
# pragma pack(push, 8)
struct THREADNAME_INFO
{
2014-12-04 16:07:04 -05:00
DWORD dwType ; // Must be 0x1000.
LPCSTR szName ; // Pointer to name (in user addr space).
DWORD dwThreadID ; // Thread ID (-1 = caller thread).
DWORD dwFlags ; // Reserved for future use, must be zero.
2014-10-23 18:58:01 -04:00
} ;
# pragma pack(pop)
/** Sets the name of a thread with the specified ID
( When in MSVC , the debugger provides " thread naming " by catching special exceptions )
*/
static void SetThreadName ( std : : thread * a_Thread , const char * a_ThreadName )
{
THREADNAME_INFO info { 0x1000 , a_ThreadName , GetThreadId ( a_Thread - > native_handle ( ) ) , 0 } ;
__try
{
RaiseException ( MS_VC_EXCEPTION , 0 , sizeof ( info ) / sizeof ( ULONG_PTR ) , ( ULONG_PTR * ) & info ) ;
}
__except ( EXCEPTION_EXECUTE_HANDLER )
{
}
}
2014-12-04 16:07:04 -05:00
# endif // _MSC_VER && _DEBUG
2014-10-23 18:58:01 -04:00
2012-06-14 09:06:06 -04:00
////////////////////////////////////////////////////////////////////////////////
// cIsThread:
2014-10-18 19:29:34 -04:00
cIsThread : : cIsThread ( const AString & a_ThreadName ) :
2012-06-14 09:06:06 -04:00
m_ShouldTerminate ( false ) ,
2014-10-18 19:29:34 -04:00
m_ThreadName ( a_ThreadName )
2012-06-14 09:06:06 -04:00
{
}
cIsThread : : ~ cIsThread ( )
{
2018-07-22 17:35:58 -04:00
Stop ( ) ;
2012-06-14 09:06:06 -04:00
}
2014-12-24 18:34:54 -05:00
void cIsThread : : DoExecute ( void )
{
m_evtStart . Wait ( ) ;
Execute ( ) ;
}
2012-06-14 09:06:06 -04:00
bool cIsThread : : Start ( void )
{
2014-10-18 19:29:34 -04:00
try
{
2014-12-24 18:34:54 -05:00
// Initialize the thread:
m_Thread = std : : thread ( & cIsThread : : DoExecute , this ) ;
2014-10-23 18:58:01 -04:00
# if defined (_MSC_VER) && defined(_DEBUG)
if ( ! m_ThreadName . empty ( ) )
{
SetThreadName ( & m_Thread , m_ThreadName . c_str ( ) ) ;
}
# endif
2014-12-24 18:34:54 -05:00
// Notify the thread that initialization is complete and it can run its code safely:
m_evtStart . Set ( ) ;
2014-10-18 19:29:34 -04:00
return true ;
}
2014-12-24 18:34:54 -05:00
catch ( const std : : system_error & a_Exception )
2014-10-18 19:29:34 -04:00
{
2014-12-07 09:46:27 -05:00
LOGERROR ( " cIsThread::Start error %i: could not construct thread %s; %s " , a_Exception . code ( ) . value ( ) , m_ThreadName . c_str ( ) , a_Exception . code ( ) . message ( ) . c_str ( ) ) ;
2014-10-18 19:29:34 -04:00
return false ;
}
2012-06-14 09:06:06 -04:00
}
2013-08-11 13:40:15 -04:00
void cIsThread : : Stop ( void )
{
m_ShouldTerminate = true ;
Wait ( ) ;
2018-07-22 17:35:58 -04:00
m_ShouldTerminate = false ;
2013-08-11 13:40:15 -04:00
}
2012-06-14 09:06:06 -04:00
bool cIsThread : : Wait ( void )
2014-10-20 16:26:18 -04:00
{
2014-12-07 09:46:27 -05:00
LOGD ( " Waiting for thread %s to finish " , m_ThreadName . c_str ( ) ) ;
2014-10-18 19:29:34 -04:00
if ( m_Thread . joinable ( ) )
{
try
{
m_Thread . join ( ) ;
return true ;
}
2015-06-22 16:27:13 -04:00
catch ( const std : : system_error & a_Exception )
2014-10-18 19:29:34 -04:00
{
2015-06-22 16:27:13 -04:00
LOGERROR ( " %s error %i: could not join thread %s; %s " , __FUNCTION__ , a_Exception . code ( ) . value ( ) , m_ThreadName . c_str ( ) , a_Exception . code ( ) . message ( ) . c_str ( ) ) ;
2014-10-18 19:29:34 -04:00
return false ;
}
}
2012-06-14 09:06:06 -04:00
2014-12-07 09:46:27 -05:00
LOGD ( " Thread %s finished " , m_ThreadName . c_str ( ) ) ;
2014-10-18 19:29:34 -04:00
return true ;
2014-06-08 15:58:08 -04:00
}