thread.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #ifndef TORQUE_OS_XENON
  23. #include "platformWin32/platformWin32.h"
  24. #endif
  25. #include "platform/threads/thread.h"
  26. #include "platform/threads/semaphore.h"
  27. #include "platform/platformIntrinsics.h"
  28. #include "core/util/safeDelete.h"
  29. #include <process.h> // [tom, 4/20/2006] for _beginthread()
  30. ThreadManager::MainThreadId ThreadManager::smMainThreadId;
  31. //-----------------------------------------------------------------------------
  32. // Thread data
  33. //-----------------------------------------------------------------------------
  34. class PlatformThreadData
  35. {
  36. public:
  37. ThreadRunFunction mRunFunc;
  38. void* mRunArg;
  39. Thread* mThread;
  40. HANDLE mThreadHnd;
  41. Semaphore mGateway;
  42. U32 mThreadID;
  43. U32 mDead;
  44. PlatformThreadData()
  45. {
  46. mRunFunc = NULL;
  47. mRunArg = 0;
  48. mThread = 0;
  49. mThreadHnd = 0;
  50. mDead = false;
  51. };
  52. };
  53. //-----------------------------------------------------------------------------
  54. // Static Functions/Methods
  55. //-----------------------------------------------------------------------------
  56. //-----------------------------------------------------------------------------
  57. // Function: ThreadRunHandler
  58. // Summary: Calls Thread::run() with the thread's specified run argument.
  59. // Neccesary because Thread::run() is provided as a non-threaded
  60. // way to execute the thread's run function. So we have to keep
  61. // track of the thread's lock here.
  62. static unsigned int __stdcall ThreadRunHandler(void * arg)
  63. {
  64. PlatformThreadData* mData = reinterpret_cast<PlatformThreadData*>(arg);
  65. mData->mThreadID = GetCurrentThreadId();
  66. ThreadManager::addThread(mData->mThread);
  67. mData->mThread->run(mData->mRunArg);
  68. ThreadManager::removeThread(mData->mThread);
  69. bool autoDelete = mData->mThread->autoDelete;
  70. mData->mThreadHnd = NULL; // mark as dead
  71. dCompareAndSwap( mData->mDead, false, true );
  72. mData->mGateway.release(); // don't access data after this.
  73. if( autoDelete )
  74. delete mData->mThread; // Safe as we own the data.
  75. _endthreadex( 0 );
  76. return 0;
  77. }
  78. //-----------------------------------------------------------------------------
  79. // Constructor/Destructor
  80. //-----------------------------------------------------------------------------
  81. Thread::Thread(ThreadRunFunction func /* = 0 */, void *arg /* = 0 */, bool start_thread /* = true */, bool autodelete /*= false*/)
  82. : autoDelete( autodelete )
  83. {
  84. AssertFatal( !start_thread, "Thread::Thread() - auto-starting threads from ctor has been disallowed since the run() method is virtual" );
  85. mData = new PlatformThreadData;
  86. mData->mRunFunc = func;
  87. mData->mRunArg = arg;
  88. mData->mThread = this;
  89. }
  90. Thread::~Thread()
  91. {
  92. stop();
  93. if( isAlive() )
  94. join();
  95. SAFE_DELETE(mData);
  96. }
  97. //-----------------------------------------------------------------------------
  98. // Public Methods
  99. //-----------------------------------------------------------------------------
  100. void Thread::start( void* arg )
  101. {
  102. AssertFatal( !mData->mThreadHnd,
  103. "Thread::start() - thread already started" );
  104. // cause start to block out other pthreads from using this Thread,
  105. // at least until ThreadRunHandler exits.
  106. mData->mGateway.acquire();
  107. // reset the shouldStop flag, so we'll know when someone asks us to stop.
  108. shouldStop = false;
  109. mData->mDead = false;
  110. if( !mData->mRunArg )
  111. mData->mRunArg = arg;
  112. mData->mThreadHnd = (HANDLE)_beginthreadex(0, 0, ThreadRunHandler, mData, 0, 0);
  113. }
  114. bool Thread::join()
  115. {
  116. mData->mGateway.acquire();
  117. AssertFatal( !isAlive(), "Thread::join() - thread still alive after join" );
  118. mData->mGateway.release(); // release for further joins
  119. return true;
  120. }
  121. void Thread::run(void *arg /* = 0 */)
  122. {
  123. if(mData->mRunFunc)
  124. mData->mRunFunc(arg);
  125. }
  126. bool Thread::isAlive()
  127. {
  128. return ( !mData->mDead );
  129. }
  130. U32 Thread::getId()
  131. {
  132. return mData->mThreadID;
  133. }
  134. void Thread::_setName( const char* name )
  135. {
  136. #if defined( TORQUE_DEBUG ) && defined( TORQUE_COMPILER_VISUALC ) && defined( TORQUE_OS_WIN )
  137. // See http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
  138. #define MS_VC_EXCEPTION 0x406D1388
  139. #pragma pack(push,8)
  140. typedef struct tagTHREADNAME_INFO
  141. {
  142. DWORD dwType; // Must be 0x1000.
  143. LPCSTR szName; // Pointer to name (in user addr space).
  144. DWORD dwThreadID; // Thread ID (-1=caller thread).
  145. DWORD dwFlags; // Reserved for future use, must be zero.
  146. } THREADNAME_INFO;
  147. #pragma pack(pop)
  148. Sleep(10);
  149. THREADNAME_INFO info;
  150. info.dwType = 0x1000;
  151. info.szName = name;
  152. info.dwThreadID = getId();
  153. info.dwFlags = 0;
  154. __try
  155. {
  156. RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
  157. }
  158. __except(EXCEPTION_EXECUTE_HANDLER)
  159. {
  160. }
  161. #endif
  162. }
  163. U32 ThreadManager::getCurrentThreadId()
  164. {
  165. return GetCurrentThreadId();
  166. }
  167. bool ThreadManager::compare(U32 threadId_1, U32 threadId_2)
  168. {
  169. return (threadId_1 == threadId_2);
  170. }