⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 workitem.cpp

📁 pci接口芯片s5933驱动程序
💻 CPP
字号:
// WorkItem.cpp -- Routines for managing work items in S5933DK1.SYS driver

// Copyright (C) 1999 by Walter Oney

// All rights reserved



#include "stddcls.h"

#include "driver.h"



VOID OnCancel(PDEVICE_OBJECT fdo, PIRP Irp);

BOOLEAN ProcessWorkItems(PDEVICE_EXTENSION pdx);

VOID WorkerThreadProc(PDEVICE_EXTENSION pdx);



#define POLLING_INTERVAL 10		// 10 ms polling interval



///////////////////////////////////////////////////////////////////////////////



#pragma LOCKEDCODE



VOID CleanupWorkItems(PDEVICE_EXTENSION pdx, PFILE_OBJECT FileObject)

	{							// CleanupWorkItems

	PLIST_ENTRY list;

	PWORKITEM item;



	// Create an empty list that will end up containing the work items we

	// want to cancel



	LIST_ENTRY cancel;

	InitializeListHead(&cancel);



	// Acquire the workitem mutex to make sure that all active work items are

	// sitting on the queue where we can find them.



	ExAcquireFastMutex(&pdx->QueueMutex);



	// Acquire the queue spin lock to prevent interference from QueueWorkItem



	KIRQL oldirql;

	KeAcquireSpinLock(&pdx->QueueLock, &oldirql);



	// Find all work items tied to the file object being cleaned up



	for (list = pdx->WorkItems.Flink; list != &pdx->WorkItems; )

		{						// for each work item

		PLIST_ENTRY next = list;



		item = CONTAINING_RECORD(list, WORKITEM, List);

		PIRP Irp = item->Irp;

		PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);

		

		if (FileObject == stack->FileObject)

			{					// item for same file object

			IoSetCancelRoutine(Irp, NULL);

			RemoveEntryList(list);

			InsertTailList(&cancel, list);

			}					// item for same file object



		list = next;			// follow chain to next item

		}						// for each work item



	KeReleaseSpinLock(&pdx->QueueLock, oldirql);

	ExReleaseFastMutex(&pdx->QueueMutex);



	// Cancel the selected work items

	

	while (!IsListEmpty(&cancel))

		{						// cancel selected IRPs

		list = RemoveHeadList(&cancel);

		item = CONTAINING_RECORD(list, WORKITEM, List);

		PIRP Irp = item->Irp;

		ExFreePool(item);

		CompleteRequest(Irp, STATUS_CANCELLED, 0);

		}						// cancel selected IRPs

	}							// CleanupWorkItems



///////////////////////////////////////////////////////////////////////////////



#pragma PAGEDCODE



VOID InitializeWorkItem(PWORKITEM item, WORKITEM_CALLBACK callback, PVOID context, PIRP Irp)

	{							// InitializeWorkItem

	item->Irp = Irp;

	item->callback = callback;

	item->context = context;

	}							// InitializeWorkItem



///////////////////////////////////////////////////////////////////////////////



#pragma LOCKEDCODE



VOID OnCancel(PDEVICE_OBJECT fdo, PIRP Irp)

	{							// OnCancel

	KIRQL oldirql = Irp->CancelIrql;

	IoReleaseCancelSpinLock(DISPATCH_LEVEL);

	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;

	KeAcquireSpinLockAtDpcLevel(&pdx->QueueLock);



	// See if the IRP that's being cancelled is associated with a queued work item.

	// If so, remove the work item from the queue and complete the IRP. Otherwise,

	// do nothing



	PLIST_ENTRY list;

	for (list = pdx->WorkItems.Flink; list != &pdx->WorkItems; list = list->Flink)

		{						// for each queued work item

		PWORKITEM item = CONTAINING_RECORD(list, WORKITEM, List);

		if (Irp == item->Irp)

			{					// cancelling active work item

			RemoveEntryList(list); // remove from active queue

			KeReleaseSpinLock(&pdx->QueueLock, oldirql);

			ExFreePool(item);

			CompleteRequest(Irp, STATUS_CANCELLED, 0);

			return;

			}					// cancelling active work item

		}						// for each queued work item



	KeReleaseSpinLock(&pdx->QueueLock, oldirql);

	}							// OnCancel



