W32Thread.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. /* Copyright The kNet Project.
  2. Licensed under the Apache License, Version 2.0 (the "License");
  3. you may not use this file except in compliance with the License.
  4. You may obtain a copy of the License at
  5. http://www.apache.org/licenses/LICENSE-2.0
  6. Unless required by applicable law or agreed to in writing, software
  7. distributed under the License is distributed on an "AS IS" BASIS,
  8. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. See the License for the specific language governing permissions and
  10. limitations under the License. */
  11. /** @file W32Thread.cpp
  12. @brief */
  13. #include <cassert>
  14. #include <exception>
  15. #include "kNet/Thread.h"
  16. #include "kNet/NetworkLogging.h"
  17. #include "kNet/Clock.h"
  18. #include "kNet/NetException.h"
  19. #include "kNet/Network.h"
  20. #include "kNet/DebugMemoryLeakCheck.h"
  21. namespace kNet
  22. {
  23. Thread::Thread()
  24. :threadHandle(NULL),
  25. threadId(0),
  26. threadEnabled(false),
  27. invoker(0)
  28. {
  29. }
  30. Thread::~Thread()
  31. {
  32. Stop();
  33. delete invoker;
  34. }
  35. bool Thread::ShouldQuit() const { return threadHandle == NULL || threadEnabled == false; }
  36. bool Thread::IsRunning() const
  37. {
  38. if (threadHandle == NULL)
  39. return false;
  40. DWORD exitCode = 0;
  41. BOOL result = GetExitCodeThread(threadHandle, &exitCode);
  42. if (result == 0)
  43. {
  44. KNET_LOG(LogError, "Warning: Received error %d from GetExitCodeThread in Thread::IsRunning!", GetLastError());
  45. return false;
  46. }
  47. return exitCode == STILL_ACTIVE;
  48. }
  49. void Thread::Stop()
  50. {
  51. // Signal that the thread should quit now.
  52. threadEnabled = false;
  53. if (threadHandle == NULL)
  54. {
  55. threadHoldEvent.Close();
  56. threadHoldEventAcked.Close();
  57. threadResumeEvent.Close();
  58. delete invoker;
  59. invoker = 0;
  60. return;
  61. }
  62. kNet::Clock::Sleep(10);
  63. assert(threadHandle != 0);
  64. int numTries = 100;
  65. while(numTries-- > 0)
  66. {
  67. DWORD exitCode = 0;
  68. BOOL result = GetExitCodeThread(threadHandle, &exitCode);
  69. if (result == 0)
  70. {
  71. KNET_LOG(LogError, "Warning: Received error %d from GetExitCodeThread in Thread::Stop()!", GetLastError());
  72. break;
  73. }
  74. else if (exitCode != STILL_ACTIVE)
  75. {
  76. CloseHandle(threadHandle);
  77. threadHandle = NULL;
  78. break;
  79. }
  80. kNet::Clock::Sleep(50);
  81. }
  82. if (threadHandle != NULL)
  83. {
  84. TerminateThread(threadHandle, (DWORD)-1);
  85. // CloseHandle(threadHandle);
  86. KNET_LOG(LogError, "Warning: Had to forcibly terminate thread!");
  87. }
  88. KNET_LOG(LogInfo, "Thread::Stop() called.");
  89. threadHandle = NULL;
  90. threadId = 0;
  91. delete invoker;
  92. invoker = 0;
  93. threadHoldEvent.Close();
  94. threadHoldEventAcked.Close();
  95. threadResumeEvent.Close();
  96. }
  97. DWORD WINAPI ThreadEntryPoint(LPVOID lpParameter)
  98. {
  99. KNET_LOG(LogInfo, "ThreadEntryPoint: Thread started with param 0x%08X.", lpParameter);
  100. Thread *thread = reinterpret_cast<Thread*>(lpParameter);
  101. if (!thread)
  102. {
  103. KNET_LOG(LogError, "Invalid thread start parameter 0!");
  104. return (DWORD)-1;
  105. }
  106. thread->_ThreadRun();
  107. return 0;
  108. }
  109. void Thread::_ThreadRun()
  110. {
  111. try
  112. {
  113. if (!threadEnabled)
  114. {
  115. KNET_LOG(LogError, "ThreadEntryPoint: Thread immediately requested to quit.");
  116. return;
  117. }
  118. invoker->Invoke();
  119. } catch(NetException &e)
  120. {
  121. KNET_LOG(LogError, "NetException thrown in thread: %s.", e.what());
  122. } catch(std::exception &e)
  123. {
  124. KNET_LOG(LogError, "std::exception thrown in thread: %s.", e.what());
  125. } catch(...)
  126. {
  127. KNET_LOG(LogError, "Unknown exception thrown in thread.");
  128. }
  129. }
  130. void Thread::StartThread()
  131. {
  132. if (threadHandle != NULL)
  133. return;
  134. threadHoldEvent = CreateNewEvent(EventWaitSignal);
  135. threadHoldEventAcked = CreateNewEvent(EventWaitSignal);
  136. threadResumeEvent = CreateNewEvent(EventWaitSignal);
  137. threadEnabled = true;
  138. threadHandle = CreateThread(NULL, 0, ThreadEntryPoint, this, 0, &threadId);
  139. if (threadHandle == NULL)
  140. throw NetException("Failed to create thread!");
  141. else
  142. KNET_LOG(LogInfo, "Thread::Run(): Thread created.");
  143. SetName("kNet Thread");
  144. }
  145. void Thread::Sleep(int msecs)
  146. {
  147. ///\todo Allow interruption between sleep.
  148. Clock::Sleep(msecs);
  149. }
  150. ThreadId Thread::Id()
  151. {
  152. return threadId;
  153. }
  154. ThreadId Thread::CurrentThreadId()
  155. {
  156. return GetCurrentThreadId();
  157. }
  158. ThreadId Thread::NullThreadId()
  159. {
  160. return 0;
  161. }
  162. } // ~kNet