summaryrefslogtreecommitdiff
path: root/general/cancel
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
parentef1905bf1e8825bb31120dfb27e0daf3154d859a (diff)
Initial publish
Diffstat (limited to 'general/cancel')
-rw-r--r--general/cancel/ReadMe.md27
-rw-r--r--general/cancel/cancel.sln59
-rw-r--r--general/cancel/exe/canclapp.vcxproj180
-rw-r--r--general/cancel/exe/canclapp.vcxproj.Filters25
-rw-r--r--general/cancel/exe/install.c480
-rw-r--r--general/cancel/exe/testapp.c333
-rw-r--r--general/cancel/exe/testapp.h14
-rw-r--r--general/cancel/startio/cancel.c965
-rw-r--r--general/cancel/startio/cancel.h166
-rw-r--r--general/cancel/startio/cancel.rc10
-rw-r--r--general/cancel/startio/cancel.vcxproj152
-rw-r--r--general/cancel/startio/cancel.vcxproj.Filters31
-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
17 files changed, 3761 insertions, 0 deletions
diff --git a/general/cancel/ReadMe.md b/general/cancel/ReadMe.md
new file mode 100644
index 00000000..5baab9b9
--- /dev/null
+++ b/general/cancel/ReadMe.md
@@ -0,0 +1,27 @@
+Cancel-Safe IRP Queue Sample
+============================
+
+This sample demonstrates the use of the cancel-safe queue routines [**IoCsqInitialize**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff549054), [**IoCsqInsertIrp**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff549066), [**IoCsqRemoveIrp**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff549070), [**IoCsqRemoveNextIrp**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff549072). These routines were introduced in Windows XP for queuing IRPs in the driver's internal device queue. By using these routines, driver developers do not have to worry about IRP cancellation race conditions. A common problem with cancellation of IRPs in a driver is synchronization between the cancel lock or the InterlockedExchange in the I/O Manager with the driver's queue lock. The **IoCsq*Xxx*** routines abstract the cancel logic while allowing the driver to implement the queue and associated synchronization.
+
+The sample is accompanied by a simple multithreaded Win32 console application to stress-test the driver's cancel and cleanup routines.
+
+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 successive reads. On a user request, the driver reads data and records the time. When the next read request comes in, the driver checks the interval to see if it's reading the device too soon. If so, it pends the IRP and sleeps for a while, and then tries again. On arrival, IRPs are queued in a cancel-safe queue and a semaphore is signaled. A polling thread that waits indefinitely on the semaphore wakes up to the signal and processes queued IRPs sequentially.
+
+The building and installation instructions given here apply to Windows 2000 and later versions of Windows.
+
+This sample driver is not a Plug and Play driver. This is a minimal driver meant to demonstrate a feature of the operating system. Neither this driver nor its sample programs are intended for use in a production environment. Instead, they are intended for educational purposes and as a skeleton driver.
+
+Look in the Startio directory for another version of the sample driver that shows how to use cancel-safe IRP queues to implement I/O queuing functionality similar to the [**IoStartPacket**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff550370) and [**IoStartNextPacket**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff550358) routines. The same test application works with this driver as well.
+
+For more information, see [Cancel-Safe IRP Queues](http://msdn.microsoft.com/en-us/library/windows/hardware/ff540755).
+
+
+Run the sample
+--------------
+
+To test this driver, run Testapp.exe, which is a simple Win32 multithreaded console application. The driver will automatically load and start. When you exit the application, the driver will stop and be removed.
+
+`Usage: testapp <NumberOfThreads>`
+
+**Note**  The `NumberOfThreads` command-line parameter is limited to a maximum of 10 threads; the default value if no parameter is specified is 1. The main thread waits for user input. If you press Q, the application exits gracefully; otherwise, it exits the process abruptly and forces all the threads to be terminated and all pending I/O operations to be canceled. Other threads perform I/O asynchronously in a loop. After every overlapped read, the thread goes into an alertable sleep and wakes as soon as the completion routine runs, which occurs when the driver completes the read IRP. You should run multiple instances of the application to stress test the driver.
+
diff --git a/general/cancel/cancel.sln b/general/cancel/cancel.sln
new file mode 100644
index 00000000..a9836742
--- /dev/null
+++ b/general/cancel/cancel.sln
@@ -0,0 +1,59 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0
+MinimumVisualStudioVersion = 12.0
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{DBD7C2B7-C00F-4FFE-84D4-B05886013873}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{0B6A483D-D5F5-4F95-96E7-281FD7EA600F}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Startio", "Startio", "{234DCAD4-F351-4964-9C3B-0B59C944B70D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cancel", "sys\cancel.vcxproj", "{3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "canclapp", "exe\canclapp.vcxproj", "{C8925B47-FB65-4E3E-89E4-2B45E3C10509}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cancel", "startio\cancel.vcxproj", "{1392C861-BA6F-4423-8C33-A8C771BAF473}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}.Debug|Win32.ActiveCfg = Debug|Win32
+ {3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}.Debug|Win32.Build.0 = Debug|Win32
+ {3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}.Release|Win32.ActiveCfg = Release|Win32
+ {3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}.Release|Win32.Build.0 = Release|Win32
+ {3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}.Debug|x64.ActiveCfg = Debug|x64
+ {3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}.Debug|x64.Build.0 = Debug|x64
+ {3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}.Release|x64.ActiveCfg = Release|x64
+ {3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}.Release|x64.Build.0 = Release|x64
+ {C8925B47-FB65-4E3E-89E4-2B45E3C10509}.Debug|Win32.ActiveCfg = Debug|Win32
+ {C8925B47-FB65-4E3E-89E4-2B45E3C10509}.Debug|Win32.Build.0 = Debug|Win32
+ {C8925B47-FB65-4E3E-89E4-2B45E3C10509}.Release|Win32.ActiveCfg = Release|Win32
+ {C8925B47-FB65-4E3E-89E4-2B45E3C10509}.Release|Win32.Build.0 = Release|Win32
+ {C8925B47-FB65-4E3E-89E4-2B45E3C10509}.Debug|x64.ActiveCfg = Debug|x64
+ {C8925B47-FB65-4E3E-89E4-2B45E3C10509}.Debug|x64.Build.0 = Debug|x64
+ {C8925B47-FB65-4E3E-89E4-2B45E3C10509}.Release|x64.ActiveCfg = Release|x64
+ {C8925B47-FB65-4E3E-89E4-2B45E3C10509}.Release|x64.Build.0 = Release|x64
+ {1392C861-BA6F-4423-8C33-A8C771BAF473}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1392C861-BA6F-4423-8C33-A8C771BAF473}.Debug|Win32.Build.0 = Debug|Win32
+ {1392C861-BA6F-4423-8C33-A8C771BAF473}.Release|Win32.ActiveCfg = Release|Win32
+ {1392C861-BA6F-4423-8C33-A8C771BAF473}.Release|Win32.Build.0 = Release|Win32
+ {1392C861-BA6F-4423-8C33-A8C771BAF473}.Debug|x64.ActiveCfg = Debug|x64
+ {1392C861-BA6F-4423-8C33-A8C771BAF473}.Debug|x64.Build.0 = Debug|x64
+ {1392C861-BA6F-4423-8C33-A8C771BAF473}.Release|x64.ActiveCfg = Release|x64
+ {1392C861-BA6F-4423-8C33-A8C771BAF473}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {3363DCA3-7873-4ECB-BA98-F243C2E8FDA0} = {DBD7C2B7-C00F-4FFE-84D4-B05886013873}
+ {C8925B47-FB65-4E3E-89E4-2B45E3C10509} = {0B6A483D-D5F5-4F95-96E7-281FD7EA600F}
+ {1392C861-BA6F-4423-8C33-A8C771BAF473} = {234DCAD4-F351-4964-9C3B-0B59C944B70D}
+ EndGlobalSection
+EndGlobal
diff --git a/general/cancel/exe/canclapp.vcxproj b/general/cancel/exe/canclapp.vcxproj
new file mode 100644
index 00000000..63333b9c
--- /dev/null
+++ b/general/cancel/exe/canclapp.vcxproj
@@ -0,0 +1,180 @@
+<?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>{C8925B47-FB65-4E3E-89E4-2B45E3C10509}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{1EB28B67-703E-42CB-AEEF-4871909ACBE4}</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 />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Desktop</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>Application</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>canclapp</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>canclapp</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>canclapp</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>canclapp</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='false'">MultiThreaded</RuntimeLibrary>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='true'">MultiThreadedDebug</RuntimeLibrary>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <BaseAddress>0x0400000</BaseAddress>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='false'">MultiThreaded</RuntimeLibrary>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='true'">MultiThreadedDebug</RuntimeLibrary>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <BaseAddress>0x0400000</BaseAddress>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='false'">MultiThreaded</RuntimeLibrary>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='true'">MultiThreadedDebug</RuntimeLibrary>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <BaseAddress>0x0400000</BaseAddress>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <ClCompile>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='false'">MultiThreaded</RuntimeLibrary>
+ <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='true'">MultiThreadedDebug</RuntimeLibrary>
+ <ExceptionHandling>
+ </ExceptionHandling>
+ </ClCompile>
+ <Midl>
+ <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories>
+ </Midl>
+ <Link>
+ <BaseAddress>0x0400000</BaseAddress>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="install.c" />
+ <ClCompile Include="testapp.c" />
+ </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/exe/canclapp.vcxproj.Filters b/general/cancel/exe/canclapp.vcxproj.Filters
new file mode 100644
index 00000000..fa02af34
--- /dev/null
+++ b/general/cancel/exe/canclapp.vcxproj.Filters
@@ -0,0 +1,25 @@
+<?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>{8E80D4A1-56AB-4705-840F-3971E3C35CC4}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{F05A42DC-3C1C-4B0B-BB8A-980D8BDD8C12}</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>{DB77EDC2-6072-41D9-B58F-42B9EECC5702}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="install.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="testapp.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/general/cancel/exe/install.c b/general/cancel/exe/install.c
new file mode 100644
index 00000000..f19ff558
--- /dev/null
+++ b/general/cancel/exe/install.c
@@ -0,0 +1,480 @@
+/*++
+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:
+
+ install.c
+
+Abstract:
+
+ Win32 routines to dynamically load and unload a Windows NT kernel-mode
+ driver using the Service Control Manager APIs.
+
+Environment:
+
+ User mode only
+
+--*/
+
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "testapp.h"
+
+
+BOOLEAN
+InstallDriver(
+ _In_ SC_HANDLE SchSCManager,
+ _In_ LPCTSTR DriverName,
+ _In_ LPCTSTR ServiceExe
+ );
+
+
+BOOLEAN
+RemoveDriver(
+ _In_ SC_HANDLE SchSCManager,
+ _In_ LPCTSTR DriverName
+ );
+
+BOOLEAN
+StartDriver(
+ _In_ SC_HANDLE SchSCManager,
+ _In_ LPCTSTR DriverName
+ );
+
+BOOLEAN
+StopDriver(
+ _In_ SC_HANDLE SchSCManager,
+ _In_ LPCTSTR DriverName
+ );
+
+BOOLEAN
+InstallDriver(
+ _In_ SC_HANDLE SchSCManager,
+ _In_ LPCTSTR DriverName,
+ _In_ LPCTSTR ServiceExe
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ SC_HANDLE schService;
+ DWORD err;
+
+ //
+ // NOTE: This creates an entry for a standalone driver. If this
+ // is modified for use with a driver that requires a Tag,
+ // Group, and/or Dependencies, it may be necessary to
+ // query the registry for existing driver information
+ // (in order to determine a unique Tag, etc.).
+ //
+
+ //
+ // Create a new a service object.
+ //
+
+ schService = CreateService(SchSCManager, // handle of service control manager database
+ DriverName, // address of name of service to start
+ DriverName, // address of display name
+ SERVICE_ALL_ACCESS, // type of access to service
+ SERVICE_KERNEL_DRIVER, // type of service
+ SERVICE_DEMAND_START, // when to start service
+ SERVICE_ERROR_NORMAL, // severity if service fails to start
+ ServiceExe, // address of name of binary file
+ NULL, // service does not belong to a group
+ NULL, // no tag requested
+ NULL, // no dependency names
+ NULL, // use LocalSystem account
+ NULL // no password for service account
+ );
+
+ if (schService == NULL) {
+
+ err = GetLastError();
+
+ if (err == ERROR_SERVICE_EXISTS) {
+
+ //
+ // Ignore this error.
+ //
+
+ return TRUE;
+
+ } else {
+
+ printf("CreateService failed! Error = %d \n", err );
+
+ //
+ // Indicate an error.
+ //
+
+ return FALSE;
+ }
+ }
+
+ //
+ // Close the service object.
+ //
+
+ if (schService) {
+
+ CloseServiceHandle(schService);
+ }
+
+ //
+ // Indicate success.
+ //
+
+ return TRUE;
+
+} // InstallDriver
+
+BOOLEAN
+ManageDriver(
+ _In_ LPCTSTR DriverName,
+ _In_ LPCTSTR ServiceName,
+ _In_ USHORT Function
+ )
+{
+
+ SC_HANDLE schSCManager;
+
+ BOOLEAN rCode = TRUE;
+
+ //
+ // Insure (somewhat) that the driver and service names are valid.
+ //
+
+ if (!DriverName || !ServiceName) {
+
+ printf("Invalid Driver or Service provided to ManageDriver() \n");
+
+ return FALSE;
+ }
+
+ //
+ // Connect to the Service Control Manager and open the Services database.
+ //
+
+ schSCManager = OpenSCManager(NULL, // local machine
+ NULL, // local database
+ SC_MANAGER_ALL_ACCESS // access required
+ );
+
+ if (!schSCManager) {
+
+ printf("Open SC Manager failed! Error = %d \n", GetLastError());
+
+ return FALSE;
+ }
+
+ //
+ // Do the requested function.
+ //
+
+ switch( Function ) {
+
+ case DRIVER_FUNC_INSTALL:
+
+ //
+ // Install the driver service.
+ //
+
+ if (InstallDriver(schSCManager,
+ DriverName,
+ ServiceName
+ )) {
+
+ //
+ // Start the driver service (i.e. start the driver).
+ //
+
+ rCode = StartDriver(schSCManager,
+ DriverName
+ );
+
+ } else {
+
+ //
+ // Indicate an error.
+ //
+
+ rCode = FALSE;
+ }
+
+ break;
+
+ case DRIVER_FUNC_REMOVE:
+
+ //
+ // Stop the driver.
+ //
+
+ StopDriver(schSCManager,
+ DriverName
+ );
+
+ //
+ // Remove the driver service.
+ //
+
+ RemoveDriver(schSCManager,
+ DriverName
+ );
+
+ //
+ // Ignore all errors.
+ //
+
+ rCode = TRUE;
+
+ break;
+
+ default:
+
+ printf("Unknown ManageDriver() function. \n");
+
+ rCode = FALSE;
+
+ break;
+ }
+
+ //
+ // Close handle to service control manager.
+ //
+
+ if (schSCManager) {
+
+ CloseServiceHandle(schSCManager);
+ }
+
+ return rCode;
+
+} // ManageDriver
+
+
+BOOLEAN
+RemoveDriver(
+ _In_ SC_HANDLE SchSCManager,
+ _In_ LPCTSTR DriverName
+ )
+{
+ SC_HANDLE schService;
+ BOOLEAN rCode;
+
+ //
+ // Open the handle to the existing service.
+ //
+
+ schService = OpenService(SchSCManager,
+ DriverName,
+ SERVICE_ALL_ACCESS
+ );
+
+ if (schService == NULL) {
+
+ printf("OpenService failed! Error = %d \n", GetLastError());
+
+ //
+ // Indicate error.
+ //
+
+ return FALSE;
+ }
+
+ //
+ // Mark the service for deletion from the service control manager database.
+ //
+
+ if (DeleteService(schService)) {
+
+ //
+ // Indicate success.
+ //
+
+ rCode = TRUE;
+
+ } else {
+
+ printf("DeleteService failed! Error = %d \n", GetLastError());
+
+ //
+ // Indicate failure. Fall through to properly close the service handle.
+ //
+
+ rCode = FALSE;
+ }
+
+ //
+ // Close the service object.
+ //
+
+ if (schService) {
+
+ CloseServiceHandle(schService);
+ }
+
+ return rCode;
+
+} // RemoveDriver
+
+
+
+BOOLEAN
+StartDriver(
+ _In_ SC_HANDLE SchSCManager,
+ _In_ LPCTSTR DriverName
+ )
+{
+ SC_HANDLE schService;
+ DWORD err;
+
+ //
+ // Open the handle to the existing service.
+ //
+
+ schService = OpenService(SchSCManager,
+ DriverName,
+ SERVICE_ALL_ACCESS
+ );
+
+ if (schService == NULL) {
+
+ printf("OpenService failed! Error = %d \n", GetLastError());
+
+ //
+ // Indicate failure.
+ //
+
+ return FALSE;
+ }
+
+ //
+ // Start the execution of the service (i.e. start the driver).
+ //
+
+ if (!StartService(schService, // service identifier
+ 0, // number of arguments
+ NULL // pointer to arguments
+ )) {
+
+ err = GetLastError();
+
+ if (err == ERROR_SERVICE_ALREADY_RUNNING) {
+
+ //
+ // Ignore this error.
+ //
+
+ return TRUE;
+
+ } else {
+
+ printf("StartService failure! Error = %d \n", err );
+
+ //
+ // Indicate failure. Fall through to properly close the service handle.
+ //
+
+ return FALSE;
+ }
+
+ }
+
+ //
+ // Close the service object.
+ //
+
+ if (schService) {
+
+ CloseServiceHandle(schService);
+ }
+
+ return TRUE;
+
+} // StartDriver
+
+
+
+BOOLEAN
+StopDriver(
+ _In_ SC_HANDLE SchSCManager,
+ _In_ LPCTSTR DriverName
+ )
+{
+ BOOLEAN rCode = TRUE;
+ SC_HANDLE schService;
+ SERVICE_STATUS serviceStatus;
+
+ //
+ // Open the handle to the existing service.
+ //
+
+ schService = OpenService(SchSCManager,
+ DriverName,
+ SERVICE_ALL_ACCESS
+ );
+
+ if (schService == NULL) {
+
+ printf("OpenService failed! Error = %d \n", GetLastError());
+
+ return FALSE;
+ }
+
+ //
+ // Request that the service stop.
+ //
+
+ if (ControlService(schService,
+ SERVICE_CONTROL_STOP,
+ &serviceStatus
+ )) {
+
+ //
+ // Indicate success.
+ //
+
+ rCode = TRUE;
+
+ } else {
+
+ printf("ControlService failed! Error = %d \n", GetLastError() );
+
+ //
+ // Indicate failure. Fall through to properly close the service handle.
+ //
+
+ rCode = FALSE;
+ }
+
+ //
+ // Close the service object.
+ //
+
+ if (schService) {
+
+ CloseServiceHandle (schService);
+ }
+
+ return rCode;
+
+} // StopDriver
+
+
+
+
diff --git a/general/cancel/exe/testapp.c b/general/cancel/exe/testapp.c
new file mode 100644
index 00000000..f6c27fe9
--- /dev/null
+++ b/general/cancel/exe/testapp.c
@@ -0,0 +1,333 @@
+/*++
+
+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:
+
+ testapp.c
+
+Abstract:
+
+Environment:
+
+ User mode Win32 console application
+
+--*/
+
+//
+// Annotation to indicate to prefast that this is nondriver user-mode code.
+//
+
+#include <DriverSpecs.h>
+_Analysis_mode_(_Analysis_code_type_user_code_)
+
+#include <windows.h>
+#include <winioctl.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <strsafe.h>
+
+#include "testapp.h"
+
+//
+// Globals
+//
+
+HANDLE hDevice;
+BOOLEAN ExitFlag = FALSE;
+HANDLE hThreads[MAXTHREADS];
+
+//
+// function prototypes
+//
+
+VOID CALLBACK CompletionRoutine(
+ DWORD errorcode,
+ DWORD bytesTransfered,
+ LPOVERLAPPED ov
+ );
+
+DWORD
+WINAPI Reader(
+ PVOID
+ );
+
+BOOLEAN
+SetupDriverName(
+ _Inout_updates_all_(BufferLength) PCHAR DriverLocation,
+ _In_ ULONG BufferLength
+ );
+
+//
+// Main function
+//
+
+VOID __cdecl
+main(
+ _In_ ULONG argc,
+ _In_reads_(argc) PCHAR argv[]
+ )
+{
+ ULONG i, Id;
+ ULONG NumberOfThreads = 1;
+ DWORD errNum = 0;
+ TCHAR driverLocation[MAX_PATH] = {'\0'};
+
+
+ if (argc >= 2 && (argv[1][0] == '-' || isalpha((unsigned char)argv[1][0])))
+ {
+ puts("Usage:testapp <NumberOfThreads>\n");
+ return;
+ }
+ else if (argc >= 2 && ((NumberOfThreads = atoi(argv[1])) > MAXTHREADS))
+ {
+ printf("Invalid option:Only a maximun of %d threads allowed.\n",
+ MAXTHREADS);
+ return;
+
+ }
+
+ //
+ // Try to connect to driver. If this fails, try to load the driver
+ // dynamically.
+ //
+
+ if ((hDevice = CreateFile("\\\\.\\CancelSamp",
+ GENERIC_READ,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ NULL
+ )) == INVALID_HANDLE_VALUE) {
+
+ errNum = GetLastError();
+
+ if (errNum != ERROR_FILE_NOT_FOUND) {
+
+ printf("CreateFile failed! Error = %d\n", errNum);
+
+ return ;
+ }
+
+ //
+ // Setup full path to driver name.
+ //
+
+ if (!SetupDriverName(driverLocation, sizeof(driverLocation))) {
+
+ return ;
+ }
+
+
+ //
+ // Install driver.
+ //
+
+ if (!ManageDriver(DRIVER_NAME,
+ driverLocation,
+ DRIVER_FUNC_INSTALL
+ )) {
+
+ printf("Unable to install driver. \n");
+
+ //
+ // Error - remove driver.
+ //
+
+ ManageDriver(DRIVER_NAME,
+ driverLocation,
+ DRIVER_FUNC_REMOVE
+ );
+
+ return;
+ }
+ //
+ // Try to open the newly installed driver.
+ //
+
+ hDevice = CreateFile( "\\\\.\\CancelSamp",
+ GENERIC_READ,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+
+ if ( hDevice == INVALID_HANDLE_VALUE ){
+ printf ( "Error: CreatFile Failed : %d\n", GetLastError());
+ return;
+ }
+ }
+
+ printf("Number of threads : %d\n", NumberOfThreads);
+
+
+ printf("Enter 'q' to exit gracefully:");
+
+ for(i=0; i < NumberOfThreads; i++)
+ {
+ hThreads[i] = CreateThread( NULL, // security attributes
+ 0, // initial stack size
+ Reader, // Main() function
+ NULL, // arg to Reader thread
+ 0, // creation flags
+ (LPDWORD)&Id); // returned thread id
+
+ if ( NULL == hThreads[i] ) {
+ printf( " Error CreateThread[%d] Failed: %d\n", i, GetLastError());
+ ExitProcess ( 1 );
+ }
+
+ }
+
+
+ if (getchar() == 'q')
+ {
+ ExitFlag = TRUE;
+
+ WaitForMultipleObjects( NumberOfThreads, hThreads, TRUE, INFINITE);
+
+ for(i=0; i < NumberOfThreads; i++)
+ CloseHandle(hThreads[i]);
+
+ }
+
+ CloseHandle(hDevice);
+
+ //
+ // Unload the driver. Ignore any errors.
+ //
+
+ ManageDriver(DRIVER_NAME,
+ driverLocation,
+ DRIVER_FUNC_REMOVE
+ );
+
+ ExitProcess(1);
+
+}
+
+
+DWORD WINAPI Reader(PVOID dummy )
+{
+ ULONG data;
+ OVERLAPPED ov;
+
+ UNREFERENCED_PARAMETER(dummy);
+
+ while(!ExitFlag)
+ {
+ ZeroMemory( &ov, sizeof(ov) );
+ ov.Offset = 0;
+ ov.OffsetHigh = 0;
+
+ if (!ReadFileEx(hDevice, (PVOID)&data, sizeof(ULONG), &ov, CompletionRoutine))
+ {
+ printf ( "Error: Read Failed: %d\n", GetLastError());
+ ExitProcess ( 1 );
+ }
+ SleepEx(INFINITE, TRUE);
+ }
+
+ printf("Exiting thread %d \n", GetCurrentThreadId());
+ ExitThread(0);
+}
+
+
+VOID CALLBACK CompletionRoutine(
+ DWORD errorcode,
+ DWORD bytesTransfered,
+ LPOVERLAPPED ov
+ )
+{
+
+ UNREFERENCED_PARAMETER(errorcode);
+ UNREFERENCED_PARAMETER(ov);
+
+ fprintf(stdout, "Thread %d read: %d bytes\n",
+ GetCurrentThreadId(), bytesTransfered);
+ return;
+}
+
+
+BOOLEAN
+SetupDriverName(
+ _Inout_updates_all_(BufferLength) PCHAR DriverLocation,
+ _In_ ULONG BufferLength
+ )
+{
+ HANDLE fileHandle;
+ DWORD driverLocLen = 0;
+
+ //
+ // Get the current directory.
+ //
+
+ driverLocLen = GetCurrentDirectory(BufferLength,
+ DriverLocation
+ );
+
+ if (driverLocLen == 0) {
+
+ printf("GetCurrentDirectory failed! Error = %d \n", GetLastError());
+
+ return FALSE;
+ }
+
+ //
+ // Setup path name to driver file.
+ //
+ if (FAILED( StringCbCat(DriverLocation, BufferLength, "\\"DRIVER_NAME".sys") )) {
+ return FALSE;
+ }
+
+ //
+ // Insure driver file is in the specified directory.
+ //
+
+ if ((fileHandle = CreateFile(DriverLocation,
+ GENERIC_READ,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL
+ )) == INVALID_HANDLE_VALUE) {
+
+
+ printf("%s.sys is not loaded.\n", DRIVER_NAME);
+
+ //
+ // Indicate failure.
+ //
+
+ return FALSE;
+ }
+
+ //
+ // Close open file handle.
+ //
+
+ if (fileHandle) {
+
+ CloseHandle(fileHandle);
+ }
+
+ //
+ // Indicate success.
+ //
+
+ return TRUE;
+
+
+} // SetupDriverName
+
+
+
diff --git a/general/cancel/exe/testapp.h b/general/cancel/exe/testapp.h
new file mode 100644
index 00000000..fa63d0b9
--- /dev/null
+++ b/general/cancel/exe/testapp.h
@@ -0,0 +1,14 @@
+
+#define DRIVER_FUNC_INSTALL 0x01
+#define DRIVER_FUNC_REMOVE 0x02
+
+#define MAXTHREADS 10
+#define DRIVER_NAME "cancel"
+
+BOOLEAN
+ManageDriver(
+ _In_ LPCTSTR DriverName,
+ _In_ LPCTSTR ServiceName,
+ _In_ USHORT Function
+ );
+
diff --git a/general/cancel/startio/cancel.c b/general/cancel/startio/cancel.c
new file mode 100644
index 00000000..808a8941
--- /dev/null
+++ b/general/cancel/startio/cancel.c
@@ -0,0 +1,965 @@
+/*++
+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.
+
+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;
+ UNICODE_STRING sddlString;
+
+ UNREFERENCED_PARAMETER (RegistryPath);
+
+ CSAMP_KDPRINT(("DriverEntry Enter \n"));
+
+
+ (void) RtlInitUnicodeString(&unicodeDeviceName, CSAMP_DEVICE_NAME_U);
+
+ //
+ // 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.
+ //
+
+ (void) RtlInitUnicodeString(&sddlString, L"D:P(A;;GA;;;SY)(A;;GA;;;BA)");
+
+ 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;
+ }
+
+ //
+ // 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;
+
+ //
+ // Initialize the spinlock. This is used to serailize
+ // access to the device.
+ //
+
+ KeInitializeSpinLock(&devExtension->DeviceLock);
+
+ //
+ // This is used to serailize access to the queue.
+ //
+
+ KeInitializeSpinLock(&devExtension->QueueLock);
+
+
+ //
+ //Initialize the Dpc object
+ //
+
+ KeInitializeDpc(&devExtension->PollingDpc,
+ CsampPollingTimerDpc,
+ (PVOID)deviceObject);
+
+ //
+ // Initialize the timer object
+ //
+
+ KeInitializeTimer(&devExtension->PollingTimer);
+
+ //
+ // Initialize the pending Irp devicequeue
+ //
+
+ InitializeListHead(&devExtension->PendingIrpQueue);
+
+ //
+ // 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);
+
+ IoCsqInitializeEx(&devExtension->CancelSafeQueue,
+ CsampInsertIrp,
+ CsampRemoveIrp,
+ CsampPeekNextIrp,
+ CsampAcquireLock,
+ CsampReleaseLock,
+ CsampCompleteCanceledIrp);
+
+ 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 higher-level driver is
+ // layering itself over a lower-level 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. Certain types of drivers do not
+ // need to handle IRP_MJ_CLOSE, mainly drivers of devices that must
+ // be available for the system to continue running. In general, this
+ // is the place that a driver should "undo" whatever has been done
+ // in the routine for IRP_MJ_CREATE.
+ //
+
+ 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;
+ PVOID readBuffer;
+ PFILE_CONTEXT fileContext;
+ BOOLEAN inCriticalRegion;
+
+ PAGED_CODE();
+
+ CSAMP_KDPRINT(("--->CsampReadReport irp 0x%p\n", Irp));
+
+ //
+ // Get a pointer to the device extension.
+ //
+ 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;
+ }
+
+ //
+ // Simple little random polling time generator.
+ // 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);
+
+ //
+ // If the thread is suspended right after the queue is marked busy due to
+ // insert, it will prevent I/Os from other threads being processed leading
+ // to denial of service (DOS) attack. So disable thread suspension by
+ // entering critical region.
+ //
+ ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
+ KeEnterCriticalRegion();
+ inCriticalRegion = TRUE;
+
+ //
+ // Try inserting the IRP in the queue. If the device is busy,
+ // the IRP will get queued and the following function will
+ // return SUCCESS. If the device is not busy, it will set the
+ // IRP to DeviceExtension->CurrentIrp and return UNSUCCESSFUL.
+ //
+ if (!NT_SUCCESS(IoCsqInsertIrpEx(&devExtension->CancelSafeQueue,
+ Irp, NULL, NULL))) {
+ IoMarkIrpPending(Irp);
+
+ CsampInitiateIo(DeviceObject);
+ } else {
+ //
+ // 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.
+ //
+ // DO_NOTHING();
+ }
+ 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);
+
+ CSAMP_KDPRINT(("<---CsampReadReport\n"));
+
+ return STATUS_PENDING;
+}
+
+VOID
+CsampInitiateIo(
+ _In_ PDEVICE_OBJECT DeviceObject
+)
+ /*++
+ Routine Description:
+
+ Performs the actual I/O operations.
+
+ Arguments:
+
+ DeviceObject - pointer to a device object.
+
+ Return Value:
+
+ NT status code.
+
+
+--*/
+
+{
+ NTSTATUS status;
+ PDEVICE_EXTENSION devExtension = DeviceObject->DeviceExtension;
+ PIRP irp = NULL;
+
+ CSAMP_KDPRINT(("--> CsampInitiateIo\n"));
+
+ irp = devExtension->CurrentIrp;
+
+ for(;;) {
+
+ ASSERT(irp != NULL && irp == devExtension->CurrentIrp);
+
+ status = CsampPollDevice(DeviceObject, irp);
+ if (status == STATUS_PENDING)
+ {
+ //
+ // Oops, polling too soon. Start the timer to retry the operation.
+ //
+ KeSetTimer(&devExtension->PollingTimer,
+ devExtension->PollingInterval,
+ &devExtension->PollingDpc);
+ break;
+ }
+ else
+ {
+ //
+ // Read device is successful. Now complete the IRP and service
+ // the next one from the queue.
+ //
+ irp->IoStatus.Status = status;
+ CSAMP_KDPRINT(("completing irp :0x%p\n", irp));
+ IoCompleteRequest (irp, IO_NO_INCREMENT);
+
+ irp = IoCsqRemoveNextIrp(&devExtension->CancelSafeQueue, NULL);
+
+ if (irp == NULL) {
+ break;
+ }
+ }
+
+ }
+
+ CSAMP_KDPRINT(("<---CsampInitiateIo\n"));
+
+ return;
+}
+
+_Use_decl_annotations_
+VOID
+CsampPollingTimerDpc(
+ PKDPC Dpc,
+ PVOID Context,
+ PVOID SystemArgument1,
+ PVOID SystemArgument2
+)
+ /*++
+ Routine Description:
+
+ CustomTimerDpc routine to process Irp that are
+ waiting in the PendingIrpQueue
+
+ Arguments:
+
+ DeviceObject - pointer to DPC object
+ Context - pointer to device object
+ SystemArgument1 - undefined
+ SystemArgument2 - undefined
+
+ Return Value:
+--*/
+{
+ PDEVICE_OBJECT deviceObject;
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(SystemArgument1);
+ UNREFERENCED_PARAMETER(SystemArgument2);
+
+ CSAMP_KDPRINT(("---> CsampPollingTimerDpc\n"));
+
+ _Analysis_assume_(Context != NULL);
+
+ deviceObject = (PDEVICE_OBJECT)Context;
+
+ CsampInitiateIo(deviceObject);
+
+ CSAMP_KDPRINT(("<--- CsampPollingTimerDpc\n"));
+}
+
+_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\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;
+ 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\n"));
+
+ return STATUS_SUCCESS;
+}
+
+_Use_decl_annotations_
+NTSTATUS
+CsampPollDevice(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ Pools 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
+ // irp should be queued before completing.
+ //
+
+ if (pInput->Data-- <= 0)
+ {
+ Irp->IoStatus.Information = sizeof(INPUT_DATA);
+ return STATUS_SUCCESS;
+ }
+ return STATUS_PENDING;
+
+ #endif
+
+}
+
+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\n"));
+
+ //
+ // The OS (XP and beyond) forces any DPCs that are already
+ // running to run to completion, even after the driver unload ,
+ // routine returns, but before unmapping the driver image from
+ // memory.
+ // This driver makes an assumption that I/O request are going to
+ // come only from usermode app and as long as there are active
+ // IRPs in the driver, the driver will not get unloaded.
+ // NOTE: If a driver can get I/O request directly from another
+ // driver without having an explicit handle, you should wait on an
+ // event signalled by the DPC to make sure that DPC doesn't access
+ // the resources that you are going to free here.
+ //
+ KeCancelTimer(&devExtension->PollingTimer);
+
+
+ //
+ // Create counted string version of our Win32 device name.
+ //
+
+ RtlInitUnicodeString(&uniWin32NameString, CSAMP_DOS_DEVICE_NAME_U);
+
+ //
+ // Delete the link from our device name to a name in the Win32 namespace.
+ //
+
+ IoDeleteSymbolicLink(&uniWin32NameString);
+
+ IoDeleteDevice(deviceObject);
+
+ CSAMP_KDPRINT(("<---CsampUnload\n"));
+ return;
+}
+
+NTSTATUS CsampInsertIrp (
+ _In_ PIO_CSQ Csq,
+ _In_ PIRP Irp,
+ _In_ PVOID InsertContext
+ )
+{
+ PDEVICE_EXTENSION devExtension;
+
+ UNREFERENCED_PARAMETER(InsertContext);
+
+ 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->CurrentIrp")
+ if (!devExtension->CurrentIrp) {
+ devExtension->CurrentIrp = Irp;
+ return STATUS_UNSUCCESSFUL;
+ }
+
+
+ InsertTailList(&devExtension->PendingIrpQueue,
+ &Irp->Tail.Overlay.ListEntry);
+ return STATUS_SUCCESS;
+}
+
+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;
+ }
+
+ //
+ // Check if this is from start packet.
+ //
+
+ if (PeekContext == NULL) {
+ devExtension->CurrentIrp = nextIrp;
+ }
+
+ 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);
+
+ CSAMP_KDPRINT(("Cancelled IRP: 0x%p\n", Irp));
+
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+}
+
diff --git a/general/cancel/startio/cancel.h b/general/cancel/startio/cancel.h
new file mode 100644
index 00000000..8f04ab75
--- /dev/null
+++ b/general/cancel/startio/cancel.h
@@ -0,0 +1,166 @@
+#ifndef __CANCEL_H
+#define __CANCEL_H
+
+#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.
+//
+#include <ntddk.h>
+#include <wdmsec.h> // for IoCreateDeviceSecure
+#include <dontuse.h>
+
+// Debugging macros
+
+#if DBG
+#define CSAMP_KDPRINT(_x_) \
+ DbgPrint("CANCEL.SYS: ");\
+ DbgPrint _x_;
+
+#define TRAP() DbgBreakPoint()
+
+#else
+
+#define CSAMP_KDPRINT(_x_)
+
+#define TRAP()
+
+#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{
+
+ // Irps waiting to be processed are queued here
+ LIST_ENTRY PendingIrpQueue;
+
+ // SpinLock to protect access to the queue
+ KSPIN_LOCK QueueLock;
+
+ // SpinLock to provide exclusive access to the port
+ KSPIN_LOCK DeviceLock;
+
+ // Pointer to current device IRP. Exclusive access to this
+ // field is also provided by the QueueLock.
+ PIRP CurrentIrp;
+
+ // Customtimer DPC object
+ KDPC PollingDpc;
+
+ // Time at which the device was last polled
+ LARGE_INTEGER LastPollTime;
+
+ // Polling timer object
+ KTIMER PollingTimer;
+
+ // Polling interval (retry interval)
+ LARGE_INTEGER PollingInterval;
+
+ IO_CSQ CancelSafeQueue;
+
+} 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;
+
+KDEFERRED_ROUTINE CsampPollingTimerDpc;
+
+VOID
+CsampInitiateIo(
+ _In_ PDEVICE_OBJECT DeviceObject
+);
+
+NTSTATUS
+CsampInsertIrp (
+ _In_ PIO_CSQ Csq,
+ _In_ PIRP Irp,
+ _In_ PVOID InsertContext
+ );
+
+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/startio/cancel.rc b/general/cancel/startio/cancel.rc
new file mode 100644
index 00000000..2bd08155
--- /dev/null
+++ b/general/cancel/startio/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/startio/cancel.vcxproj b/general/cancel/startio/cancel.vcxproj
new file mode 100644
index 00000000..8cdbf0ce
--- /dev/null
+++ b/general/cancel/startio/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>{1392C861-BA6F-4423-8C33-A8C771BAF473}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{2FA77D27-524D-4C63-81CD-62E054676D96}</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/startio/cancel.vcxproj.Filters b/general/cancel/startio/cancel.vcxproj.Filters
new file mode 100644
index 00000000..015f96b7
--- /dev/null
+++ b/general/cancel/startio/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>{DBC52094-6726-43E4-8D3A-1E52EB8592CA}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{12A618AD-2EC7-4EF1-B1F8-F14652DE50D0}</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>{01F4B40C-7AC7-4573-A236-526D211FE249}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Driver Files">
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ <UniqueIdentifier>{C63E5134-5856-4331-9141-C85F75D697B9}</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
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