Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

268 lines
7.9 KiB

  1. #include "thread.h"
  2. // Thread callback...
  3. #pragma LOCKEDCODE
  4. VOID CThread::ThreadFunction(CThread* Thread)
  5. {
  6. if(Thread) Thread->ThreadRoutine(NULL);
  7. }
  8. #pragma PAGEDCODE
  9. VOID CThread::ThreadRoutine(PVOID context)
  10. {
  11. NTSTATUS status;
  12. TRACE("================= STARTING THREAD %8.8lX ===============\n", thread);
  13. // Wait for a request to Start pooling or for
  14. // someone to kill this thread.
  15. PVOID mainevents[] = {(PVOID) &evKill,(PVOID) &evStart};
  16. PVOID pollevents[] = {(PVOID) &evKill,(PVOID) timer->getHandle(),(PVOID) &smOnDemandStart};
  17. ASSERT(arraysize(mainevents) <= THREAD_WAIT_OBJECTS);
  18. ASSERT(arraysize(pollevents) <= THREAD_WAIT_OBJECTS);
  19. BOOLEAN kill = FALSE;
  20. while (!kill && thread)
  21. { // until told to start or to quit
  22. ASSERT(system->getCurrentIrql()<=DISPATCH_LEVEL);
  23. // Before going to thread routine thread considered to be Idle
  24. if(event) event->set(&evIdle, IO_NO_INCREMENT, FALSE);
  25. status = event->waitForMultipleObjects(arraysize(mainevents),
  26. mainevents, WaitAny, Executive, KernelMode, FALSE, NULL, NULL);
  27. if(!NT_SUCCESS(status))
  28. { // error in wait
  29. TRACE("Thread: waitForMultipleObjects failed - %X\n", status);
  30. break;
  31. }
  32. if (status == STATUS_WAIT_0)
  33. {
  34. DEBUG_START();
  35. TRACE("Request to kill thread arrived...\n");
  36. TRACE("================= KILLING THREAD! ===============\n");
  37. break; // kill event was set
  38. }
  39. // Starting the timer with a zero due time will cause us to perform the
  40. // first poll immediately. Thereafter, polls occur at the POLLING_INTERVAL
  41. // interval (measured in milliseconds).
  42. // Now thread is busy...
  43. if(event) event->clear(&evIdle);
  44. LARGE_INTEGER duetime = {0};// Signal timer right away!
  45. timer->set(duetime, PoolingTimeout, NULL);
  46. while (TRUE)
  47. { // Block until time to poll again
  48. ASSERT(system->getCurrentIrql()<=DISPATCH_LEVEL);
  49. status = event->waitForMultipleObjects(arraysize(pollevents),
  50. pollevents, WaitAny, Executive, KernelMode, FALSE, NULL, NULL);
  51. if (!NT_SUCCESS(status))
  52. { // error in wait
  53. DEBUG_START();
  54. TRACE("CTread - waitForMultipleObjects failed - %X\n", status);
  55. TRACE("================= KILLING THREAD! ===============\n");
  56. timer->cancel();
  57. kill = TRUE;
  58. break;
  59. }
  60. if (status == STATUS_WAIT_0)
  61. { // told to quit
  62. DEBUG_START();
  63. TRACE("Loop: Request to kill thread arrived...\n");
  64. TRACE("================= KILLING THREAD! ===============\n");
  65. timer->cancel();
  66. status = STATUS_DELETE_PENDING;
  67. kill = TRUE;
  68. break;
  69. }
  70. //if(device)
  71. if(pfClientThreadFunction)
  72. {
  73. if(StopRequested) break;
  74. // Do device specific thread processing...
  75. //TRACE("Calling thread %8.8lX function...\n",thread);
  76. if(status = pfClientThreadFunction(ClientContext))
  77. {
  78. TRACE("Device reported error %8.8lX\n",status);
  79. timer->cancel();
  80. break;
  81. }
  82. }
  83. else
  84. {
  85. DEBUG_START();
  86. TRACE("================= THREAD FUNCTION POINTER IS NOT SET!! FINISHED... ===============\n");
  87. TRACE("================= KILLING THREAD! ===============\n");
  88. status = STATUS_DELETE_PENDING;
  89. kill = TRUE;
  90. break;
  91. }
  92. }
  93. }// until told to quit
  94. TRACE(" Leaving thread %8.8lX...\n", thread);
  95. if(event) event->set(&evIdle, IO_NO_INCREMENT, FALSE);
  96. if(event) event->set(&evStopped, IO_NO_INCREMENT, FALSE);
  97. if(semaphore) semaphore->initialize(&smOnDemandStart, 0, MAXLONG);
  98. if(system) system->terminateSystemThread(STATUS_SUCCESS);
  99. }
  100. #pragma PAGEDCODE
  101. CThread::CThread(PCLIENT_THREAD_ROUTINE ClientThreadFunction,PVOID ClientContext, ULONG delay)
  102. { // StartPollingThread for the device
  103. NTSTATUS status;
  104. HANDLE hthread;
  105. m_Status = STATUS_INSUFFICIENT_RESOURCES;
  106. //this->device = device;
  107. // Create objects..
  108. event = kernel->createEvent();
  109. system = kernel->createSystem();
  110. timer = kernel->createTimer(SynchronizationTimer);
  111. semaphore = kernel->createSemaphore();
  112. debug = kernel->createDebug();
  113. StopRequested = FALSE;
  114. ThreadActive = FALSE;
  115. if(ALLOCATED_OK(event))
  116. {
  117. event->initialize(&evKill, NotificationEvent, FALSE);
  118. event->initialize(&evStart, SynchronizationEvent, FALSE);
  119. event->initialize(&evStopped, NotificationEvent, FALSE);
  120. event->initialize(&evIdle, NotificationEvent, TRUE);
  121. }
  122. // At the begining there is no request to start,
  123. // so semaphore is not at signal state.
  124. if(ALLOCATED_OK(semaphore)) semaphore->initialize(&smOnDemandStart, 0, MAXLONG);
  125. pfClientThreadFunction = ClientThreadFunction;
  126. this->ClientContext = ClientContext;
  127. PoolingTimeout = delay; // Default thread pooling interval...
  128. // Create system thread object...
  129. status = system->createSystemThread(&hthread, THREAD_ALL_ACCESS, NULL, NULL, NULL,
  130. (PKSTART_ROUTINE) ThreadFunction, this);
  131. if(NT_SUCCESS(status)) // Get thread pointer...
  132. {
  133. thread = NULL;
  134. status = system->referenceObjectByHandle(hthread, THREAD_ALL_ACCESS, NULL,
  135. KernelMode, (PVOID*) &thread, NULL);
  136. if(!NT_SUCCESS(status))
  137. {
  138. TRACE("FAILED TO REFERENCE OBJECT! Error %8.8lX\n", status);
  139. }
  140. }
  141. else TRACE("FAILED TO CREATE SYSTEM THREAD! Error %8.8lX\n", status);
  142. system->ZwClose(hthread);
  143. if(NT_SUCCESS(status) &&
  144. ALLOCATED_OK(event)&&
  145. ALLOCATED_OK(system)&&
  146. ALLOCATED_OK(timer)&&
  147. ALLOCATED_OK(semaphore) && thread)
  148. m_Status = STATUS_SUCCESS;
  149. } // StartPollingThread
  150. #pragma PAGEDCODE
  151. CThread::~CThread()
  152. { // StopPollingThread
  153. DEBUG_START();
  154. TRACE("Terminating thread %8.8lX...\n", thread);
  155. if(event) event->set(&evKill, IO_NO_INCREMENT, FALSE);
  156. StopRequested = TRUE;
  157. //device = NULL;
  158. if (thread)
  159. { // wait for the thread to die
  160. if(system && event)
  161. {
  162. ASSERT(system->getCurrentIrql()<=DISPATCH_LEVEL);
  163. event->waitForSingleObject(&evStopped, Executive, KernelMode, FALSE, NULL);
  164. if(!isWin98())
  165. event->waitForSingleObject(thread, Executive, KernelMode, FALSE, NULL);
  166. system->dereferenceObject(thread);
  167. thread = NULL;
  168. }
  169. }
  170. TRACE("Thread terminated...\n");
  171. if(event) event->dispose();
  172. if(system) system->dispose();
  173. if(timer) timer->dispose();
  174. if(semaphore) semaphore->dispose();
  175. if(debug) debug->dispose();
  176. }
  177. #pragma PAGEDCODE
  178. VOID CThread::kill()
  179. {
  180. DEBUG_START();
  181. TRACE("Killing thread %8.8lX...\n", thread);
  182. StopRequested = TRUE;
  183. if(system)
  184. {
  185. ASSERT(system->getCurrentIrql()<=DISPATCH_LEVEL);
  186. }
  187. if(event) event->set(&evKill, IO_NO_INCREMENT, FALSE);
  188. if(event) event->waitForSingleObject(&evStopped, Executive, KernelMode, FALSE, NULL);
  189. }
  190. #pragma PAGEDCODE
  191. VOID CThread::start()
  192. {
  193. DEBUG_START();
  194. TRACE("Starting thread %8.8lX...\n", thread);
  195. if(system)
  196. {
  197. ASSERT(system->getCurrentIrql()<=DISPATCH_LEVEL);
  198. }
  199. StopRequested = FALSE;
  200. ThreadActive = TRUE;
  201. // Start Card pooling...
  202. if(event) event->set(&evStart, IO_NO_INCREMENT, FALSE);
  203. }
  204. #pragma PAGEDCODE
  205. VOID CThread::stop()
  206. {
  207. DEBUG_START();
  208. TRACE("Stop thread %8.8lX...\n", thread);
  209. StopRequested = TRUE;
  210. ThreadActive = FALSE;
  211. if(system)
  212. {
  213. ASSERT(system->getCurrentIrql()<=DISPATCH_LEVEL);
  214. }
  215. if(event) event->clear(&evStart);
  216. // Unblock thread if it is blocked...
  217. if(semaphore) semaphore->release(&smOnDemandStart,0,1,FALSE);
  218. // Wait for for the thread to go to the idle state...
  219. if(event) event->waitForSingleObject(&evIdle, Executive, KernelMode, FALSE, NULL);
  220. // Stop thread ...
  221. if(semaphore) semaphore->initialize(&smOnDemandStart, 0, MAXLONG);
  222. }
  223. #pragma PAGEDCODE
  224. BOOL CThread::isThreadActive()
  225. {
  226. return ThreadActive;
  227. }
  228. #pragma PAGEDCODE
  229. VOID CThread::setPoolingInterval(ULONG delay)
  230. {
  231. PoolingTimeout = delay;
  232. };
  233. #pragma PAGEDCODE
  234. VOID CThread::callThreadFunction()
  235. { // This will force thread function to be called right away.
  236. // Useful if we want to update some information or
  237. // start some processing without waiting for the pooling
  238. // timeout to occure.
  239. if(semaphore) semaphore->release(&smOnDemandStart,0,1,FALSE);
  240. };