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.

402 lines
8.7 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. tpswork.cpp
  5. Abstract:
  6. Contains Win32 thread pool services worker thread functions
  7. Contents:
  8. SHSetThreadPoolLimits
  9. SHTerminateThreadPool
  10. SHQueueUserWorkItem
  11. SHCancelUserWorkItems
  12. TerminateWorkers
  13. TpsEnter
  14. (InitializeWorkerThreadPool)
  15. (StartIOWorkerThread)
  16. (QueueIOWorkerRequest)
  17. (IOWorkerThread)
  18. (ExecuteIOWorkItem)
  19. Author:
  20. Richard L Firth (rfirth) 10-Feb-1998
  21. Environment:
  22. Win32 user-mode
  23. Revision History:
  24. 10-Feb-1998 rfirth
  25. Created
  26. 12-Aug-1998 rfirth
  27. Rewritten for DEMANDTHREAD and LONGEXEC work items. Officially
  28. divergent from original which was based on NT5 base thread pool API
  29. --*/
  30. #include "priv.h"
  31. #include "threads.h"
  32. #include "tpsclass.h"
  33. //
  34. // private prototypes
  35. //
  36. struct WorkItem {
  37. LPTHREAD_START_ROUTINE pfnCallback;
  38. LPVOID pContext;
  39. HMODULE hModuleToFree;
  40. };
  41. PRIVATE
  42. VOID
  43. ExecuteWorkItem(
  44. IN WorkItem *pItem
  45. );
  46. //
  47. // global data
  48. //
  49. BOOL g_bTpsTerminating = FALSE;
  50. const char g_cszShlwapi[] = "SHLWAPI.DLL";
  51. DWORD g_ActiveRequests = 0;
  52. DWORD g_dwTerminationThreadId = 0;
  53. BOOL g_bDeferredWorkerTermination = FALSE;
  54. //
  55. // functions
  56. //
  57. LWSTDAPI_(BOOL)
  58. SHSetThreadPoolLimits(
  59. IN PSH_THREAD_POOL_LIMITS pLimits
  60. )
  61. /*++
  62. Routine Description:
  63. Change internal settings
  64. Arguments:
  65. pLimits - pointer to SH_THREAD_POOL_LIMITS structure containing limits
  66. to set
  67. Return Value:
  68. BOOL
  69. Success - TRUE
  70. Failure - FALSE. See GetLastError() for more info
  71. --*/
  72. {
  73. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  74. return FALSE;
  75. }
  76. LWSTDAPI_(BOOL)
  77. SHTerminateThreadPool(
  78. VOID
  79. )
  80. /*++
  81. Routine Description:
  82. Required to clean up threads before unloading SHLWAPI
  83. Arguments:
  84. None.
  85. Return Value:
  86. BOOL
  87. Success - TRUE
  88. Failure - FALSE
  89. --*/
  90. {
  91. if (InterlockedExchange((PLONG)&g_bTpsTerminating, TRUE)) {
  92. return TRUE;
  93. }
  94. //
  95. // wait until all in-progress requests have finished
  96. //
  97. while (g_ActiveRequests != 0) {
  98. SleepEx(0, FALSE);
  99. }
  100. //
  101. // kill all wait threads
  102. //
  103. TerminateWaiters();
  104. if (!g_bDeferredWaiterTermination) {
  105. g_dwTerminationThreadId = 0;
  106. g_bTpsTerminating = FALSE;
  107. } else {
  108. g_dwTerminationThreadId = GetCurrentThreadId();
  109. }
  110. return TRUE;
  111. }
  112. LWSTDAPI_(BOOL)
  113. SHQueueUserWorkItem(
  114. IN LPTHREAD_START_ROUTINE pfnCallback,
  115. IN LPVOID pContext,
  116. IN LONG lPriority,
  117. IN DWORD_PTR dwTag,
  118. OUT DWORD_PTR * pdwId OPTIONAL,
  119. IN LPCSTR pszModule OPTIONAL,
  120. IN DWORD dwFlags
  121. )
  122. /*++
  123. Routine Description:
  124. Queues a work item and associates a user-supplied tag for use by
  125. SHCancelUserWorkItems()
  126. N.B. IO work items CANNOT be cancelled due to the fact that they are
  127. queued as APCs and there is no OS support to revoke an APC
  128. Arguments:
  129. pfnCallback - caller-supplied function to call
  130. pContext - caller-supplied context argument to pfnCallback
  131. lPriority - relative priority of non-IO work item. Default is 0
  132. dwTag - caller-supplied tag for non-IO work item if TPS_TAGGEDITEM
  133. pdwId - pointer to returned ID. Pass NULL if not required. ID will be
  134. 0 for an IO work item
  135. pszModule - if specified, name of library (DLL) to load and free so that
  136. the dll will reamin in our process for the lifetime of the work
  137. item.
  138. dwFlags - flags modifying request:
  139. TPS_EXECUTEIO
  140. - execute work item in I/O thread. If set, work item
  141. cannot be tagged (and therefore cannot be subsequently
  142. cancelled) and cannot have an associated priority
  143. (both tag and priority are ignored for I/O work items)
  144. TPS_TAGGEDITEM
  145. - the dwTag field is meaningful
  146. TPS_DEMANDTHREAD
  147. - a thread will be created for this work item if one is
  148. not currently available. DEMANDTHREAD work items are
  149. queued at the head of the work queue. That is, they
  150. get the highest priority
  151. TPS_LONGEXECTIME
  152. - caller expects this work item to take relatively long
  153. time to complete (e.g. it could be in a UI loop). Work
  154. items thus described remove a thread from the pool for
  155. an indefinite amount of time
  156. Return Value:
  157. BOOL
  158. Success - TRUE
  159. Failure - FALSE. See GetLastError() for more info
  160. --*/
  161. {
  162. DWORD error;
  163. if (dwFlags & TPS_INVALID_FLAGS) {
  164. error = ERROR_INVALID_PARAMETER;
  165. goto exit;
  166. }
  167. error = TpsEnter();
  168. if (error != ERROR_SUCCESS) {
  169. goto exit;
  170. }
  171. ASSERT(!(dwFlags & TPS_EXECUTEIO));
  172. if (!(dwFlags & TPS_EXECUTEIO))
  173. {
  174. // Use NT Thread pool!
  175. WorkItem *pItem = new WorkItem;
  176. if (pItem)
  177. {
  178. pItem->pfnCallback = pfnCallback;
  179. pItem->pContext = pContext;
  180. if (pszModule && *pszModule)
  181. {
  182. pItem->hModuleToFree = LoadLibrary(pszModule);
  183. }
  184. ULONG uFlags = WT_EXECUTEDEFAULT;
  185. if (dwFlags & TPS_LONGEXECTIME)
  186. uFlags |= WT_EXECUTELONGFUNCTION;
  187. error = ERROR_SUCCESS;
  188. if (!QueueUserWorkItem((LPTHREAD_START_ROUTINE)ExecuteWorkItem, (PVOID)pItem, uFlags))
  189. {
  190. error = GetLastError();
  191. if (pItem->hModuleToFree)
  192. FreeLibrary(pItem->hModuleToFree);
  193. delete pItem;
  194. }
  195. }
  196. else
  197. {
  198. error = ERROR_NOT_ENOUGH_MEMORY;
  199. }
  200. }
  201. else
  202. {
  203. error = ERROR_CALL_NOT_IMPLEMENTED;
  204. }
  205. TpsLeave();
  206. exit:
  207. BOOL success = TRUE;
  208. if (error != ERROR_SUCCESS) {
  209. SetLastError(error);
  210. success = FALSE;
  211. }
  212. return success;
  213. }
  214. LWSTDAPI_(DWORD)
  215. SHCancelUserWorkItems(
  216. IN DWORD_PTR dwTagOrId,
  217. IN BOOL bTag
  218. )
  219. /*++
  220. Routine Description:
  221. Cancels one or more queued work items. By default, if ID is supplied, only
  222. one work item can be cancelled. If tag is supplied, all work items with same
  223. tag will be deleted
  224. Arguments:
  225. dwTagOrId - user-supplied tag or API-supplied ID of work item(s) to
  226. cancel. Used as search key
  227. bTag - TRUE if dwTagOrId is tag else ID
  228. Return Value:
  229. DWORD
  230. Success - Number of work items successfully cancelled (0..0xFFFFFFFE)
  231. Failure - 0xFFFFFFFF. Use GetLastError() for more info
  232. ERROR_SHUTDOWN_IN_PROGRESS
  233. - DLL being unloaded/support terminated
  234. --*/
  235. {
  236. SetLastError(ERROR_ACCESS_DENIED);
  237. return 0xFFFFFFFF;
  238. }
  239. //
  240. // private functions
  241. //
  242. PRIVATE
  243. VOID
  244. ExecuteWorkItem(
  245. IN WorkItem *pItem
  246. )
  247. /*++
  248. Routine Description:
  249. Executes a regular Work function. Runs in the NT thread pool
  250. Arguments:
  251. pItem - context information. Contains the worker function that needs to
  252. be run and the hModule to free. We need to free it.
  253. Return Value:
  254. None.
  255. --*/
  256. {
  257. HMODULE hModule = pItem->hModuleToFree;
  258. LPTHREAD_START_ROUTINE pfn = pItem->pfnCallback;
  259. LPVOID ctx = pItem->pContext;
  260. delete pItem;
  261. #ifdef DEBUG
  262. HRESULT hrDebug = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
  263. if (hrDebug == RPC_E_CHANGED_MODE)
  264. {
  265. ASSERTMSG(FALSE, "SHLWAPI Thread pool wrapper: Could not CoInitialize Appartment threaded. We got infected with an MTA!\n");
  266. }
  267. else
  268. {
  269. CoUninitialize();
  270. }
  271. #endif
  272. // Do the work now
  273. pfn(ctx);
  274. #ifdef DEBUG
  275. hrDebug = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
  276. if (hrDebug == RPC_E_CHANGED_MODE)
  277. {
  278. ASSERTMSG(FALSE, "SHLWAPI Thread pool wrapper: Could not CoInitialize Appartment threaded. The task at %x forgot to CoUninitialize or "
  279. "we got infected with an MTA!\n", pfn);
  280. }
  281. else
  282. {
  283. CoUninitialize();
  284. }
  285. #endif
  286. if (hModule)
  287. FreeLibrary(hModule);
  288. }