///////////////////////////////////////////////////////////////////////////////



#pragma PAGEDCODE



BOOLEAN ProcessWorkItems(PDEVICE_EXTENSION pdx)

	{							// ProcessWorkItems

	LIST_ENTRY active;			// list of still-active items

	InitializeListHead(&active);



	// Pull each work item off the queue and examine it



	PLIST_ENTRY list;

	while ((list = ExInterlockedRemoveHeadList(&pdx->WorkItems, &pdx->QueueLock)))

		{						// for each work item

		PWORKITEM item = CONTAINING_RECORD(list, WORKITEM, List);

		PIRP Irp = item->Irp;

		IoSetCancelRoutine(Irp, NULL);	// can no longer be cancelled



		// If the IRP associated with this item is marked cancelled, what must

		// have happened is that our cancel routine got called too late to

		// remove the work item from the active queue. In that case, it's our

		// responsibility to complete it



		if (Irp->Cancel)

			{					// item was cancelled

			ExFreePool(item);

			CompleteRequest(Irp, STATUS_CANCELLED, 0);

			continue;			// with "for each work item"

			}					// item was cancelled



		// Call the callback routine for this work item. It returns TRUE if

		// the item needs to remain active. Note that, if the item got cancelled

		// in the very immediate past, we won't pick that fact up until the next

		// poll occurs.



		if ((*item->callback)(pdx, item, item->context))

			{

			InsertTailList(&active, &item->List);

			}

		else

			{					// complete the item

			ExFreePool(item);

			IoCompleteRequest(Irp, IO_NO_INCREMENT);

			}					// complete the item

		}						// for each work item



	// Requeue the active items for the next poll



	if (IsListEmpty(&active))

		return FALSE;			// halt polling loop since no more active items



	while (!IsListEmpty(&active))

		{						// repopulate work item list

		list = RemoveHeadList(&active);

		ExInterlockedInsertTailList(&pdx->WorkItems, list, &pdx->QueueLock);

		}						// repopulate work item list



	return TRUE;				// another poll needed

	}							// ProcessWorkItems



///////////////////////////////////////////////////////////////////////////////



#pragma LOCKEDCODE



NTSTATUS QueueWorkItem(PDEVICE_EXTENSION pdx, PWORKITEM item)

	{							// QueueWorkItem

	PIRP Irp = item->Irp;



	KIRQL oldirql;

	KeAcquireSpinLock(&pdx->QueueLock, &oldirql);



	// Install a cancel routine for the IRP. If we detect the Cancel flag,

	// our cancel routine may or may not have actually been called for this

	// IRP, but it won't have done anything because the work item won't have

	// been queued yet.



	IoSetCancelRoutine(Irp, OnCancel);

	if (Irp->Cancel)

		{						// IRP has already been cancelled

		IoSetCancelRoutine(Irp, NULL);

		KeReleaseSpinLock(&pdx->QueueLock, oldirql);

		return STATUS_CANCELLED;

		}						// IRP has already been cancelled



	InsertTailList(&pdx->WorkItems, &item->List);



	KeReleaseSpinLock(&pdx->QueueLock, oldirql);



	// Alert the worker thread that a new work item has arrived. Then return

	// STATUS_PENDING to indicate that the item has not yet been processed



	KeSetEvent(&pdx->evWork, EVENT_INCREMENT, FALSE);

	return STATUS_PENDING;

	}							// QueueWorkItem



///////////////////////////////////////////////////////////////////////////////



#pragma PAGEDCODE



