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.

374 lines
7.5 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. All rights reserved
  4. Module Name:
  5. ThreadM.c
  6. Abstract:
  7. Generic thread manager for spooler.
  8. Author:
  9. Albert Ting (AlbertT) 13-Feb-1994
  10. Environment:
  11. User Mode -Win32
  12. Revision History:
  13. --*/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. #include "threadm.h"
  17. #define ENTER_CRITICAL(pTMStateVar) \
  18. EnterCriticalSection(pTMStateVar->pTMStateStatic->pCritSec)
  19. #define LEAVE_CRITICAL(pTMStateVar) \
  20. LeaveCriticalSection(pTMStateVar->pTMStateStatic->pCritSec)
  21. //
  22. // Prototypes
  23. //
  24. DWORD
  25. xTMThreadProc(
  26. LPVOID pVoid);
  27. BOOL
  28. TMCreateStatic(
  29. PTMSTATESTATIC pTMStateStatic)
  30. /*++
  31. Routine Description:
  32. Intialize static state.
  33. Arguments:
  34. pTMStateStatic - static state to initialize
  35. Return Value:
  36. TRUE = success
  37. FALSE = fail
  38. --*/
  39. {
  40. return TRUE;
  41. }
  42. VOID
  43. TMDestroyStatic(
  44. PTMSTATESTATIC pTMStateStatic)
  45. /*++
  46. Routine Description:
  47. Destroys static state.
  48. Arguments:
  49. pTMStateStatic - static state to destroy
  50. Return Value:
  51. VOID
  52. --*/
  53. {
  54. }
  55. BOOL
  56. TMCreate(
  57. PTMSTATESTATIC pTMStateStatic,
  58. PTMSTATEVAR pTMStateVar)
  59. /*++
  60. Routine Description:
  61. Creates a virtual TM object.
  62. Arguments:
  63. pTMStateStatic - static portion of the TM object that can be
  64. used multiple times for subsequent instantiations.
  65. pTMStateVar - variable portion of the structure; 1 per instantiation
  66. Return Value:
  67. TRUE = success
  68. FALSE = fail
  69. --*/
  70. {
  71. pTMStateVar->hTrigger = CreateEvent(NULL,
  72. FALSE,
  73. FALSE,
  74. NULL);
  75. if (!pTMStateVar->hTrigger)
  76. return FALSE;
  77. pTMStateVar->uIdleThreads = 0;
  78. pTMStateVar->uActiveThreads = 0;
  79. pTMStateVar->Status = TMSTATUS_NULL;
  80. pTMStateVar->pTMStateStatic = pTMStateStatic;
  81. return TRUE;
  82. }
  83. BOOL
  84. TMDestroy(
  85. PTMSTATEVAR pTMStateVar)
  86. /*++
  87. Routine Description:
  88. Destroy TM object. If threads are currently processing the object,
  89. mark it pending and return.
  90. Arguments:
  91. pTMStateVar - TM Object to destroy
  92. Return Value:
  93. TRUE = success
  94. FALSE = fail
  95. --*/
  96. {
  97. ENTER_CRITICAL(pTMStateVar);
  98. pTMStateVar->Status |= TMSTATUS_DESTROY_REQ;
  99. if (!pTMStateVar->uActiveThreads) {
  100. //
  101. // Mark as destroyed so that no more jobs are processed.
  102. //
  103. pTMStateVar->Status |= TMSTATUS_DESTROYED;
  104. LEAVE_CRITICAL(pTMStateVar);
  105. if (pTMStateVar->pTMStateStatic->pfnCloseState)
  106. (*pTMStateVar->pTMStateStatic->pfnCloseState)(pTMStateVar);
  107. } else {
  108. LEAVE_CRITICAL(pTMStateVar);
  109. }
  110. return TRUE;
  111. }
  112. BOOL
  113. TMAddJob(
  114. PTMSTATEVAR pTMStateVar)
  115. {
  116. DWORD dwThreadId;
  117. HANDLE hThread;
  118. BOOL rc = TRUE;
  119. ENTER_CRITICAL(pTMStateVar);
  120. if (pTMStateVar->Status & TMSTATUS_DESTROY_REQ) {
  121. rc = FALSE;
  122. } else {
  123. //
  124. // Check if we can give it to an idle thread.
  125. //
  126. if (pTMStateVar->uIdleThreads) {
  127. pTMStateVar->uIdleThreads--;
  128. DBGMSG(DBG_NOTIFY, ("Trigger event: uIdleThreads = %d\n",
  129. pTMStateVar->uIdleThreads));
  130. SetEvent(pTMStateVar->hTrigger);
  131. } else if (pTMStateVar->uActiveThreads <
  132. pTMStateVar->pTMStateStatic->uMaxThreads) {
  133. //
  134. // We have less active threads than the max; create a new one.
  135. //
  136. DBGMSG(DBG_NOTIFY, ("Create thread: uActiveThreads = %d\n",
  137. pTMStateVar->uActiveThreads));
  138. hThread = CreateThread(NULL,
  139. 0,
  140. xTMThreadProc,
  141. pTMStateVar,
  142. 0,
  143. &dwThreadId);
  144. if (hThread) {
  145. CloseHandle(hThread);
  146. //
  147. // We have successfully created a thread; up the
  148. // count.
  149. //
  150. pTMStateVar->uActiveThreads++;
  151. } else {
  152. rc = FALSE;
  153. }
  154. }
  155. }
  156. LEAVE_CRITICAL(pTMStateVar);
  157. return rc;
  158. }
  159. DWORD
  160. xTMThreadProc(
  161. LPVOID pVoid)
  162. /*++
  163. Routine Description:
  164. Worker thread routine that calls the client to process the jobs.
  165. Arguments:
  166. pVoid - pTMStateVar
  167. Return Value:
  168. Ignored.
  169. --*/
  170. {
  171. PTMSTATEVAR pTMStateVar = (PTMSTATEVAR)pVoid;
  172. PJOB pJob;
  173. BOOL bQuit = FALSE;
  174. pJob = (*pTMStateVar->pTMStateStatic->pfnNextJob)(pTMStateVar);
  175. do {
  176. while (pJob) {
  177. //
  178. // Call back to client to process the job.
  179. //
  180. (*pTMStateVar->pTMStateStatic->pfnProcessJob)(pTMStateVar, pJob);
  181. //
  182. // If we are pending shutdown, quit now.
  183. //
  184. if (pTMStateVar->Status & TMSTATUS_DESTROY_REQ) {
  185. bQuit = TRUE;
  186. break;
  187. }
  188. pJob = (*pTMStateVar->pTMStateStatic->pfnNextJob)(pTMStateVar);
  189. }
  190. ENTER_CRITICAL(pTMStateVar);
  191. pTMStateVar->uIdleThreads++;
  192. pTMStateVar->uActiveThreads--;
  193. DBGMSG(DBG_NOTIFY, ("Going to sleep: uIdle = %d, uActive = %d\n",
  194. pTMStateVar->uIdleThreads,
  195. pTMStateVar->uActiveThreads));
  196. LEAVE_CRITICAL(pTMStateVar);
  197. if (bQuit)
  198. break;
  199. //
  200. // Done, now relax and go idle for a bit. We don't care whether
  201. // we timeout or get triggered; in either case we check for another
  202. // job.
  203. //
  204. WaitForSingleObject(pTMStateVar->hTrigger,
  205. pTMStateVar->pTMStateStatic->uIdleLife);
  206. ENTER_CRITICAL(pTMStateVar);
  207. if (pTMStateVar->Status & TMSTATUS_DESTROY_REQ) {
  208. pJob = NULL;
  209. } else {
  210. //
  211. // We must check here instead of relying on the return value
  212. // of WaitForSingleObject since someone may see uIdleThreads!=0
  213. // and set the trigger, but we timeout before it gets set.
  214. //
  215. pJob = (*pTMStateVar->pTMStateStatic->pfnNextJob)(pTMStateVar);
  216. }
  217. if (pJob) {
  218. pTMStateVar->uActiveThreads++;
  219. DBGMSG(DBG_NOTIFY, ("Woke and found job: uActiveThreads = %d\n",
  220. pTMStateVar->uActiveThreads));
  221. } else {
  222. if (!pTMStateVar->uIdleThreads) {
  223. //
  224. // We may add a job that already is on the list, so
  225. // uIdleThreads gets dec'd twice, but only 1 job left.
  226. //
  227. DBGMSG(DBG_NOTIFY, ("threadm: No jobs, yet no idle threads\n"));
  228. } else {
  229. //
  230. // No jobs, we are going to exit, so we are no longer idle
  231. //
  232. pTMStateVar->uIdleThreads--;
  233. }
  234. }
  235. LEAVE_CRITICAL(pTMStateVar);
  236. } while (pJob);
  237. DBGMSG(DBG_NOTIFY, ("No active jobs: uIdleThreads = %d, uActiveThreads = %d\n",
  238. pTMStateVar->uIdleThreads,
  239. pTMStateVar->uActiveThreads));
  240. return 0;
  241. }