📄 roll.c
字号:
//
// (C) Copyright 1997 OSR Open Systems Resources, Inc.
// All Rights Reserved
//
#include "roll.h"
//
// This demonstrates how to build your own IRPs completely from scratch, using
// your own memory, etc.
//
// Please keep in mind as you read this example that it was written with the intent
// to demonstrate a specific technique. Thus, there are numerous ways this could
// be implemented, some of them far more brief. Feel free to modify this code to use
// in your OWN programs...
//
//
// Data structures local to this module.
//
LIST_ENTRY MyIrpFreeList; // contains freed, not currently in use
KSPIN_LOCK MyIrpFreeListLock; // protection for the list
USHORT MyIrpFreeListMax; // maximum # of IRPs to create for my free list
USHORT MyIrpFreeListCount; // current # of IRPs created for my free list
KEVENT MyIrpFreeListEvent; // allows caller to wait for an IRP
USHORT MyIrpSize; // # of bytes in the IRPs we allocate
CCHAR MyNumberOfIrpStackLocations; // # of IRP stack locations allocated in each IRP
//
// NOTE: In NT 4.0 you can use "look aside" lists to track free IRPs (they
// are really "free lists".) These examples were written for NT 3.51 or
// 4.0 so you should modify the code to fit your specific requirements.
//
//
// For our purposes we hard-code the size of the IRPs we'll be creating. We
// use five because that's safe, even with a single filter driver in the stack.
//
#define MAXIMUM_IRP_STACK_LOCATIONS (5)
//
// We'll limit the # of IRPs we create in this package to an arbitrary number. Again,
// this can be changed to fit your requirements - or don't limit it at all!
//
#define MAXIMUM_IRP_COUNT (64)
//
// AllocateNewIrp
//
// This internal helper routine is used to allocate a new IRP from non-paged pool.
//
// Inputs:
// None.
//
// Outputs:
// None.
//
// Returns:
// A pointer to the newly created IRP.
//
// Notes:
// None.
static PIRP AllocateNewIrp()
{
PIRP newIrp;
//
// First, this routine fails whenever we've hit the maximum number.
//
if (MyIrpFreeListCount > MyIrpFreeListMax) {
//
// Return null - refuse this request.
//
return (PIRP) 0;
}
//
// We use a special tag value to allow us to detect the IRPs we are creating (using
// the kernel debugger or "poolmon".
//
newIrp = ExAllocatePoolWithTag(NonPagedPool, MyIrpSize, 'rIyM');
if (!newIrp) {
//
// The creation of a new IRP failed. The only time this really happens is when there is
// no more non-paged pool.
//
// We choose the simpler solution here - we just return a null pointer.
// If your driver requires it, please feel free to call NonPagedPoolMustSucceed - but
// remember that the amount of such memory is VERY limited and if it cannot be granted
// the system crashes ("blue screen"). Use sparingly.
//
return 0;
}
//
// At this point, the IRP is allocated. Return it to the caller.
//
return newIrp;
}
//
// MyInitIrpPackage
//
// This routine is called to initialize the IRP management package.
//
// Inputs:
// MaximumNumberOfIrpStackLocations - the # of IRP stack locations to allocate for all IRPs in the package
// MaximumNumberOfIrps - the maximum # of IRPs to be allocated (on demand) by this package
//
// Outputs:
// None.
//
// Returns:
// None.
//
// Notes:
// This package uses defaults if the passed-in values are zero.
//
VOID MyInitIrpPackage(CCHAR MaximumNumberOfIrpStackLocations, USHORT MaximumNumberOfIrps)
{
ULONG MyIrpSize;
if (MaximumNumberOfIrpStackLocations == 0) {
//
// We'll use the "default" number in this case
//
MyNumberOfIrpStackLocations = MAXIMUM_IRP_STACK_LOCATIONS;
} else {
//
// We'll use the number passed in by the caller
//
MyNumberOfIrpStackLocations = MaximumNumberOfIrpStackLocations;
}
if (MaximumNumberOfIrps == 0) {
//
// We'll fall back on the backup value.
// Note: this could be turned into a registry lookup for your particular driver.
//
MyIrpFreeListMax = MAXIMUM_IRP_COUNT;
} else {
//
// We'll use the number given us by the caller
//
MyIrpFreeListMax = MaximumNumberOfIrps;
}
//
// Now, compute the size of an IRP with the requisite # of stack
// locations.
//
MyIrpSize = IoSizeOfIrp(MyNumberOfIrpStackLocations);
//
// Initialize our free list, spin lock, and free list event...
//
InitializeListHead(&MyIrpFreeList);
KeInitializeSpinLock(&MyIrpFreeListLock);
MyIrpFreeListCount = 0;
KeInitializeEvent(&MyIrpFreeListEvent, SynchronizationEvent, FALSE);
//
// Now, let's start the list off with the first IRP. We could defer this to first
// reference but we decided to add this code early because it ensures we exercise
// most of the logic we use in this package.
//
MyFreeIrp(AllocateNewIrp());
//
// We believe there will be something on the list. We assert this at this point.
//
ASSERT(!IsListEmpty(&MyIrpFreeList));
//
// Done with the initialization. Of course, feel free to add more
// code here for YOUR specific project!
//
return;
}
//
// MyAllocateIrp
//
// This routine is called by your driver to allocate a new I/O request packet.
//
// Inputs:
// StackSize - this is the # of stack elements required. It must be <= the max # of stack sizes
// Wait - indicates if the caller is willing to wait for the IRP allocation
//
// Outputs:
// None.
//
// Returns:
// The new IRP if successful. Otherwise, null
//
// Notes:
// Any caller already "owning" an IRP created by this package MUST indicate Wait = FALSE to
// avoid deadlock conditions. Callers of this routine which indicate Wait == TRUE must be
// dispatchable (IRQL < DISPATCH_LEVEL).
//
PIRP MyAllocateIrp(CCHAR StackSize, BOOLEAN Wait)
{
KIRQL oldIrql;
PIRP newIrp = 0;
//
// The caller should never ask for an IRP with more stack locations than those we
// have created. If they do, there is something wrong - we'll assert out at this point
// so we can catch this problem.
//
// (If you ignore this failure here, later you will see a blue screen with
// NO_MORE_IRP_STACK_LOCATIONS as the stop code - eventually.)
//
ASSERT(StackSize <= MyNumberOfIrpStackLocations);
while (1) {
KeAcquireSpinLock(&MyIrpFreeListLock, &oldIrql);
//
// We must use RemoveHeadList in an IF statement because it is not an expression.
//
if (!IsListEmpty(&MyIrpFreeList)) {
PLIST_ENTRY listEntry;
//
// Remove the head of the list.
//
listEntry = RemoveHeadList(&MyIrpFreeList);
//
// Convert into an IRP pointer.
//
newIrp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
}
KeReleaseSpinLock(&MyIrpFreeListLock, oldIrql);
if (newIrp) {
//
// Jump out of the loop.
//
break;
}
//
// We'll try to create a new entry.
//
newIrp = AllocateNewIrp();
if (!newIrp) {
//
// The allocation was unsuccessful. If the caller indicated they could wait
// then we'll put them to sleep waiting for the synchronization event
//
// NOTE: We assume here we seeded the list, so there is AT LEAST ONE IRP already
// created for the pool. If there were zero, we might never wake up, because
// we're going to count on some other thread releasing an IRP.
//
if (Wait) {
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
KeWaitForSingleObject(&MyIrpFreeListEvent,
Spare6, // reason - we use this to ease debugging.
KernelMode, // mode
FALSE, // not altertable
0); // no timeout
} else {
//
// The caller indicated they could not wait. We'll break from the loop and handle
// this condition below.
//
break;
}
} // if (!newIrp)
} // while (1)
//
// At this point we're done with the processing. If this is null, it is because the caller
// was unwilling to wait for allocation.
//
return newIrp;
}
//
// MyFreeIrp
//
// This routine is called to free up an IRP previously allocated by a call to MyAllocateIrp
//
// Inputs:
// Irp - the IRP to be freed
//
// Outputs:
// None.
//
// Returns:
// None.
//
// Notes:
// NEVER call this package with I/O manager allocated IRPs - doing so may cause catastrophic system failure
// (since we're going to reinitialize the IRPs and if they aren't of the correct size we could trash things...)
//
//
VOID MyFreeIrp(PIRP Irp)
{
//
// If a null pointer is passed we just return. Not much we can do with
// a null pointer.
//
if (!Irp) {
return;
}
//
// Before we re-queue the IRP, we will initialize it. It will then be ready to hand off to the new caller
// when they allocate it.
//
// NOTE: This is the ONLY time you would call IoInitializeIrp - with your own allocated memory. Do NOT
// call it after calling IoAllocateIrp as that will change flags within the IRP which can lead to a system
// crash (memory arena corruption.)
//
IoInitializeIrp(Irp,
MyIrpSize,
(USHORT) MAXIMUM_IRP_STACK_LOCATIONS);
//
// Stick it on the free list
//
ExInterlockedInsertTailList(&MyIrpFreeList,
&Irp->Tail.Overlay.ListEntry,
&MyIrpFreeListLock);
//
// And set the event - this awakens anyone who might be waiting for an IRP.
//
KeSetEvent(&MyIrpFreeListEvent, 1, FALSE);
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -