summaryrefslogtreecommitdiff
path: root/general/cancel/sys
diff options
context:
space:
mode:
authorDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
committerDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
commit97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch)
tree46f3701832d70b420eb0fc0eb93261f9da45db3f /general/cancel/sys
parentef1905bf1e8825bb31120dfb27e0daf3154d859a (diff)
Initial publish
Diffstat (limited to 'general/cancel/sys')
-rw-r--r--general/cancel/sys/cancel.c945
-rw-r--r--general/cancel/sys/cancel.h181
-rw-r--r--general/cancel/sys/cancel.rc10
-rw-r--r--general/cancel/sys/cancel.vcxproj152
-rw-r--r--general/cancel/sys/cancel.vcxproj.Filters31
5 files changed, 1319 insertions, 0 deletions
diff --git a/general/cancel/sys/cancel.c b/general/cancel/sys/cancel.c
new file mode 100644
index 00000000..58bf72e9
--- /dev/null
+++ b/general/cancel/sys/cancel.c
@@ -0,0 +1,945 @@
+/*++
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+
+Module Name:
+
+ cancel.c
+
+Abstract: Demonstrates the use of new Cancel-Safe queue
+ APIs to perform queuing of IRPs without worrying about
+ any synchronization issues between cancel lock in the I/O
+ manager and the driver's queue lock.
+
+ This driver is written for an hypothetical data acquisition
+ device that requires polling at a regular interval.
+ The device has some settling period between two reads.
+ Upon user request the driver reads data and records the time.
+ When the next read request comes in, it checks the interval
+ to see if it's reading the device too soon. If so, it pends
+ the IRP and sleeps for while and tries again.
+
+ Upon arrival, IRPs are queued in a cancel-safe queue and a
+ semaphore is signaled. A polling thread indefinitely waits on the
+ semaphore to process queued IRPs sequentially.
+
+ This sample is adapted from the original cancel
+ sample (KB Q188276) available in MSDN.
+
+Environment:
+
+ Kernel mode
+
+--*/
+
+#include "cancel.h"
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text( INIT, DriverEntry )
+#pragma alloc_text( PAGE, CsampCreateClose)
+#pragma alloc_text( PAGE, CsampUnload)
+#pragma alloc_text( PAGE, CsampRead)
+#endif // ALLOC_PRAGMA
+
+NTSTATUS
+DriverEntry(
+ _In_ PDRIVER_OBJECT DriverObject,
+ _In_ PUNICODE_STRING RegistryPath
+ )
+/*++
+
+Routine Description:
+
+ Installable driver initialization entry point.
+ This entry point is called directly by the I/O system.
+
+Arguments:
+
+ DriverObject - pointer to the driver object
+
+ registryPath - pointer to a unicode string representing the path,
+ to driver-specific key in the registry.
+
+Return Value:
+
+ STATUS_SUCCESS if successful,
+ STATUS_UNSUCCESSFUL otherwise
+
+--*/
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ UNICODE_STRING unicodeDeviceName;
+ UNICODE_STRING unicodeDosDeviceName;
+ PDEVICE_OBJECT deviceObject;
+ PDEVICE_EXTENSION devExtension;
+ HANDLE threadHandle;
+ UNICODE_STRING sddlString;
+
+ UNREFERENCED_PARAMETER (RegistryPath);
+
+ CSAMP_KDPRINT(("DriverEntry Enter \n"));
+
+
+ (void) RtlInitUnicodeString(&unicodeDeviceName, CSAMP_DEVICE_NAME_U);
+
+ (void) RtlInitUnicodeString( &sddlString, L"D:P(A;;GA;;;SY)(A;;GA;;;BA)");
+
+ //
+ // We will create a secure deviceobject so that only processes running
+ // in admin and local system account can access the device. Refer
+ // "Security Descriptor String Format" section in the platform
+ // SDK documentation to understand the format of the sddl string.
+ // We need to do because this is a legacy driver and there is no INF
+ // involved in installing the driver. For PNP drivers, security descriptor
+ // is typically specified for the FDO in the INF file.
+ //
+
+ status = IoCreateDeviceSecure(
+ DriverObject,
+ sizeof(DEVICE_EXTENSION),
+ &unicodeDeviceName,
+ FILE_DEVICE_UNKNOWN,
+ FILE_DEVICE_SECURE_OPEN,
+ (BOOLEAN) FALSE,
+ &sddlString,
+ (LPCGUID)&GUID_DEVCLASS_CANCEL_SAMPLE,
+ &deviceObject
+ );
+ if (!NT_SUCCESS(status))
+ {
+ return status;
+ }
+
+ DbgPrint("DeviceObject %p\n", deviceObject);
+
+ //
+ // Allocate and initialize a Unicode String containing the Win32 name
+ // for our device.
+ //
+
+ (void)RtlInitUnicodeString( &unicodeDosDeviceName, CSAMP_DOS_DEVICE_NAME_U );
+
+
+ status = IoCreateSymbolicLink(
+ (PUNICODE_STRING) &unicodeDosDeviceName,
+ (PUNICODE_STRING) &unicodeDeviceName
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ IoDeleteDevice(deviceObject);
+ return status;
+ }
+
+ devExtension = deviceObject->DeviceExtension;
+
+ DriverObject->MajorFunction[IRP_MJ_CREATE]=
+ DriverObject->MajorFunction[IRP_MJ_CLOSE] = CsampCreateClose;
+ DriverObject->MajorFunction[IRP_MJ_READ] = CsampRead;
+ DriverObject->MajorFunction[IRP_MJ_CLEANUP] = CsampCleanup;
+
+ DriverObject->DriverUnload = CsampUnload;
+
+ //
+ // Set the flag signifying that we will do buffered I/O. This causes NT
+ // to allocate a buffer on a ReadFile operation which will then be copied
+ // back to the calling application by the I/O subsystem
+ //
+
+ deviceObject->Flags |= DO_BUFFERED_IO;
+
+ //
+ // This is used to serailize access to the queue.
+ //
+
+ KeInitializeSpinLock(&devExtension->QueueLock);
+
+ KeInitializeSemaphore(&devExtension->IrpQueueSemaphore, 0, MAXLONG );
+
+ //
+ // Initialize the pending Irp devicequeue
+ //
+
+ InitializeListHead( &devExtension->PendingIrpQueue );
+
+ //
+ // Initialize the cancel safe queue
+ //
+ IoCsqInitialize( &devExtension->CancelSafeQueue,
+ CsampInsertIrp,
+ CsampRemoveIrp,
+ CsampPeekNextIrp,
+ CsampAcquireLock,
+ CsampReleaseLock,
+ CsampCompleteCanceledIrp );
+ //
+ // 10 is multiplied because system time is specified in 100ns units
+ //
+
+ devExtension->PollingInterval.QuadPart = Int32x32To64(
+ CSAMP_RETRY_INTERVAL, -10);
+ //
+ // Note down system time
+ //
+
+ KeQuerySystemTime (&devExtension->LastPollTime);
+
+ //
+ // Start the polling thread.
+ //
+
+ devExtension->ThreadShouldStop = FALSE;
+
+ status = PsCreateSystemThread(&threadHandle,
+ (ACCESS_MASK)0,
+ NULL,
+ (HANDLE) 0,
+ NULL,
+ CsampPollingThread,
+ deviceObject );
+
+ if ( !NT_SUCCESS( status ))
+ {
+ IoDeleteSymbolicLink( &unicodeDosDeviceName );
+ IoDeleteDevice( deviceObject );
+ return status;
+ }
+
+ //
+ // Convert the Thread object handle into a pointer to the Thread object
+ // itself. Then close the handle.
+ //
+
+ ObReferenceObjectByHandle(threadHandle,
+ THREAD_ALL_ACCESS,
+ NULL,
+ KernelMode,
+ &devExtension->ThreadObject,
+ NULL );
+
+ ZwClose(threadHandle);
+
+ CSAMP_KDPRINT(("DriverEntry Exit = %x\n", status));
+
+ ASSERT(NT_SUCCESS(status));
+
+ return status;
+}
+
+
+_Use_decl_annotations_
+NTSTATUS
+CsampCreateClose(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+/*++
+
+Routine Description:
+
+ Process the Create and close IRPs sent to this device.
+
+Arguments:
+
+ DeviceObject - pointer to a device object.
+
+ Irp - pointer to an I/O Request Packet.
+
+Return Value:
+
+ NT Status code
+
+--*/
+{
+ PIO_STACK_LOCATION irpStack;
+ NTSTATUS status = STATUS_SUCCESS;
+ PFILE_CONTEXT fileContext;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ PAGED_CODE ();
+
+ CSAMP_KDPRINT(("CsampCreateClose Enter\n"));
+
+ irpStack = IoGetCurrentIrpStackLocation(Irp);
+
+ ASSERT(irpStack->FileObject != NULL);
+
+ switch(irpStack->MajorFunction)
+ {
+ case IRP_MJ_CREATE:
+
+ //
+ // The dispatch routine for IRP_MJ_CREATE is called when a
+ // file object associated with the device is created.
+ // This is typically because of a call to CreateFile() in
+ // a user-mode program or because a another driver is
+ // layering itself over a this driver. A driver is
+ // required to supply a dispatch routine for IRP_MJ_CREATE.
+ //
+ fileContext = ExAllocatePoolWithQuotaTag(NonPagedPool,
+ sizeof(FILE_CONTEXT),
+ TAG);
+
+ if (NULL == fileContext) {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ IoInitializeRemoveLock(&fileContext->FileRundownLock, TAG, 0, 0);
+
+ //
+ // Make sure nobody is using the FsContext scratch area.
+ //
+ ASSERT(irpStack->FileObject->FsContext == NULL);
+
+ //
+ // Store the context in the FileObject's scratch area.
+ //
+ irpStack->FileObject->FsContext = (PVOID) fileContext;
+
+ CSAMP_KDPRINT(("IRP_MJ_CREATE\n"));
+ break;
+
+ case IRP_MJ_CLOSE:
+ //
+ // The IRP_MJ_CLOSE dispatch routine is called when a file object
+ // opened on the driver is being removed from the system; that is,
+ // all file object handles have been closed and the reference count
+ // of the file object is down to 0.
+ //
+ fileContext = irpStack->FileObject->FsContext;
+
+ ExFreePoolWithTag(fileContext, TAG);
+
+ CSAMP_KDPRINT(("IRP_MJ_CLOSE\n"));
+ break;
+
+ default:
+ CSAMP_KDPRINT((" Invalid CreateClose Parameter\n"));
+ status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+
+ //
+ // Save Status for return and complete Irp
+ //
+ Irp->IoStatus.Status = status;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ CSAMP_KDPRINT((" CsampCreateClose Exit = %x\n", status));
+
+ return status;
+}
+
+
+_Use_decl_annotations_
+NTSTATUS
+CsampRead(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+ /*++
+ Routine Description:
+
+ Read disptach routine
+
+ Arguments:
+
+ DeviceObject - pointer to a device object.
+ Irp - pointer to current Irp
+
+ Return Value:
+
+ NT status code.
+
+--*/
+{
+ NTSTATUS status;
+ PDEVICE_EXTENSION devExtension;
+ PIO_STACK_LOCATION irpStack;
+ LARGE_INTEGER currentTime;
+ PFILE_CONTEXT fileContext;
+ PVOID readBuffer;
+ BOOLEAN inCriticalRegion;
+
+ PAGED_CODE();
+
+ CSAMP_KDPRINT(("CsampRead Enter:0x%p\n", Irp));
+
+ devExtension = DeviceObject->DeviceExtension;
+ inCriticalRegion = FALSE;
+
+ irpStack = IoGetCurrentIrpStackLocation(Irp);
+ ASSERT(irpStack->FileObject != NULL);
+
+ fileContext = irpStack->FileObject->FsContext;
+
+ status = IoAcquireRemoveLock(&fileContext->FileRundownLock, Irp);
+ if (!NT_SUCCESS(status)) {
+ //
+ // Lock is in a removed state. That means we have already received
+ // cleaned up request for this handle.
+ //
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return status;
+ }
+
+ //
+ // First make sure there is enough room.
+ //
+ if (irpStack->Parameters.Read.Length < sizeof(INPUT_DATA))
+ {
+ Irp->IoStatus.Status = status = STATUS_BUFFER_TOO_SMALL;
+ Irp->IoStatus.Information = 0;
+ IoReleaseRemoveLock(&fileContext->FileRundownLock, Irp);
+ IoCompleteRequest (Irp, IO_NO_INCREMENT);
+ return status;
+ }
+
+ //
+ // FOR TESTING:
+ // Initialize the data to mod 2 of some random number.
+ // With this value you can control the number of times the
+ // Irp will be queued before completion. Check
+ // CsampPollDevice routine to know how this works.
+ //
+
+ KeQuerySystemTime(&currentTime);
+
+ readBuffer = Irp->AssociatedIrp.SystemBuffer;
+
+ *((PULONG)readBuffer) = ((currentTime.LowPart/13)%2);
+
+ //
+ // To avoid the thread from being suspended after it has queued the IRP and
+ // before it signalled the semaphore, we will enter critical region.
+ //
+ ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
+ KeEnterCriticalRegion();
+ inCriticalRegion = TRUE;
+
+ //
+ // Queue the IRP and return STATUS_PENDING after signalling the
+ // polling thread.
+ // Note: IoCsqInsertIrp marks the IRP pending.
+ //
+ IoCsqInsertIrp(&devExtension->CancelSafeQueue, Irp, NULL);
+
+ //
+ // Do not touch the IRP once it has been queued because another thread
+ // could remove the IRP and complete it before this one gets to run.
+ //
+
+ //
+ // A semaphore remains signaled as long as its count is greater than
+ // zero, and non-signaled when the count is zero. Following function
+ // increments the semaphore count by 1.
+ //
+
+ KeReleaseSemaphore(&devExtension->IrpQueueSemaphore,
+ 0,// No priority boost
+ 1,// Increment semaphore by 1
+ FALSE );// No WaitForXxx after this call
+ if (inCriticalRegion == TRUE) {
+ KeLeaveCriticalRegion();
+ }
+ //
+ // We don't hold the lock for IRP that's pending in the list because this
+ // lock is meant to rundown currently dispatching threads when the cleanup
+ // is handled.
+ //
+ IoReleaseRemoveLock(&fileContext->FileRundownLock, Irp);
+
+ return STATUS_PENDING;
+}
+
+VOID
+CsampPollingThread(
+ _In_ PVOID Context
+ )
+/*++
+
+Routine Description:
+
+ This is the main thread that removes IRP from the queue
+ and peforms I/O on it.
+
+Arguments:
+
+ Context -- pointer to the device object
+
+--*/
+{
+ PDEVICE_OBJECT DeviceObject = Context;
+ PDEVICE_EXTENSION DevExtension = DeviceObject->DeviceExtension;
+ PIRP Irp;
+ NTSTATUS Status;
+
+ KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY );
+
+ //
+ // Now enter the main IRP-processing loop
+ //
+ for(;;)
+ {
+ //
+ // Wait indefinitely for an IRP to appear in the work queue or for
+ // the Unload routine to stop the thread. Every successful return
+ // from the wait decrements the semaphore count by 1.
+ //
+ KeWaitForSingleObject(&DevExtension->IrpQueueSemaphore,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL );
+
+ //
+ // See if thread was awakened because driver is unloading itself...
+ //
+
+ if ( DevExtension->ThreadShouldStop ) {
+ PsTerminateSystemThread( STATUS_SUCCESS );
+ }
+
+ //
+ // Remove a pending IRP from the queue.
+ //
+ Irp = IoCsqRemoveNextIrp(&DevExtension->CancelSafeQueue, NULL);
+
+ if (!Irp) {
+ CSAMP_KDPRINT(("Oops, a queued irp got cancelled\n"));
+ continue; // go back to waiting
+ }
+
+ for(;;) {
+ //
+ // Perform I/O
+ //
+ Status = CsampPollDevice(DeviceObject, Irp);
+ if (Status == STATUS_PENDING) {
+
+ //
+ // Device is not ready, so sleep for a while and try again.
+ //
+ KeDelayExecutionThread(KernelMode, FALSE,
+ &DevExtension->PollingInterval);
+
+ } else {
+
+ //
+ // I/O is successful, so complete the Irp.
+ //
+ Irp->IoStatus.Status = Status;
+ IoCompleteRequest (Irp, IO_NO_INCREMENT);
+ break;
+ }
+
+ }
+ //
+ // Go back to the top of the loop to see if there's another request waiting.
+ //
+ } // end of while-loop
+}
+
+_Use_decl_annotations_
+NTSTATUS
+CsampPollDevice(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ Polls for data
+
+Arguments:
+
+ DeviceObject -- pointer to the device object
+ Irp -- pointer to the requesing Irp
+
+
+Return Value:
+
+ STATUS_SUCCESS -- if the poll succeeded,
+ STATUS_TIMEOUT -- if the poll failed (timeout),
+ or the checksum was incorrect
+ STATUS_PENDING -- if polled too soon
+
+--*/
+{
+ PINPUT_DATA pInput;
+
+ UNREFERENCED_PARAMETER( DeviceObject );
+
+ pInput = (PINPUT_DATA)Irp->AssociatedIrp.SystemBuffer;
+
+#ifdef REAL
+
+ RtlZeroMemory( pInput, sizeof(INPUT_DATA) );
+
+ //
+ // If currenttime is less than the lasttime polled plus
+ // minimum time required for the device to settle
+ // then don't poll and return STATUS_PENDING
+ //
+
+ KeQuerySystemTime(&currentTime);
+ if (currentTime->QuadPart < (TimeBetweenPolls +
+ devExtension->LastPollTime.QuadPart))
+ {
+ return STATUS_PENDING;
+ }
+
+ //
+ // Read/Write to the port here.
+ // Fill the INPUT structure
+ //
+
+ //
+ // Note down the current time as the last polled time
+ //
+
+ KeQuerySystemTime(&devExtension->LastPollTime);
+
+
+ return STATUS_SUCCESS;
+#else
+
+ //
+ // With this conditional statement
+ // you can control the number of times the
+ // i/o should be retried before completing.
+ //
+
+ if (pInput->Data-- <= 0)
+ {
+ Irp->IoStatus.Information = sizeof(INPUT_DATA);
+ return STATUS_SUCCESS;
+ }
+ return STATUS_PENDING;
+
+ #endif
+
+}
+
+_Use_decl_annotations_
+NTSTATUS
+CsampCleanup(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+)
+/*++
+
+Routine Description:
+ This dispatch routine is called when the last handle (in
+ the whole system) to a file object is closed. In other words, the open
+ handle count for the file object goes to 0. A driver that holds pending
+ IRPs internally must implement a routine for IRP_MJ_CLEANUP. When the
+ routine is called, the driver should cancel all the pending IRPs that
+ belong to the file object identified by the IRP_MJ_CLEANUP call. In other
+ words, it should cancel all the IRPs that have the same file-object pointer
+ as the one supplied in the current I/O stack location of the IRP for the
+ IRP_MJ_CLEANUP call. Of course, IRPs belonging to other file objects should
+ not be canceled. Also, if an outstanding IRP is completed immediately, the
+ driver does not have to cancel it.
+
+Arguments:
+
+ DeviceObject -- pointer to the device object
+ Irp -- pointer to the requesing Irp
+
+Return Value:
+
+ STATUS_SUCCESS -- if the poll succeeded,
+--*/
+{
+
+ PDEVICE_EXTENSION devExtension;
+ PIRP pendingIrp;
+ PIO_STACK_LOCATION irpStack;
+ PFILE_CONTEXT fileContext;
+ NTSTATUS status;
+
+ CSAMP_KDPRINT(("CsampCleanupIrp enter\n"));
+
+ devExtension = DeviceObject->DeviceExtension;
+
+ irpStack = IoGetCurrentIrpStackLocation(Irp);
+ ASSERT(irpStack->FileObject != NULL);
+
+ fileContext = irpStack->FileObject->FsContext;
+
+ //
+ // This acquire cannot fail because you cannot get more than one
+ // cleanup for the same handle.
+ //
+ status = IoAcquireRemoveLock(&fileContext->FileRundownLock, Irp);
+ ASSERT(NT_SUCCESS(status));
+
+ //
+ // Wait for all the threads that are currently dispatching to exit and
+ // prevent any threads dispatching I/O on the same handle beyond this point.
+ //
+ IoReleaseRemoveLockAndWait(&fileContext->FileRundownLock, Irp);
+
+ pendingIrp = IoCsqRemoveNextIrp(&devExtension->CancelSafeQueue,
+ irpStack->FileObject);
+
+ while(pendingIrp)
+ {
+ //
+ // Cancel the IRP
+ //
+ pendingIrp->IoStatus.Information = 0;
+ pendingIrp->IoStatus.Status = STATUS_CANCELLED;
+ CSAMP_KDPRINT(("Cleanup cancelled irp\n"));
+ IoCompleteRequest(pendingIrp, IO_NO_INCREMENT);
+
+ pendingIrp = IoCsqRemoveNextIrp(&devExtension->CancelSafeQueue,
+ irpStack->FileObject);
+ }
+
+ //
+ // Finally complete the cleanup IRP
+ //
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ CSAMP_KDPRINT(("CsampCleanupIrp exit\n"));
+
+ return STATUS_SUCCESS;
+
+}
+
+VOID
+CsampUnload(
+ _In_ PDRIVER_OBJECT DriverObject
+ )
+/*++
+
+Routine Description:
+
+ Free all the allocated resources, etc.
+
+Arguments:
+
+ DriverObject - pointer to a driver object.
+
+Return Value:
+
+ VOID
+--*/
+{
+ PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject;
+ UNICODE_STRING uniWin32NameString;
+ PDEVICE_EXTENSION devExtension = deviceObject->DeviceExtension;
+
+ PAGED_CODE();
+
+ CSAMP_KDPRINT(("CsampUnload Enter\n"));
+
+ //
+ // Set the Stop flag
+ //
+ devExtension->ThreadShouldStop = TRUE;
+
+ //
+ // Make sure the thread wakes up
+ //
+#pragma prefast(suppress: __WARNING_ERROR, "Passing TRUE as last parameter of KeReleaseSemaphore is just a hint that a wait is next.")
+ KeReleaseSemaphore(&devExtension->IrpQueueSemaphore,
+ 0, // No priority boost
+ 1, // Increment semaphore by 1
+ TRUE );// WaitForXxx after this call
+
+ //
+ // Wait for the thread to terminate
+ //
+ KeWaitForSingleObject(devExtension->ThreadObject,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL );
+
+ ObDereferenceObject(devExtension->ThreadObject);
+
+ //
+ // Create counted string version of our Win32 device name.
+ //
+
+ RtlInitUnicodeString( &uniWin32NameString, CSAMP_DOS_DEVICE_NAME_U );
+
+ IoDeleteSymbolicLink( &uniWin32NameString );
+
+ IoDeleteDevice( deviceObject );
+
+ CSAMP_KDPRINT(("CsampUnload Exit\n"));
+ return;
+}
+
+VOID CsampInsertIrp (
+ _In_ PIO_CSQ Csq,
+ _In_ PIRP Irp
+ )
+{
+ PDEVICE_EXTENSION devExtension;
+
+ devExtension = CONTAINING_RECORD(Csq,
+ DEVICE_EXTENSION, CancelSafeQueue);
+
+ InsertTailList(&devExtension->PendingIrpQueue,
+ &Irp->Tail.Overlay.ListEntry);
+}
+
+VOID CsampRemoveIrp(
+ _In_ PIO_CSQ Csq,
+ _In_ PIRP Irp
+ )
+{
+ UNREFERENCED_PARAMETER(Csq);
+
+ RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
+}
+
+
+PIRP CsampPeekNextIrp(
+ _In_ PIO_CSQ Csq,
+ _In_ PIRP Irp,
+ _In_ PVOID PeekContext
+ )
+{
+ PDEVICE_EXTENSION devExtension;
+ PIRP nextIrp = NULL;
+ PLIST_ENTRY nextEntry;
+ PLIST_ENTRY listHead;
+ PIO_STACK_LOCATION irpStack;
+
+ devExtension = CONTAINING_RECORD(Csq,
+ DEVICE_EXTENSION, CancelSafeQueue);
+
+ listHead = &devExtension->PendingIrpQueue;
+
+ //
+ // If the IRP is NULL, we will start peeking from the listhead, else
+ // we will start from that IRP onwards. This is done under the
+ // assumption that new IRPs are always inserted at the tail.
+ //
+
+ if (Irp == NULL) {
+ nextEntry = listHead->Flink;
+ } else {
+ nextEntry = Irp->Tail.Overlay.ListEntry.Flink;
+ }
+
+ while(nextEntry != listHead) {
+
+ nextIrp = CONTAINING_RECORD(nextEntry, IRP, Tail.Overlay.ListEntry);
+
+ irpStack = IoGetCurrentIrpStackLocation(nextIrp);
+
+ //
+ // If context is present, continue until you find a matching one.
+ // Else you break out as you got next one.
+ //
+
+ if (PeekContext) {
+ if (irpStack->FileObject == (PFILE_OBJECT) PeekContext) {
+ break;
+ }
+ } else {
+ break;
+ }
+ nextIrp = NULL;
+ nextEntry = nextEntry->Flink;
+ }
+
+ return nextIrp;
+
+}
+
+//
+// CsampAcquireLock modifies the execution level of the current processor.
+//
+// KeAcquireSpinLock raises the execution level to Dispatch Level and stores
+// the current execution level in the Irql parameter to be restored at a later
+// time. KeAcqurieSpinLock also requires us to be running at no higher than
+// Dispatch level when it is called.
+//
+// The annotations reflect these changes and requirments.
+//
+
+_IRQL_raises_(DISPATCH_LEVEL)
+_IRQL_requires_max_(DISPATCH_LEVEL)
+_Acquires_lock_(CONTAINING_RECORD(Csq,DEVICE_EXTENSION, CancelSafeQueue)->QueueLock)
+VOID CsampAcquireLock(
+ _In_ PIO_CSQ Csq,
+ _Out_ _At_(*Irql, _Post_ _IRQL_saves_) PKIRQL Irql
+ )
+{
+ PDEVICE_EXTENSION devExtension;
+
+ devExtension = CONTAINING_RECORD(Csq,
+ DEVICE_EXTENSION, CancelSafeQueue);
+ //
+ // Suppressing because the address below csq is valid since it's
+ // part of DEVICE_EXTENSION structure.
+ //
+#pragma prefast(suppress: __WARNING_BUFFER_UNDERFLOW, "Underflow using expression 'devExtension->QueueLock'")
+ KeAcquireSpinLock(&devExtension->QueueLock, Irql);
+}
+
+//
+// CsampReleaseLock modifies the execution level of the current processor.
+//
+// KeReleaseSpinLock assumes we already hold the spin lock and are therefore
+// running at Dispatch level. It will use the Irql parameter saved in a
+// previous call to KeAcquireSpinLock to return the thread back to it's original
+// execution level.
+//
+// The annotations reflect these changes and requirments.
+//
+
+_IRQL_requires_(DISPATCH_LEVEL)
+_Releases_lock_(CONTAINING_RECORD(Csq,DEVICE_EXTENSION, CancelSafeQueue)->QueueLock)
+VOID CsampReleaseLock(
+ _In_ PIO_CSQ Csq,
+ _In_ _IRQL_restores_ KIRQL Irql
+ )
+{
+ PDEVICE_EXTENSION devExtension;
+
+ devExtension = CONTAINING_RECORD(Csq,
+ DEVICE_EXTENSION, CancelSafeQueue);
+ //
+ // Suppressing because the address below csq is valid since it's
+ // part of DEVICE_EXTENSION structure.
+ //
+#pragma prefast(suppress: __WARNING_BUFFER_UNDERFLOW, "Underflow using expression 'devExtension->QueueLock'")
+ KeReleaseSpinLock(&devExtension->QueueLock, Irql);
+}
+
+VOID CsampCompleteCanceledIrp(
+ _In_ PIO_CSQ pCsq,
+ _In_ PIRP Irp
+ )
+{
+
+ UNREFERENCED_PARAMETER(pCsq);
+
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ Irp->IoStatus.Information = 0;
+ CSAMP_KDPRINT(("cancelled irp\n"));
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+}
+
diff --git a/general/cancel/sys/cancel.h b/general/cancel/sys/cancel.h
new file mode 100644
index 00000000..4f63d2af
--- /dev/null
+++ b/general/cancel/sys/cancel.h
@@ -0,0 +1,181 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ cancel.h
+
+Abstract:
+
+Environment:
+
+ Kernel mode only.
+
+
+Revision History:
+
+--*/
+
+#include <initguid.h>
+
+//
+// Since this driver is a legacy driver and gets installed as a service
+// (without an INF file), we will define a class guid for use in
+// IoCreateDeviceSecure function. This would allow the system to store
+// Security, DeviceType, Characteristics and Exclusivity information of the
+// deviceobject in the registery under
+// HKLM\SYSTEM\CurrentControlSet\Control\Class\ClassGUID\Properties.
+// This information can be overrided by an Administrators giving them the ability
+// to control access to the device beyond what is initially allowed
+// by the driver developer.
+//
+
+// {5D006E1A-2631-466c-B8A0-32FD498E4424} - generated using guidgen.exe
+DEFINE_GUID (GUID_DEVCLASS_CANCEL_SAMPLE,
+ 0x5d006e1a, 0x2631, 0x466c, 0xb8, 0xa0, 0x32, 0xfd, 0x49, 0x8e, 0x44, 0x24);
+
+//
+// GUID definition are required to be outside of header inclusion pragma to avoid
+// error during precompiled headers.
+//
+
+#ifndef __CANCEL_H
+#define __CANCEL_H
+
+//
+// GUID definition are required to be outside of header inclusion pragma to
+// avoid error during precompiled headers.
+//
+#include <ntddk.h>
+#include <wdmsec.h> // for IoCreateDeviceSecure
+#include <dontuse.h>
+
+// Debugging macros
+
+#if DBG
+#define CSAMP_KDPRINT(_x_) \
+ DbgPrint("CANCEL.SYS: ");\
+ DbgPrint _x_;
+#else
+
+#define CSAMP_KDPRINT(_x_)
+
+#endif
+
+#define CSAMP_DEVICE_NAME_U L"\\Device\\CANCELSAMP"
+#define CSAMP_DOS_DEVICE_NAME_U L"\\DosDevices\\CancelSamp"
+#define CSAMP_RETRY_INTERVAL 500*1000 //500 ms
+#define TAG (ULONG)'MASC'
+
+typedef struct _INPUT_DATA{
+
+ ULONG Data; //device data is stored here
+
+} INPUT_DATA, *PINPUT_DATA;
+
+typedef struct _DEVICE_EXTENSION{
+
+ BOOLEAN ThreadShouldStop;
+
+ // Irps waiting to be processed are queued here
+ LIST_ENTRY PendingIrpQueue;
+
+ // SpinLock to protect access to the queue
+ KSPIN_LOCK QueueLock;
+
+ IO_CSQ CancelSafeQueue;
+
+ // Time at which the device was last polled
+ LARGE_INTEGER LastPollTime;
+
+ // Polling interval (retry interval)
+ LARGE_INTEGER PollingInterval;
+
+ KSEMAPHORE IrpQueueSemaphore;
+
+ PETHREAD ThreadObject;
+} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
+
+typedef struct _FILE_CONTEXT{
+ //
+ // Lock to rundown threads that are dispatching I/Os on a file handle
+ // while the cleanup for that handle is in progress.
+ //
+ IO_REMOVE_LOCK FileRundownLock;
+} FILE_CONTEXT, *PFILE_CONTEXT;
+
+DRIVER_INITIALIZE DriverEntry;
+
+_Dispatch_type_(IRP_MJ_CREATE)
+_Dispatch_type_(IRP_MJ_CLOSE)
+DRIVER_DISPATCH CsampCreateClose;
+
+_Dispatch_type_(IRP_MJ_CLEANUP)
+DRIVER_DISPATCH CsampCleanup;
+
+_Dispatch_type_(IRP_MJ_READ)
+DRIVER_DISPATCH CsampRead;
+
+DRIVER_DISPATCH CsampPollDevice;
+
+DRIVER_UNLOAD CsampUnload;
+
+KSTART_ROUTINE CsampPollingThread;
+
+VOID
+CsampPollingThread(
+ _In_ PVOID Context
+ );
+
+VOID
+CsampInsertIrp (
+ _In_ PIO_CSQ Csq,
+ _In_ PIRP Irp
+ );
+
+VOID
+CsampRemoveIrp(
+ _In_ PIO_CSQ Csq,
+ _In_ PIRP Irp
+ );
+
+PIRP
+CsampPeekNextIrp(
+ _In_ PIO_CSQ Csq,
+ _In_ PIRP Irp,
+ _In_ PVOID PeekContext
+ );
+
+_IRQL_raises_(DISPATCH_LEVEL)
+_IRQL_requires_max_(DISPATCH_LEVEL)
+_Acquires_lock_(CONTAINING_RECORD(Csq,DEVICE_EXTENSION, CancelSafeQueue)->QueueLock)
+VOID
+CsampAcquireLock(
+ _In_ PIO_CSQ Csq,
+ _Out_ _At_(*Irql, _Post_ _IRQL_saves_) PKIRQL Irql
+ );
+
+_IRQL_requires_(DISPATCH_LEVEL)
+_Releases_lock_(CONTAINING_RECORD(Csq,DEVICE_EXTENSION, CancelSafeQueue)->QueueLock)
+VOID
+CsampReleaseLock(
+ _In_ PIO_CSQ Csq,
+ _In_ _IRQL_restores_ KIRQL Irql
+ );
+
+VOID
+CsampCompleteCanceledIrp(
+ _In_ PIO_CSQ pCsq,
+ _In_ PIRP Irp
+ );
+
+#endif
+
+
+
diff --git a/general/cancel/sys/cancel.rc b/general/cancel/sys/cancel.rc
new file mode 100644
index 00000000..2bd08155
--- /dev/null
+++ b/general/cancel/sys/cancel.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "Sample Cancel Driver"
+#define VER_INTERNALNAME_STR "cancel.sys"
+
+#include "common.ver"
diff --git a/general/cancel/sys/cancel.vcxproj b/general/cancel/sys/cancel.vcxproj
new file mode 100644
index 00000000..6227a13d
--- /dev/null
+++ b/general/cancel/sys/cancel.vcxproj
@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{3003AE7E-3AA2-458A-B349-64E4A921061B}</SampleGuid>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType>WDM</DriverType>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>cancel</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>cancel</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>cancel</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>cancel</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\wdmsec.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\wdmsec.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\wdmsec.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\wdmsec.lib</AdditionalDependencies>
+ </Link>
+ <ClCompile>
+ <TreatWarningAsError>true</TreatWarningAsError>
+ <WarningLevel>Level4</WarningLevel>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="cancel.c" />
+ <ResourceCompile Include="cancel.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/general/cancel/sys/cancel.vcxproj.Filters b/general/cancel/sys/cancel.vcxproj.Filters
new file mode 100644
index 00000000..bdf2e015
--- /dev/null
+++ b/general/cancel/sys/cancel.vcxproj.Filters
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{6BC3B1BF-F875-48B1-9E49-07CB6AE2FED1}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{646CC6F7-384E-44CB-B55D-2CF7427232F2}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{A3ADD9F6-E06C-4974-AD86-F265759792E2}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{4BC75BD1-ADE8-40F5-91AF-0002A740EF8C}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="cancel.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="cancel.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file