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