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.

390 lines
12 KiB

  1. /*
  2. * WORKITEM.C
  3. *
  4. * RSM Service : Library work items
  5. *
  6. * Author: ErvinP
  7. *
  8. * (c) 2001 Microsoft Corporation
  9. *
  10. */
  11. #include <windows.h>
  12. #include <stdlib.h>
  13. #include <wtypes.h>
  14. #include <objbase.h>
  15. #include <ntmsapi.h>
  16. #include "internal.h"
  17. #include "resource.h"
  18. #include "debug.h"
  19. WORKITEM *NewWorkItem(LIBRARY *lib)
  20. {
  21. WORKITEM *newWorkItem;
  22. newWorkItem = GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT, sizeof(WORKITEM));
  23. if (newWorkItem){
  24. newWorkItem->state = WORKITEMSTATE_NONE;
  25. InitializeListHead(&newWorkItem->libListEntry);
  26. InitializeListHead(&newWorkItem->workGroupListEntry);
  27. newWorkItem->workItemCompleteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  28. if (newWorkItem->workItemCompleteEvent){
  29. EnterCriticalSection(&lib->lock);
  30. lib->numTotalWorkItems++;
  31. newWorkItem->owningLib = lib;
  32. LeaveCriticalSection(&lib->lock);
  33. }
  34. else {
  35. GlobalFree(newWorkItem);
  36. newWorkItem = NULL;
  37. }
  38. }
  39. ASSERT(newWorkItem);
  40. return newWorkItem;
  41. }
  42. VOID FreeWorkItem(WORKITEM *workItem)
  43. {
  44. EnterCriticalSection(&workItem->owningLib->lock);
  45. ASSERT(IsEmptyList(&workItem->libListEntry));
  46. ASSERT(IsEmptyList(&workItem->workGroupListEntry));
  47. ASSERT(lib->numTotalWorkItems > 0);
  48. workItem->owningLib->numTotalWorkItems--;
  49. LeaveCriticalSection(&workItem->owningLib->lock);
  50. CloseHandle(workItem->workItemCompleteEvent);
  51. GlobalFree(workItem);
  52. }
  53. VOID EnqueueFreeWorkItem(LIBRARY *lib, WORKITEM *workItem)
  54. {
  55. ASSERT(workItem->owningLib == lib);
  56. workItem->state = WORKITEMSTATE_FREE;
  57. EnterCriticalSection(&lib->lock);
  58. InsertTailList(&lib->freeWorkItemsList, &workItem->libListEntry);
  59. LeaveCriticalSection(&lib->lock);
  60. }
  61. WORKITEM *DequeueFreeWorkItem(LIBRARY *lib, BOOL allocOrYieldIfNeeded)
  62. {
  63. WORKITEM *workItem;
  64. EnterCriticalSection(&lib->lock);
  65. if (IsListEmpty(&lib->freeWorkItemsList)){
  66. if (allocOrYieldIfNeeded){
  67. /*
  68. * No free workItems immediately available.
  69. * If possible, try allocating a new one.
  70. * Otherwise, go do some work and maybe that'll free some up.
  71. */
  72. if (lib->numTotalWorkItems < MAX_LIBRARY_WORKITEMS){
  73. workItem = NewWorkItem(lib);
  74. }
  75. else {
  76. /*
  77. * Give the library thread a chance to free up some workItems.
  78. */
  79. LeaveCriticalSection(&lib->lock);
  80. Sleep(10);
  81. EnterCriticalSection(&lib->lock);
  82. if (IsListEmpty(&lib->freeWorkItemsList)){
  83. workItem = NULL;
  84. }
  85. else {
  86. LIST_ENTRY *listEntry = RemoveHeadList(&lib->freeWorkItemsList);
  87. workItem = CONTAINING_RECORD(listEntry, WORKITEM, libListEntry);
  88. InitializeListHead(&workItem->libListEntry);
  89. }
  90. }
  91. }
  92. else {
  93. workItem = NULL;
  94. }
  95. }
  96. else {
  97. LIST_ENTRY *listEntry = RemoveHeadList(&lib->freeWorkItemsList);
  98. workItem = CONTAINING_RECORD(listEntry, WORKITEM, libListEntry);
  99. InitializeListHead(&workItem->libListEntry);
  100. }
  101. if (workItem){
  102. workItem->state = WORKITEMSTATE_STAGING;
  103. }
  104. LeaveCriticalSection(&lib->lock);
  105. return workItem;
  106. }
  107. VOID EnqueuePendingWorkItem(LIBRARY *lib, WORKITEM *workItem)
  108. {
  109. workItem->state = WORKITEMSTATE_PENDING;
  110. /*
  111. * Make sure workItemCompleteEvent is reset to non-signalled.
  112. */
  113. ResetEvent(workItem->workItemCompleteEvent);
  114. /*
  115. * Create a unique identifier for this workItem,
  116. * which can be used to enumerate and cancel it.
  117. */
  118. CoCreateGuid(&workItem->currentOp.requestGuid);
  119. EnterCriticalSection(&lib->lock);
  120. InsertTailList(&lib->pendingWorkItemsList, &workItem->libListEntry);
  121. LeaveCriticalSection(&lib->lock);
  122. /*
  123. * Wake up the library thread so it can process this workItem.
  124. */
  125. PulseEvent(lib->somethingToDoEvent);
  126. }
  127. WORKITEM *DequeuePendingWorkItem(LIBRARY *lib, WORKITEM *specificWorkItem)
  128. {
  129. WORKITEM *workItem;
  130. EnterCriticalSection(&lib->lock);
  131. if (specificWorkItem){
  132. ASSERT(!IsListEmpty(&lib->pendingWorkItemsList));
  133. ASSERT(!IsListEmpty(&specificWorkItem->libListEntry));
  134. RemoveEntryList(&specificWorkItem->libListEntry);
  135. InitializeListHead(&specificWorkItem->libListEntry);
  136. workItem = specificWorkItem;
  137. }
  138. else {
  139. if (IsListEmpty(&lib->pendingWorkItemsList)){
  140. workItem = NULL;
  141. }
  142. else {
  143. LIST_ENTRY *listEntry = RemoveHeadList(&lib->pendingWorkItemsList);
  144. workItem = CONTAINING_RECORD(listEntry, WORKITEM, libListEntry);
  145. InitializeListHead(&workItem->libListEntry);
  146. }
  147. }
  148. LeaveCriticalSection(&lib->lock);
  149. return workItem;
  150. }
  151. WORKITEM *DequeuePendingWorkItemByGuid(LIBRARY *lib, LPNTMS_GUID lpRequestId)
  152. {
  153. WORKITEM *workItem = NULL;
  154. LIST_ENTRY *listEntry;
  155. EnterCriticalSection(&lib->lock);
  156. listEntry = &lib->pendingWorkItemsList;
  157. while ((listEntry = listEntry->Flink) != &lib->pendingWorkItemsList){
  158. WORKITEM *thisWorkItem = CONTAINING_RECORD(listEntry, WORKITEM, libListEntry);
  159. if (RtlEqualMemory(&workItem->currentOp.requestGuid, lpRequestId, sizeof(NTMS_GUID))){
  160. workItem = thisWorkItem;
  161. RemoveEntryList(&workItem->libListEntry);
  162. InitializeListHead(&workItem->libListEntry);
  163. break;
  164. }
  165. }
  166. LeaveCriticalSection(&lib->lock);
  167. return workItem;
  168. }
  169. VOID EnqueueCompleteWorkItem(LIBRARY *lib, WORKITEM *workItem)
  170. {
  171. EnterCriticalSection(&lib->lock);
  172. /*
  173. * Put the workItem in the complete queue and signal its complete event
  174. * to wake up the thread that originally queued this event.
  175. */
  176. workItem->state = WORKITEMSTATE_COMPLETE;
  177. InsertTailList(&lib->completeWorkItemsList, &workItem->libListEntry);
  178. PulseEvent(workItem->workItemCompleteEvent);
  179. /*
  180. * If the workItem is a member of a workGroup, decrement
  181. * the count in the workGroup. If the entire workGroup is complete,
  182. * signal the workGroup's complete event.
  183. */
  184. if (workItem->workGroup){
  185. EnterCriticalSection(&workItem->workGroup->lock);
  186. ASSERT(workItem->workGroup->numPendingWorkItems > 0);
  187. ASSERT(workItem->workGroup->numPendingWorkItems <= workItem->workGroup->numTotalWorkItems);
  188. workItem->workGroup->numPendingWorkItems--;
  189. if (workItem->workGroup->numPendingWorkItems == 0){
  190. PulseEvent(workItem->workGroup->allWorkItemsCompleteEvent);
  191. }
  192. LeaveCriticalSection(&workItem->workGroup->lock);
  193. }
  194. LeaveCriticalSection(&lib->lock);
  195. }
  196. WORKITEM *DequeueCompleteWorkItem(LIBRARY *lib, WORKITEM *specificWorkItem)
  197. {
  198. WORKITEM *workItem;
  199. EnterCriticalSection(&lib->lock);
  200. if (specificWorkItem){
  201. ASSERT(!IsListEmpty(&lib->completeWorkItemsList));
  202. ASSERT(!IsListEmpty(&specificWorkItem->libListEntry));
  203. RemoveEntryList(&specificWorkItem->libListEntry);
  204. InitializeListHead(&specificWorkItem->libListEntry);
  205. workItem = specificWorkItem;
  206. }
  207. else {
  208. if (IsListEmpty(&lib->completeWorkItemsList)){
  209. workItem = NULL;
  210. }
  211. else {
  212. LIST_ENTRY *listEntry = RemoveHeadList(&lib->completeWorkItemsList);
  213. workItem = CONTAINING_RECORD(listEntry, WORKITEM, libListEntry);
  214. InitializeListHead(&workItem->libListEntry);
  215. }
  216. }
  217. LeaveCriticalSection(&lib->lock);
  218. return workItem;
  219. }
  220. /*
  221. * FlushWorkItem
  222. *
  223. * Dereference any objects pointed to by the workItem
  224. * and zero out the current op.
  225. */
  226. VOID FlushWorkItem(WORKITEM *workItem)
  227. {
  228. if (workItem->currentOp.drive) DerefObject(workItem->currentOp.drive);
  229. if (workItem->currentOp.physMedia) DerefObject(workItem->currentOp.physMedia);
  230. if (workItem->currentOp.mediaPartition) DerefObject(workItem->currentOp.mediaPartition);
  231. RtlZeroMemory(&workItem->currentOp, sizeof(workItem->currentOp));
  232. }
  233. VOID BuildSingleMountWorkItem( WORKITEM *workItem,
  234. DRIVE *drive OPTIONAL,
  235. OBJECT_HEADER *mediaOrPartObj,
  236. ULONG dwOptions,
  237. int dwPriority)
  238. {
  239. RtlZeroMemory(&workItem->currentOp, sizeof(workItem->currentOp));
  240. workItem->currentOp.opcode = NTMS_LM_MOUNT;
  241. workItem->currentOp.options = dwOptions;
  242. workItem->currentOp.resultStatus = ERROR_IO_PENDING;
  243. workItem->currentOp.drive = drive;
  244. switch (mediaOrPartObj->objType){
  245. case OBJECTTYPE_PHYSICALMEDIA:
  246. workItem->currentOp.physMedia = (PHYSICAL_MEDIA *)mediaOrPartObj;
  247. break;
  248. case OBJECTTYPE_MEDIAPARTITION:
  249. workItem->currentOp.mediaPartition = (MEDIA_PARTITION *)mediaOrPartObj;
  250. break;
  251. default:
  252. ASSERT(0);
  253. break;
  254. }
  255. /*
  256. * Reference every object that we're pointing this workItem to.
  257. */
  258. if (drive) RefObject(drive);
  259. RefObject(mediaOrPartObj);
  260. }
  261. VOID BuildSingleDismountWorkItem( WORKITEM *workItem,
  262. OBJECT_HEADER *mediaOrPartObj,
  263. DWORD dwOptions)
  264. {
  265. RtlZeroMemory(&workItem->currentOp, sizeof(workItem->currentOp));
  266. workItem->currentOp.opcode = NTMS_LM_DISMOUNT;
  267. workItem->currentOp.options = dwOptions;
  268. workItem->currentOp.resultStatus = ERROR_IO_PENDING;
  269. switch (mediaOrPartObj->objType){
  270. case OBJECTTYPE_PHYSICALMEDIA:
  271. workItem->currentOp.physMedia = (PHYSICAL_MEDIA *)mediaOrPartObj;
  272. break;
  273. case OBJECTTYPE_MEDIAPARTITION:
  274. workItem->currentOp.mediaPartition = (MEDIA_PARTITION *)mediaOrPartObj;
  275. break;
  276. default:
  277. ASSERT(0);
  278. break;
  279. }
  280. /*
  281. * Reference every object that we're pointing this workItem to.
  282. */
  283. RefObject(mediaOrPartObj);
  284. }
  285. VOID BuildInjectWorkItem( WORKITEM *workItem,
  286. LPNTMS_GUID lpInjectOperation,
  287. ULONG dwAction)
  288. {
  289. RtlZeroMemory(&workItem->currentOp, sizeof(workItem->currentOp));
  290. workItem->currentOp.opcode = NTMS_LM_INJECT;
  291. workItem->currentOp.options = dwAction;
  292. workItem->currentOp.resultStatus = ERROR_IO_PENDING;
  293. workItem->currentOp.guidArg = *lpInjectOperation;
  294. }
  295. VOID BuildEjectWorkItem( WORKITEM *workItem,
  296. PHYSICAL_MEDIA *physMedia,
  297. LPNTMS_GUID lpEjectOperation,
  298. ULONG dwAction)
  299. {
  300. RtlZeroMemory(&workItem->currentOp, sizeof(workItem->currentOp));
  301. workItem->currentOp.opcode = NTMS_LM_EJECT;
  302. workItem->currentOp.options = dwAction;
  303. workItem->currentOp.physMedia = physMedia;
  304. workItem->currentOp.resultStatus = ERROR_IO_PENDING;
  305. workItem->currentOp.guidArg = *lpEjectOperation;
  306. /*
  307. * Reference every object that we point the workItem to.
  308. */
  309. RefObject(physMedia);
  310. }