/* * LIBRARY.C * * RSM Service : Library management * * Author: ErvinP * * (c) 2001 Microsoft Corporation * */ #include #include #include #include #include "internal.h" #include "resource.h" #include "debug.h" LIBRARY *NewRSMLibrary(ULONG numDrives, ULONG numSlots, ULONG numTransports) { LIBRARY *lib; lib = (LIBRARY *)GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT, sizeof(LIBRARY)); if (lib){ BOOL success = FALSE; lib->state = LIBSTATE_INITIALIZING; InitializeCriticalSection(&lib->lock); InitializeListHead(&lib->allLibrariesListEntry); InitializeListHead(&lib->mediaPoolsList); InitializeListHead(&lib->freeWorkItemsList); InitializeListHead(&lib->pendingWorkItemsList); InitializeListHead(&lib->completeWorkItemsList); /* * Enqueue the new library */ EnterCriticalSection(&g_globalServiceLock); InsertTailList(&g_allLibrariesList, &lib->allLibrariesListEntry); LeaveCriticalSection(&g_globalServiceLock); lib->somethingToDoEvent = CreateEvent(NULL, FALSE, FALSE, NULL); /* * Allocate arrays for drives, slots, and transports. * If the library has zero of any of these, * go ahead and allocate a zero-length array for consistency. */ lib->drives = GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT, numDrives*sizeof(DRIVE)); lib->slots = GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT, numSlots*sizeof(SLOT)); lib->transports = GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT, numTransports*sizeof(TRANSPORT)); if (lib->somethingToDoEvent && lib->drives && lib->slots && lib->transports){ lib->numDrives = numDrives; lib->numSlots = numSlots; lib->numTransports = numTransports; lib->objHeader.objType = OBJECTTYPE_LIBRARY; lib->objHeader.refCount = 1; success = TRUE; } else { ASSERT(0); } if (!success){ FreeRSMLibrary(lib); lib = NULL; } } else { ASSERT(lib); } return lib; } VOID FreeRSMLibrary(LIBRARY *lib) { WORKITEM *workItem; LIST_ENTRY *listEntry; ASSERT(lib->state == LIBSTATE_HALTED); /* * Dequeue library */ EnterCriticalSection(&g_globalServiceLock); ASSERT(!IsEmptyList(&lib->allLibrariesListEntry)); ASSERT(!IsEmptyList(&g_allLibrariesList)); RemoveEntryList(&lib->allLibrariesListEntry); InitializeListHead(&lib->allLibrariesListEntry); LeaveCriticalSection(&g_globalServiceLock); /* * Free all the workItems */ while (workItem = DequeueCompleteWorkItem(lib, NULL)){ DBGERR(("there shouldn't be any completed workItems left")); FreeWorkItem(workItem); } while (workItem = DequeuePendingWorkItem(lib, NULL)){ DBGERR(("there shouldn't be any pending workItems left")); FreeWorkItem(workItem); } while (workItem = DequeueFreeWorkItem(lib, FALSE)){ FreeWorkItem(workItem); } ASSERT(lib->numTotalWorkItems == 0); /* * Free other internal resources. * Note that this is also called from a failed NewRSMLibrary() call, * so check each resource before freeing. */ if (lib->somethingToDoEvent) CloseHandle(lib->somethingToDoEvent); if (lib->drives) GlobalFree(lib->drives); if (lib->slots) GlobalFree(lib->slots); if (lib->transports) GlobalFree(lib->transports); DeleteCriticalSection(&lib->lock); GlobalFree(lib); } LIBRARY *FindLibrary(LPNTMS_GUID libId) { LIBRARY *lib = NULL; if (libId){ OBJECT_HEADER *objHdr; objHdr = FindObjectInGuidHash(libId); if (objHdr){ if (objHdr->objType == OBJECTTYPE_LIBRARY){ lib = (LIBRARY *)objHdr; } else { DerefObject(objHdr); } } } return lib; } BOOL StartLibrary(LIBRARY *lib) { DWORD threadId; BOOL result; lib->hThread = CreateThread(NULL, 0, LibraryThread, lib, 0, &threadId); if (lib->hThread){ result = TRUE; } else { ASSERT(lib->hThread); lib->state = LIBSTATE_ERROR; result = FALSE; } ASSERT(result); return result; } /* * HaltLibrary * * Take a library offline. */ VOID HaltLibrary(LIBRARY *lib) { // BUGBUG - deal with multiple threads trying to halt at the same time // (e.g. can't use PulseEvent) EnterCriticalSection(&lib->lock); lib->state = LIBSTATE_OFFLINE; PulseEvent(lib->somethingToDoEvent); LeaveCriticalSection(&lib->lock); /* * The library thread may be doing some work. * Wait here until it has exited its loop. * (a thread handle gets signalled when the thread terminates). */ WaitForSingleObject(lib->hThread, INFINITE); CloseHandle(lib->hThread); } DWORD __stdcall LibraryThread(void *context) { LIBRARY *lib = (LIBRARY *)context; enum libraryStates libState; ASSERT(lib); EnterCriticalSection(&lib->lock); ASSERT((lib->state == LIBSTATE_INITIALIZING) || (lib->state == LIBSTATE_OFFLINE)); libState = lib->state = LIBSTATE_ONLINE; LeaveCriticalSection(&lib->lock); while (libState == LIBSTATE_ONLINE){ Library_DoWork(lib); EnterCriticalSection(&lib->lock); libState = lib->state; LeaveCriticalSection(&lib->lock); WaitForSingleObject(lib->somethingToDoEvent, INFINITE); } ASSERT(libState == LIBSTATE_OFFLINE); return NO_ERROR; } VOID Library_DoWork(LIBRARY *lib) { WORKITEM *workItem; while (workItem = DequeuePendingWorkItem(lib, NULL)){ BOOL complete; /* * Service the work item. * The workItem is 'complete' if we are done with it, * regardless of whether or not there was an error. */ complete = ServiceOneWorkItem(lib, workItem); if (complete){ /* * All done. * Put the workItem in the complete queue and signal * the originating thread. */ EnqueueCompleteWorkItem(lib, workItem); } } } HRESULT DeleteLibrary(LIBRARY *lib) { HRESULT result; EnterCriticalSection(&lib->lock); /* * Take the library offline. */ lib->state = LIBSTATE_OFFLINE; // BUGBUG FINISH - move any media to the offline library // BUGBUG FINISH - delete all media pools, etc. // BUGBUG FINISH - wait for all workItems, opReqs, etc to complete ASSERT(0); result = ERROR_CALL_NOT_IMPLEMENTED; // BUGBUG ? /* * Mark the library as deleted. * This will cause it not to get any new references. */ ASSERT(!lib->objHeader.isDeleted); lib->objHeader.isDeleted = TRUE; /* * This dereference will cause the library's refcount to eventually go * to zero, upon which it will get deleted. We can still use our pointer * though because the caller added a refcount to get his lib pointer. */ DerefObject(lib); LeaveCriticalSection(&lib->lock); return result; } SLOT *FindLibrarySlot(LIBRARY *lib, LPNTMS_GUID slotId) { SLOT *slot = NULL; if (slotId){ ULONG i; EnterCriticalSection(&lib->lock); for (i = 0; i < lib->numSlots; i++){ SLOT *thisSlot = &lib->slots[i]; if (RtlEqualMemory(&thisSlot->objHeader.guid, slotId, sizeof(NTMS_GUID))){ /* * Found the slot. Reference it since we're returning a pointer to it. */ ASSERT(thisSlot->slotIndex == i); slot = thisSlot; RefObject(slot); break; } } LeaveCriticalSection(&lib->lock); } return slot; } HRESULT StopCleanerInjection(LIBRARY *lib, LPNTMS_GUID lpInjectOperation) { HRESULT result; // BUGBUG FINISH ASSERT(0); result = ERROR_CALL_NOT_IMPLEMENTED; return result; } HRESULT StopCleanerEjection(LIBRARY *lib, LPNTMS_GUID lpEjectOperation) { HRESULT result; // BUGBUG FINISH ASSERT(0); result = ERROR_CALL_NOT_IMPLEMENTED; return result; }