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

/*
* LIBRARY.C
*
* RSM Service : Library management
*
* Author: ErvinP
*
* (c) 2001 Microsoft Corporation
*
*/
#include <windows.h>
#include <stdlib.h>
#include <wtypes.h>
#include <ntmsapi.h>
#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;
}