thread.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  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. mThreadID = 0;
  51. mDead = false;
  52. };
  53. };
  54. //-----------------------------------------------------------------------------
  55. // Static Functions/Methods
  56. //-----------------------------------------------------------------------------
  57. //-----------------------------------------------------------------------------
  58. // Function: ThreadRunHandler
  59. // Summary: Calls Thread::run() with the thread's specified run argument.
  60. // Neccesary because Thread::run() is provided as a non-threaded
  61. // way to execute the thread's run function. So we have to keep
  62. // track of the thread's lock here.
  63. static U32 __stdcall ThreadRunHandler(void * arg)
  64. {
  65. PlatformThreadData* mData = reinterpret_cast<PlatformThreadData*>(arg);
  66. mData->mThreadID = GetCurrentThreadId();
  67. ThreadManager::addThread(mData->mThread);
  68. mData->mThread->run(mData->mRunArg);
  69. ThreadManager::removeThread(mData->mThread);
  70. bool autoDelete = mData->mThread->autoDelete;
  71. mData->mThreadHnd = NULL; // mark as dead
  72. dCompareAndSwap( mData->mDead, false, true );
  73. mData->mGateway.release(); // don't access data after this.
  74. if( autoDelete )
  75. delete mData->mThread; // Safe as we own the data.
  76. _endthreadex( 0 );
  77. return 0;
  78. }
  79. //-----------------------------------------------------------------------------
  80. // Constructor/Destructor
  81. //-----------------------------------------------------------------------------
  82. Thread::Thread(ThreadRunFunction func /* = 0 */, void *arg /* = 0 */, bool start_thread /* = true */, bool autodelete /*= false*/)
  83. : autoDelete( autodelete )
  84. {
  85. AssertFatal( !start_thread, "Thread::Thread() - auto-starting threads from ctor has been disallowed since the run() method is virtual" );
  86. mData = new PlatformThreadData;
  87. mData->mRunFunc = func;
  88. mData->mRunArg = arg;
  89. mData->mThread = this;
  90. }
  91. Thread::~Thread()
  92. {
  93. stop();
  94. if( isAlive() )
  95. join();
  96. SAFE_DELETE(mData);
  97. }
  98. //-----------------------------------------------------------------------------
  99. // Public Methods
  100. //-----------------------------------------------------------------------------
  101. void Thread::start( void* arg )
  102. {
  103. AssertFatal( !mData->mThreadHnd,
  104. "Thread::start() - thread already started" );
  105. // cause start to block out other pthreads from using this Thread,
  106. // at least until ThreadRunHandler exits.
  107. mData->mGateway.acquire();
  108. // reset the shouldStop flag, so we'll know when someone asks us to stop.
  109. shouldStop = false;
  110. mData->mDead = false;
  111. if( !mData->mRunArg )
  112. mData->mRunArg = arg;
  113. mData->mThreadHnd = (HANDLE)_beginthreadex(0, 0, ThreadRunHandler, mData, 0, 0);
  114. }
  115. bool Thread::join()
  116. {
  117. mData->mGateway.acquire();
  118. AssertFatal( !isAlive(), "Thread::join() - thread still alive after join" );
  119. mData->mGateway.release(); // release for further joins
  120. return true;
  121. }
  122. void Thread::run(void *arg /* = 0 */)
  123. {
  124. if(mData->mRunFunc)
  125. mData->mRunFunc(arg);
  126. }
  127. bool Thread::isAlive()
  128. {
  129. return ( !mData->mDead );
  130. }
  131. U32 Thread::getId()
  132. {
  133. return mData->mThreadID;
  134. }
  135. void Thread::_setName( const char* name )
  136. {
  137. #if defined( TORQUE_DEBUG ) && defined( TORQUE_COMPILER_VISUALC ) && defined( TORQUE_OS_WIN )
  138. // See http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
  139. #define MS_VC_EXCEPTION 0x406D1388
  140. #pragma pack(push,8)
  141. typedef struct tagTHREADNAME_INFO
  142. {
  143. DWORD dwType; // Must be 0x1000.
  144. LPCSTR szName; // Pointer to name (in user addr space).
  145. DWORD dwThreadID; // Thread ID (-1=caller thread).
  146. DWORD dwFlags; // Reserved for future use, must be zero.
  147. } THREADNAME_INFO;
  148. #pragma pack(pop)
  149. Sleep(10);
  150. THREADNAME_INFO info;
  151. info.dwType = 0x1000;
  152. info.szName = name;
  153. info.dwThreadID = getId();
  154. info.dwFlags = 0;
  155. __try
  156. {
  157. RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
  158. }
  159. __except(EXCEPTION_EXECUTE_HANDLER)
  160. {
  161. }
  162. #endif
  163. }
  164. U32 ThreadManager::getCurrentThreadId()
  165. {
  166. return GetCurrentThreadId();
  167. }
  168. bool ThreadManager::compare(U32 threadId_1, U32 threadId_2)
  169. {
  170. return (threadId_1 == threadId_2);
  171. }