NTSTATUS StartWorkerThread(PDEVICE_EXTENSION pdx)

	{							// StartWorkerThread

	PAGED_CODE();



	NTSTATUS status;

	HANDLE hthread;



	KeClearEvent(&pdx->evKill);



	status = PsCreateSystemThread(&hthread, THREAD_ALL_ACCESS, NULL, NULL, NULL,

		(PKSTART_ROUTINE) WorkerThreadProc, pdx);



	if (!NT_SUCCESS(status))

		return status;



	status = ObReferenceObjectByHandle(hthread, THREAD_ALL_ACCESS, NULL, KernelMode,

		(PVOID*) &pdx->thread, NULL);



	if (!NT_SUCCESS(status))

		KdPrint((DRIVERNAME " - ObReferenceObjectByHandle failed - %X\n", status));



	ZwClose(hthread);

	return status;

	}							// StartWorkerThread



///////////////////////////////////////////////////////////////////////////////



#pragma PAGEDCODE



VOID StopWorkerThread(PDEVICE_EXTENSION pdx)

	{							// StopWorkerThread

	PAGED_CODE();



	if (!pdx->thread)

		return;



	KeSetEvent(&pdx->evKill, IO_NO_INCREMENT, FALSE);



	// In Win98, we don't dare wait on the thread object (it will cause a crash)

	

	if (!win98)

		KeWaitForSingleObject(pdx->thread, Executive, KernelMode, FALSE, NULL);

	

	ObDereferenceObject(pdx->thread);

	pdx->thread = NULL;

	}							// StopWorkerThread



///////////////////////////////////////////////////////////////////////////////



#pragma PAGEDCODE



VOID WorkerThreadProc(PDEVICE_EXTENSION pdx)

	{							// WorkerThreadProc

	PAGED_CODE();



	KdPrint((DRIVERNAME " - Starting worker thread\n"));



	NTSTATUS status;



	// Event array for main loop (while waiting for work)



	PVOID mainevents[] = {

		(PVOID) &pdx->evKill,

		(PVOID) &pdx->evWork,

		};

	ASSERT(arraysize(mainevents) <= THREAD_WAIT_OBJECTS);



	// Event array for polling loop



	KTIMER timer;

	KeInitializeTimerEx(&timer, SynchronizationTimer);

	PVOID pollevents[] = {

		(PVOID) &pdx->evKill,

		(PVOID) &timer,

		};

	ASSERT(arraysize(pollevents) <= THREAD_WAIT_OBJECTS);



	// Wait for a work item to arrive or for the kill event to be set



	while (TRUE)

		{						// until told to quit

		status = KeWaitForMultipleObjects(arraysize(mainevents), mainevents,

			WaitAny, Executive, KernelMode, FALSE, NULL, NULL);

		if (!NT_SUCCESS(status))

			break;

		if (status == STATUS_WAIT_0)

			break;				// evKill has been set



		// As long as there are work items in the queue, execute a polling loop

		// in which we repeatedly execute the callback routines for each of the

		// items.



		LARGE_INTEGER duetime = {0};	// causes timer to expire immediately 1 time

		KeSetTimerEx(&timer, duetime, POLLING_INTERVAL, NULL); // start repetitive timer



		while (TRUE)

			{					// until no more work items

			status = KeWaitForMultipleObjects(arraysize(pollevents), pollevents, WaitAny, Executive,

				KernelMode, FALSE, NULL, NULL);

			if (status == STATUS_WAIT_0)

				break;			// kill event set



			KeClearEvent(&pdx->evWork);

			if (!ProcessWorkItems(pdx))

				break;			// no more items in the queue

			}					// until no more work items



		KeCancelTimer(&timer);

		}						// until told to quit



	// Purge any queued work items



	PLIST_ENTRY list;

	while ((list = ExInterlockedRemoveHeadList(&pdx->WorkItems, &pdx->QueueLock)))

		{						// purge queued items

		PWORKITEM item = CONTAINING_RECORD(list, WORKITEM, List);

		PIRP Irp = item->Irp;

		ExFreePool(item);

		CompleteRequest(Irp, STATUS_CANCELLED, 0);

		}						// purge queued items



	KdPrint((DRIVERNAME " - Worker thread exiting\n"));

	PsTerminateSystemThread(STATUS_SUCCESS);

	}							// WorkerThreadProc

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -