|
|
#include "wdmsys.h"
#pragma LOCKED_CODE
#pragma LOCKED_DATA
//
// Robust checking enables bugchecks in the retail version of this component.
//
BOOL gbRobustChecking = FALSE;
#if 0
//
// PagedCode: This routine should be used in routines that touch pageable
// code and data. Notice that this is not the PAGED_CODE() macro so that it
// will be in the retail code.
//
void PagedCode( void ) { if( KeGetCurrentIrql() > APC_LEVEL ) { KeBugCheckEx(AUDIO_BUGCHECK_CODE,AUDIO_NOT_BELOW_DISPATCH_LEVEL,0,0,0); } }
void ValidatePassiveLevel( void ) { if( KeGetCurrentIrql() != PASSIVE_LEVEL ) { KeBugCheckEx(AUDIO_BUGCHECK_CODE,AUDIO_NOT_AT_PASSIVE_LEVEL,0,0,0); } }
//
// If bExclusive is TRUE, the caller wants to know if the mutex is acquired multiple
// times on the same thread. If they don't want this checking done, they should
// set bExclusive to FALSE.
//
NTSTATUS AudioEnterMutex( IN PKMUTEX pmutex, IN BOOL bExclusive ) { PRKTHREAD pkt; NTSTATUS Status; LONG lMutexState;
Status = KeWaitForSingleObject ( pmutex,Executive,KernelMode,FALSE,NULL ) ; if( gbRobustChecking && bExclusive ) { //
// After entering the mutex, we sanity check our nested count, but we
// only do this if we need to. If the caller said that they designed the
// code only for exclusive access, we'll bugcheck if we get nested.
//
if( (lMutexState = KeReadStateMutex(pmutex)) < 0 ) { //
// Every time you acquire a mutex the state will be decremented. 1 means
// that it's available, 0 means it's held, -1 means this is the second time
// it's acquired, -2 means it's the third and so on. Thus, if we're nested
// on this thread, we'll end up here.
//
KeBugCheckEx(AUDIO_BUGCHECK_CODE, AUDIO_NESTED_MUTEX_SITUATION, (ULONG_PTR)pmutex, lMutexState, 0); } } return Status; }
//
// This routine yields if we're at PASSIVE_LEVEL
//
void AudioPerformYield( void ) { PRKTHREAD pthrd; KPRIORITY kpriority;
//
// After releasing the mutex we want to yield execution to all other threads
// on the machine to try to expose preemption windows.
//
if( ( gbRobustChecking ) && ( KeGetCurrentIrql() == PASSIVE_LEVEL ) ) { if( (pthrd = KeGetCurrentThread()) ) { kpriority = KeQueryPriorityThread(KeGetCurrentThread()); //
// Lower this thrread's priority so another thread will
// get scheduled.
//
KeSetPriorityThread(pthrd,1); // Is that low enough?
//
// This might be overkill, but yield.
//
ZwYieldExecution();
//
// Now restore the priority for this thread and party on.
//
KeSetPriorityThread(pthrd,kpriority); }
} }
void AudioLeaveMutex( IN PKMUTEX pmutex ) { PRKTHREAD pthrd; KPRIORITY kpriority;
KeReleaseMutex ( pmutex, FALSE ) ;
AudioPerformYield(); }
NTSTATUS AudioIoCallDriver ( IN PDEVICE_OBJECT pDevice, IN PIRP pIrp ) { NTSTATUS Status;
Status = IoCallDriver(pDevice,pIrp);
AudioPerformYield();
return Status; }
void AudioEnterSpinLock( IN PKSPIN_LOCK pSpinLock, OUT PKIRQL pOldIrql ) { //
// KeAcquireSpinLock can only be called less then or equal to dispatch level.
// let's verify that here.
//
if( ( gbRobustChecking ) && ( KeGetCurrentIrql() > DISPATCH_LEVEL ) ) { KeBugCheckEx(AUDIO_BUGCHECK_CODE, AUDIO_INVALID_IRQL_LEVEL, 0, 0, 0); }
KeAcquireSpinLock ( pSpinLock, pOldIrql ) ; }
void AudioLeaveSpinLock( IN PKSPIN_LOCK pSpinLock, IN KIRQL OldIrql ) { KeReleaseSpinLock ( pSpinLock, OldIrql ) ; AudioPerformYield(); }
void AudioObDereferenceObject( IN PVOID pvObject ) { ObDereferenceObject(pvObject); AudioPerformYield(); }
void AudioIoCompleteRequest( IN PIRP pIrp, IN CCHAR PriorityBoost ) { IoCompleteRequest(pIrp,PriorityBoost);
AudioPerformYield(); } #endif
#define MEMORY_LIMIT_CHECK 262144
//
// This routine assumes that pptr points to a memory location that currently
// contains a NULL value. Thus, on failure, this routine does not have to
// write back a NULL value.
//
// Entry:
// if dwFlags contains:
//#define DEFAULT_MEMORY 0x00 // Standard ExAllocatePool call
//#define ZERO_FILL_MEMORY 0x01 // Zero the memory
//#define QUOTA_MEMORY 0x02 // ExAllocatePoolWithQuota call
//#define LIMIT_MEMORY 0x04 // Never allocation more then 1/4 Meg
//#define FIXED_MEMORY 0x08 // Use locked memory
//#define PAGED_MEMORY 0x10 // use pageable memory
//
NTSTATUS AudioAllocateMemory( IN SIZE_T bytes, IN ULONG tag, IN AAMFLAGS dwFlags, OUT PVOID *pptr ) { NTSTATUS Status; POOL_TYPE pooltype; PVOID pInit; KIRQL irql; PVOID ptr = NULL;
ASSERT(*pptr == NULL);
if( 0 == bytes ) { //
// The code should never be asking for zero bytes. The core will bugcheck
// on a call like this. In debug mode we'll assert. In retail, we'll
// return an error.
//
ASSERT(0); Status = STATUS_INSUFFICIENT_RESOURCES; } else {
if( dwFlags & FIXED_MEMORY ) pooltype = NonPagedPool; else pooltype = PagedPool;
//
// Allocating pageable memory at DISPATCH_LEVEL is a bad thing to do.
// here we make sure that is not the case.
//
if( ( (irql = KeGetCurrentIrql()) > DISPATCH_LEVEL ) || ((DISPATCH_LEVEL == irql ) && (NonPagedPool != pooltype)) ) { //
// Either way, we've got an error, bugcheck or exit.
//
if( gbRobustChecking ) { KeBugCheckEx(AUDIO_BUGCHECK_CODE,AUDIO_INVALID_IRQL_LEVEL,0,0,0); } else { //
// If we can't bugcheck, then we're going to return an error
// in this case.
//
Status = STATUS_INSUFFICIENT_RESOURCES; goto exit; } } //
// Let's see if the caller has asked to limit the allocation to a "reasonable"
// number of bytes. If so, "reasonable" is 1/4 meg.
//
if( ( dwFlags & LIMIT_MEMORY ) && ( bytes > MEMORY_LIMIT_CHECK ) ) { //
// For some reason, this allocation is trying to allocate more then was designed.
// Why is the caller allocating so much?
//
if( gbRobustChecking ) KeBugCheckEx(AUDIO_BUGCHECK_CODE,AUDIO_ABSURD_ALLOCATION_ATTEMPTED,0,0,0);
//
// Checked build will assert if robust checking is not enabled.
//
ASSERT("Memory Allocation Unreasonable!"); }
//
// Allocate the memory, NULL is returned on failure in the normal case, an exception
// is raised with quota. ptr is NULLed out above for the Quota routine.
//
if( dwFlags & QUOTA_MEMORY ) { //
// Caller wants to charge the allocation to the current user context.
//
try {
ptr = ExAllocatePoolWithQuotaTag(pooltype,bytes,tag);
}except (EXCEPTION_EXECUTE_HANDLER) {
Status = STATUS_INSUFFICIENT_RESOURCES; } } else { //
// Don't want to assign this memory to the quota.
//
ptr = ExAllocatePoolWithTag(pooltype, bytes, tag); }
if( ptr ) { if( dwFlags & ZERO_FILL_MEMORY ) { RtlFillMemory( ptr,bytes,0 ); } //
// Never allocate over the top of an existing pointer. Interlock exchange
// with the location. This interlock updates the location in the caller.
//
if( pInit = InterlockedExchangePointer(pptr,ptr) ) { //
// If we get a return value from this exchange it means that there
// was already a pointer in the location that we added a pointer too.
// If this is the case, most likely we overwrote a valid memory
// pointer. With robust checking we don't want this to happen.
//
if( gbRobustChecking ) { KeBugCheckEx(AUDIO_BUGCHECK_CODE, AUDIO_MEMORY_ALLOCATION_OVERWRITE, (ULONG_PTR)pInit, 0,0); } //
// If we end up here, we've overwritten a memory pointer with a
// successful memory allocation. Or ASSERT at the top of this
// function should have fired. In any case, we can return success
// and how that nothing bad happens.
//
} Status = STATUS_SUCCESS; } else { //
// Our memory allocation failed. *pptr should still be NULL
// return error.
//
Status = STATUS_INSUFFICIENT_RESOURCES; } } exit: return Status; }
//
// This routine is safe to call with a NULL memory pointer. It will return
// STATUS_UNSUCCESSFUL and do nothing if passed a NULL pointer. Also, this routine
// reads the location atomically so it should be safe in a multiproc environment.
//
void AudioFreeMemory( IN SIZE_T bytes, IN OUT PVOID *pptr ) { PVOID pFree; KIRQL irql;
//
// Interlockedexhchange the pointer will NULL, validate that it's non-NULL
// trash the memory if needed and then free the pointer.
//
pFree = InterlockedExchangePointer(pptr,NULL); if( pFree ) { //
// We have a pointer to free.
//
if( gbRobustChecking ) { //
// The docs say that we need to be careful how we call the free routine
// with regard to IRQlevel. Thus, if we're being robust we'll do this
// extra work.
//
if( (irql = KeGetCurrentIrql()) > DISPATCH_LEVEL ) { KeBugCheckEx(AUDIO_BUGCHECK_CODE,AUDIO_INVALID_IRQL_LEVEL,0,0,0); }
//
// Under debug we're going to put 'k's in the memory location in order
// to make extra sure that no one is using this memory.
//
if( UNKNOWN_SIZE != bytes ) { RtlFillMemory( pFree,bytes,'k' ); } }
//
// Now we actually free the memory.
//
ExFreePool(pFree);
}
return; }
|