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

/*
* WORKITEM.C
*
* RSM Service : Library work items
*
* Author: ErvinP
*
* (c) 2001 Microsoft Corporation
*
*/
#include <windows.h>
#include <stdlib.h>
#include <wtypes.h>
#include <objbase.h>
#include <ntmsapi.h>
#include "internal.h"
#include "resource.h"
#include "debug.h"
WORKITEM *NewWorkItem(LIBRARY *lib)
{
WORKITEM *newWorkItem;
newWorkItem = GlobalAlloc(GMEM_FIXED|GMEM_ZEROINIT, sizeof(WORKITEM));
if (newWorkItem){
newWorkItem->state = WORKITEMSTATE_NONE;
InitializeListHead(&newWorkItem->libListEntry);
InitializeListHead(&newWorkItem->workGroupListEntry);
newWorkItem->workItemCompleteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (newWorkItem->workItemCompleteEvent){
EnterCriticalSection(&lib->lock);
lib->numTotalWorkItems++;
newWorkItem->owningLib = lib;
LeaveCriticalSection(&lib->lock);
}
else {
GlobalFree(newWorkItem);
newWorkItem = NULL;
}
}
ASSERT(newWorkItem);
return newWorkItem;
}
VOID FreeWorkItem(WORKITEM *workItem)
{
EnterCriticalSection(&workItem->owningLib->lock);
ASSERT(IsEmptyList(&workItem->libListEntry));
ASSERT(IsEmptyList(&workItem->workGroupListEntry));
ASSERT(lib->numTotalWorkItems > 0);
workItem->owningLib->numTotalWorkItems--;
LeaveCriticalSection(&workItem->owningLib->lock);
CloseHandle(workItem->workItemCompleteEvent);
GlobalFree(workItem);
}
VOID EnqueueFreeWorkItem(LIBRARY *lib, WORKITEM *workItem)
{
ASSERT(workItem->owningLib == lib);
workItem->state = WORKITEMSTATE_FREE;
EnterCriticalSection(&lib->lock);
InsertTailList(&lib->freeWorkItemsList, &workItem->libListEntry);
LeaveCriticalSection(&lib->lock);
}
WORKITEM *DequeueFreeWorkItem(LIBRARY *lib, BOOL allocOrYieldIfNeeded)
{
WORKITEM *workItem;
EnterCriticalSection(&lib->lock);
if (IsListEmpty(&lib->freeWorkItemsList)){
if (allocOrYieldIfNeeded){
/*
* No free workItems immediately available.
* If possible, try allocating a new one.
* Otherwise, go do some work and maybe that'll free some up.
*/
if (lib->numTotalWorkItems < MAX_LIBRARY_WORKITEMS){
workItem = NewWorkItem(lib);
}
else {
/*
* Give the library thread a chance to free up some workItems.
*/
LeaveCriticalSection(&lib->lock);
Sleep(10);
EnterCriticalSection(&lib->lock);
if (IsListEmpty(&lib->freeWorkItemsList)){
workItem = NULL;
}
else {
LIST_ENTRY *listEntry = RemoveHeadList(&lib->freeWorkItemsList);
workItem = CONTAINING_RECORD(listEntry, WORKITEM, libListEntry);
InitializeListHead(&workItem->libListEntry);
}
}
}
else {
workItem = NULL;
}
}
else {
LIST_ENTRY *listEntry = RemoveHeadList(&lib->freeWorkItemsList);
workItem = CONTAINING_RECORD(listEntry, WORKITEM, libListEntry);
InitializeListHead(&workItem->libListEntry);
}
if (workItem){
workItem->state = WORKITEMSTATE_STAGING;
}
LeaveCriticalSection(&lib->lock);
return workItem;
}
VOID EnqueuePendingWorkItem(LIBRARY *lib, WORKITEM *workItem)
{
workItem->state = WORKITEMSTATE_PENDING;
/*
* Make sure workItemCompleteEvent is reset to non-signalled.
*/
ResetEvent(workItem->workItemCompleteEvent);
/*
* Create a unique identifier for this workItem,
* which can be used to enumerate and cancel it.
*/
CoCreateGuid(&workItem->currentOp.requestGuid);
EnterCriticalSection(&lib->lock);
InsertTailList(&lib->pendingWorkItemsList, &workItem->libListEntry);
LeaveCriticalSection(&lib->lock);
/*
* Wake up the library thread so it can process this workItem.
*/
PulseEvent(lib->somethingToDoEvent);
}
WORKITEM *DequeuePendingWorkItem(LIBRARY *lib, WORKITEM *specificWorkItem)
{
WORKITEM *workItem;
EnterCriticalSection(&lib->lock);
if (specificWorkItem){
ASSERT(!IsListEmpty(&lib->pendingWorkItemsList));
ASSERT(!IsListEmpty(&specificWorkItem->libListEntry));
RemoveEntryList(&specificWorkItem->libListEntry);
InitializeListHead(&specificWorkItem->libListEntry);
workItem = specificWorkItem;
}
else {
if (IsListEmpty(&lib->pendingWorkItemsList)){
workItem = NULL;
}
else {
LIST_ENTRY *listEntry = RemoveHeadList(&lib->pendingWorkItemsList);
workItem = CONTAINING_RECORD(listEntry, WORKITEM, libListEntry);
InitializeListHead(&workItem->libListEntry);
}
}
LeaveCriticalSection(&lib->lock);
return workItem;
}
WORKITEM *DequeuePendingWorkItemByGuid(LIBRARY *lib, LPNTMS_GUID lpRequestId)
{
WORKITEM *workItem = NULL;
LIST_ENTRY *listEntry;
EnterCriticalSection(&lib->lock);
listEntry = &lib->pendingWorkItemsList;
while ((listEntry = listEntry->Flink) != &lib->pendingWorkItemsList){
WORKITEM *thisWorkItem = CONTAINING_RECORD(listEntry, WORKITEM, libListEntry);
if (RtlEqualMemory(&workItem->currentOp.requestGuid, lpRequestId, sizeof(NTMS_GUID))){
workItem = thisWorkItem;
RemoveEntryList(&workItem->libListEntry);
InitializeListHead(&workItem->libListEntry);
break;
}
}
LeaveCriticalSection(&lib->lock);
return workItem;
}
VOID EnqueueCompleteWorkItem(LIBRARY *lib, WORKITEM *workItem)
{
EnterCriticalSection(&lib->lock);
/*
* Put the workItem in the complete queue and signal its complete event
* to wake up the thread that originally queued this event.
*/
workItem->state = WORKITEMSTATE_COMPLETE;
InsertTailList(&lib->completeWorkItemsList, &workItem->libListEntry);
PulseEvent(workItem->workItemCompleteEvent);
/*
* If the workItem is a member of a workGroup, decrement
* the count in the workGroup. If the entire workGroup is complete,
* signal the workGroup's complete event.
*/
if (workItem->workGroup){
EnterCriticalSection(&workItem->workGroup->lock);
ASSERT(workItem->workGroup->numPendingWorkItems > 0);
ASSERT(workItem->workGroup->numPendingWorkItems <= workItem->workGroup->numTotalWorkItems);
workItem->workGroup->numPendingWorkItems--;
if (workItem->workGroup->numPendingWorkItems == 0){
PulseEvent(workItem->workGroup->allWorkItemsCompleteEvent);
}
LeaveCriticalSection(&workItem->workGroup->lock);
}
LeaveCriticalSection(&lib->lock);
}
WORKITEM *DequeueCompleteWorkItem(LIBRARY *lib, WORKITEM *specificWorkItem)
{
WORKITEM *workItem;
EnterCriticalSection(&lib->lock);
if (specificWorkItem){
ASSERT(!IsListEmpty(&lib->completeWorkItemsList));
ASSERT(!IsListEmpty(&specificWorkItem->libListEntry));
RemoveEntryList(&specificWorkItem->libListEntry);
InitializeListHead(&specificWorkItem->libListEntry);
workItem = specificWorkItem;
}
else {
if (IsListEmpty(&lib->completeWorkItemsList)){
workItem = NULL;
}
else {
LIST_ENTRY *listEntry = RemoveHeadList(&lib->completeWorkItemsList);
workItem = CONTAINING_RECORD(listEntry, WORKITEM, libListEntry);
InitializeListHead(&workItem->libListEntry);
}
}
LeaveCriticalSection(&lib->lock);
return workItem;
}
/*
* FlushWorkItem
*
* Dereference any objects pointed to by the workItem
* and zero out the current op.
*/
VOID FlushWorkItem(WORKITEM *workItem)
{
if (workItem->currentOp.drive) DerefObject(workItem->currentOp.drive);
if (workItem->currentOp.physMedia) DerefObject(workItem->currentOp.physMedia);
if (workItem->currentOp.mediaPartition) DerefObject(workItem->currentOp.mediaPartition);
RtlZeroMemory(&workItem->currentOp, sizeof(workItem->currentOp));
}
VOID BuildSingleMountWorkItem( WORKITEM *workItem,
DRIVE *drive OPTIONAL,
OBJECT_HEADER *mediaOrPartObj,
ULONG dwOptions,
int dwPriority)
{
RtlZeroMemory(&workItem->currentOp, sizeof(workItem->currentOp));
workItem->currentOp.opcode = NTMS_LM_MOUNT;
workItem->currentOp.options = dwOptions;
workItem->currentOp.resultStatus = ERROR_IO_PENDING;
workItem->currentOp.drive = drive;
switch (mediaOrPartObj->objType){
case OBJECTTYPE_PHYSICALMEDIA:
workItem->currentOp.physMedia = (PHYSICAL_MEDIA *)mediaOrPartObj;
break;
case OBJECTTYPE_MEDIAPARTITION:
workItem->currentOp.mediaPartition = (MEDIA_PARTITION *)mediaOrPartObj;
break;
default:
ASSERT(0);
break;
}
/*
* Reference every object that we're pointing this workItem to.
*/
if (drive) RefObject(drive);
RefObject(mediaOrPartObj);
}
VOID BuildSingleDismountWorkItem( WORKITEM *workItem,
OBJECT_HEADER *mediaOrPartObj,
DWORD dwOptions)
{
RtlZeroMemory(&workItem->currentOp, sizeof(workItem->currentOp));
workItem->currentOp.opcode = NTMS_LM_DISMOUNT;
workItem->currentOp.options = dwOptions;
workItem->currentOp.resultStatus = ERROR_IO_PENDING;
switch (mediaOrPartObj->objType){
case OBJECTTYPE_PHYSICALMEDIA:
workItem->currentOp.physMedia = (PHYSICAL_MEDIA *)mediaOrPartObj;
break;
case OBJECTTYPE_MEDIAPARTITION:
workItem->currentOp.mediaPartition = (MEDIA_PARTITION *)mediaOrPartObj;
break;
default:
ASSERT(0);
break;
}
/*
* Reference every object that we're pointing this workItem to.
*/
RefObject(mediaOrPartObj);
}
VOID BuildInjectWorkItem( WORKITEM *workItem,
LPNTMS_GUID lpInjectOperation,
ULONG dwAction)
{
RtlZeroMemory(&workItem->currentOp, sizeof(workItem->currentOp));
workItem->currentOp.opcode = NTMS_LM_INJECT;
workItem->currentOp.options = dwAction;
workItem->currentOp.resultStatus = ERROR_IO_PENDING;
workItem->currentOp.guidArg = *lpInjectOperation;
}
VOID BuildEjectWorkItem( WORKITEM *workItem,
PHYSICAL_MEDIA *physMedia,
LPNTMS_GUID lpEjectOperation,
ULONG dwAction)
{
RtlZeroMemory(&workItem->currentOp, sizeof(workItem->currentOp));
workItem->currentOp.opcode = NTMS_LM_EJECT;
workItem->currentOp.options = dwAction;
workItem->currentOp.physMedia = physMedia;
workItem->currentOp.resultStatus = ERROR_IO_PENDING;
workItem->currentOp.guidArg = *lpEjectOperation;
/*
* Reference every object that we point the workItem to.
*/
RefObject(physMedia);
}