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.

354 lines
8.7 KiB

  1. /*
  2. * LIBRARY.C
  3. *
  4. * RSM Service : Library management
  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 <ntmsapi.h>
  15. #include "internal.h"
  16. #include "resource.h"
  17. #include "debug.h"
  18. LIBRARY *NewRSMLibrary(ULONG numDrives, ULONG numSlots, ULONG numTransports)
  19. {
  20. LIBRARY *lib;
  21. lib = (LIBRARY *)GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT, sizeof(LIBRARY));
  22. if (lib){
  23. BOOL success = FALSE;
  24. lib->state = LIBSTATE_INITIALIZING;
  25. InitializeCriticalSection(&lib->lock);
  26. InitializeListHead(&lib->allLibrariesListEntry);
  27. InitializeListHead(&lib->mediaPoolsList);
  28. InitializeListHead(&lib->freeWorkItemsList);
  29. InitializeListHead(&lib->pendingWorkItemsList);
  30. InitializeListHead(&lib->completeWorkItemsList);
  31. /*
  32. * Enqueue the new library
  33. */
  34. EnterCriticalSection(&g_globalServiceLock);
  35. InsertTailList(&g_allLibrariesList, &lib->allLibrariesListEntry);
  36. LeaveCriticalSection(&g_globalServiceLock);
  37. lib->somethingToDoEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  38. /*
  39. * Allocate arrays for drives, slots, and transports.
  40. * If the library has zero of any of these,
  41. * go ahead and allocate a zero-length array for consistency.
  42. */
  43. lib->drives = GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT, numDrives*sizeof(DRIVE));
  44. lib->slots = GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT, numSlots*sizeof(SLOT));
  45. lib->transports = GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT, numTransports*sizeof(TRANSPORT));
  46. if (lib->somethingToDoEvent &&
  47. lib->drives && lib->slots && lib->transports){
  48. lib->numDrives = numDrives;
  49. lib->numSlots = numSlots;
  50. lib->numTransports = numTransports;
  51. lib->objHeader.objType = OBJECTTYPE_LIBRARY;
  52. lib->objHeader.refCount = 1;
  53. success = TRUE;
  54. }
  55. else {
  56. ASSERT(0);
  57. }
  58. if (!success){
  59. FreeRSMLibrary(lib);
  60. lib = NULL;
  61. }
  62. }
  63. else {
  64. ASSERT(lib);
  65. }
  66. return lib;
  67. }
  68. VOID FreeRSMLibrary(LIBRARY *lib)
  69. {
  70. WORKITEM *workItem;
  71. LIST_ENTRY *listEntry;
  72. ASSERT(lib->state == LIBSTATE_HALTED);
  73. /*
  74. * Dequeue library
  75. */
  76. EnterCriticalSection(&g_globalServiceLock);
  77. ASSERT(!IsEmptyList(&lib->allLibrariesListEntry));
  78. ASSERT(!IsEmptyList(&g_allLibrariesList));
  79. RemoveEntryList(&lib->allLibrariesListEntry);
  80. InitializeListHead(&lib->allLibrariesListEntry);
  81. LeaveCriticalSection(&g_globalServiceLock);
  82. /*
  83. * Free all the workItems
  84. */
  85. while (workItem = DequeueCompleteWorkItem(lib, NULL)){
  86. DBGERR(("there shouldn't be any completed workItems left"));
  87. FreeWorkItem(workItem);
  88. }
  89. while (workItem = DequeuePendingWorkItem(lib, NULL)){
  90. DBGERR(("there shouldn't be any pending workItems left"));
  91. FreeWorkItem(workItem);
  92. }
  93. while (workItem = DequeueFreeWorkItem(lib, FALSE)){
  94. FreeWorkItem(workItem);
  95. }
  96. ASSERT(lib->numTotalWorkItems == 0);
  97. /*
  98. * Free other internal resources.
  99. * Note that this is also called from a failed NewRSMLibrary() call,
  100. * so check each resource before freeing.
  101. */
  102. if (lib->somethingToDoEvent) CloseHandle(lib->somethingToDoEvent);
  103. if (lib->drives) GlobalFree(lib->drives);
  104. if (lib->slots) GlobalFree(lib->slots);
  105. if (lib->transports) GlobalFree(lib->transports);
  106. DeleteCriticalSection(&lib->lock);
  107. GlobalFree(lib);
  108. }
  109. LIBRARY *FindLibrary(LPNTMS_GUID libId)
  110. {
  111. LIBRARY *lib = NULL;
  112. if (libId){
  113. OBJECT_HEADER *objHdr;
  114. objHdr = FindObjectInGuidHash(libId);
  115. if (objHdr){
  116. if (objHdr->objType == OBJECTTYPE_LIBRARY){
  117. lib = (LIBRARY *)objHdr;
  118. }
  119. else {
  120. DerefObject(objHdr);
  121. }
  122. }
  123. }
  124. return lib;
  125. }
  126. BOOL StartLibrary(LIBRARY *lib)
  127. {
  128. DWORD threadId;
  129. BOOL result;
  130. lib->hThread = CreateThread(NULL, 0, LibraryThread, lib, 0, &threadId);
  131. if (lib->hThread){
  132. result = TRUE;
  133. }
  134. else {
  135. ASSERT(lib->hThread);
  136. lib->state = LIBSTATE_ERROR;
  137. result = FALSE;
  138. }
  139. ASSERT(result);
  140. return result;
  141. }
  142. /*
  143. * HaltLibrary
  144. *
  145. * Take a library offline.
  146. */
  147. VOID HaltLibrary(LIBRARY *lib)
  148. {
  149. // BUGBUG - deal with multiple threads trying to halt at the same time
  150. // (e.g. can't use PulseEvent)
  151. EnterCriticalSection(&lib->lock);
  152. lib->state = LIBSTATE_OFFLINE;
  153. PulseEvent(lib->somethingToDoEvent);
  154. LeaveCriticalSection(&lib->lock);
  155. /*
  156. * The library thread may be doing some work.
  157. * Wait here until it has exited its loop.
  158. * (a thread handle gets signalled when the thread terminates).
  159. */
  160. WaitForSingleObject(lib->hThread, INFINITE);
  161. CloseHandle(lib->hThread);
  162. }
  163. DWORD __stdcall LibraryThread(void *context)
  164. {
  165. LIBRARY *lib = (LIBRARY *)context;
  166. enum libraryStates libState;
  167. ASSERT(lib);
  168. EnterCriticalSection(&lib->lock);
  169. ASSERT((lib->state == LIBSTATE_INITIALIZING) || (lib->state == LIBSTATE_OFFLINE));
  170. libState = lib->state = LIBSTATE_ONLINE;
  171. LeaveCriticalSection(&lib->lock);
  172. while (libState == LIBSTATE_ONLINE){
  173. Library_DoWork(lib);
  174. EnterCriticalSection(&lib->lock);
  175. libState = lib->state;
  176. LeaveCriticalSection(&lib->lock);
  177. WaitForSingleObject(lib->somethingToDoEvent, INFINITE);
  178. }
  179. ASSERT(libState == LIBSTATE_OFFLINE);
  180. return NO_ERROR;
  181. }
  182. VOID Library_DoWork(LIBRARY *lib)
  183. {
  184. WORKITEM *workItem;
  185. while (workItem = DequeuePendingWorkItem(lib, NULL)){
  186. BOOL complete;
  187. /*
  188. * Service the work item.
  189. * The workItem is 'complete' if we are done with it,
  190. * regardless of whether or not there was an error.
  191. */
  192. complete = ServiceOneWorkItem(lib, workItem);
  193. if (complete){
  194. /*
  195. * All done.
  196. * Put the workItem in the complete queue and signal
  197. * the originating thread.
  198. */
  199. EnqueueCompleteWorkItem(lib, workItem);
  200. }
  201. }
  202. }
  203. HRESULT DeleteLibrary(LIBRARY *lib)
  204. {
  205. HRESULT result;
  206. EnterCriticalSection(&lib->lock);
  207. /*
  208. * Take the library offline.
  209. */
  210. lib->state = LIBSTATE_OFFLINE;
  211. // BUGBUG FINISH - move any media to the offline library
  212. // BUGBUG FINISH - delete all media pools, etc.
  213. // BUGBUG FINISH - wait for all workItems, opReqs, etc to complete
  214. ASSERT(0);
  215. result = ERROR_CALL_NOT_IMPLEMENTED; // BUGBUG ?
  216. /*
  217. * Mark the library as deleted.
  218. * This will cause it not to get any new references.
  219. */
  220. ASSERT(!lib->objHeader.isDeleted);
  221. lib->objHeader.isDeleted = TRUE;
  222. /*
  223. * This dereference will cause the library's refcount to eventually go
  224. * to zero, upon which it will get deleted. We can still use our pointer
  225. * though because the caller added a refcount to get his lib pointer.
  226. */
  227. DerefObject(lib);
  228. LeaveCriticalSection(&lib->lock);
  229. return result;
  230. }
  231. SLOT *FindLibrarySlot(LIBRARY *lib, LPNTMS_GUID slotId)
  232. {
  233. SLOT *slot = NULL;
  234. if (slotId){
  235. ULONG i;
  236. EnterCriticalSection(&lib->lock);
  237. for (i = 0; i < lib->numSlots; i++){
  238. SLOT *thisSlot = &lib->slots[i];
  239. if (RtlEqualMemory(&thisSlot->objHeader.guid, slotId, sizeof(NTMS_GUID))){
  240. /*
  241. * Found the slot. Reference it since we're returning a pointer to it.
  242. */
  243. ASSERT(thisSlot->slotIndex == i);
  244. slot = thisSlot;
  245. RefObject(slot);
  246. break;
  247. }
  248. }
  249. LeaveCriticalSection(&lib->lock);
  250. }
  251. return slot;
  252. }
  253. HRESULT StopCleanerInjection(LIBRARY *lib, LPNTMS_GUID lpInjectOperation)
  254. {
  255. HRESULT result;
  256. // BUGBUG FINISH
  257. ASSERT(0);
  258. result = ERROR_CALL_NOT_IMPLEMENTED;
  259. return result;
  260. }
  261. HRESULT StopCleanerEjection(LIBRARY *lib, LPNTMS_GUID lpEjectOperation)
  262. {
  263. HRESULT result;
  264. // BUGBUG FINISH
  265. ASSERT(0);
  266. result = ERROR_CALL_NOT_IMPLEMENTED;
  267. return result;
  268. }