|
|
/***********
//joejoe
Joelinn 2-13-95
This is the pits......i have to pull in the browser in order to be started form the lanman network provider DLL. the browser should be moved elsewhere........
**********************/
/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
disccode.c
Abstract:
This module contains the code to manage the NT redirectors discardable code sections.
Author:
Larry Osterman (larryo) 12-Nov-1993
Environment:
Kernel mode.
Revision History:
12-Nov-1993
Created
--*/
//
// Include modules
//
#include "precomp.h"
#pragma hdrstop
#include <ntbowsif.h>
//
// The Bug check file id for this module
//
#define BugCheckFileId (RDBSS_BUG_CHECK_NTBOWSIF)
//
// The local debug trace level
//
#define Dbg (DEBUG_TRACE_DISCCODE)
BOOLEAN DiscCodeInitialized = FALSE;
VOID RdrDiscardableCodeRoutine( IN PVOID Context );
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, RdrReferenceDiscardableCode)
#pragma alloc_text(PAGE, RdrDereferenceDiscardableCode)
#pragma alloc_text(PAGE, RdrDiscardableCodeRoutine)
#pragma alloc_text(INIT, RdrInitializeDiscardableCode)
#pragma alloc_text(PAGE, RdrUninitializeDiscardableCode)
#endif
//
// These 7 variables maintain the state needed to manage the redirector
// discardable code section.
//
// The redirector discardable code section is referenced via a call to
// RdrReferenceDiscardableCodeSection, and dereferenced via a call to
// RdrDereferenceDiscardableCodeSection.
//
// If the discardable code section is already mapped into memory, then
// referencing the discardable code section is extremely quick.
//
// When the reference count on the discardable code section drops to 0, a
// timer is set that will actually perform the work needed to uninitalize the
// section. This means that if the reference count goes from 0 to 1 to 0
// frequently, we won't thrash inside MmLockPagableCodeSection.
//
#define POOL_DISCTIMER 'wbxR'
ERESOURCE RdrDiscardableCodeLock = {0};
ULONG RdrDiscardableCodeTimeout = 10;
RDR_SECTION RdrSectionInfo[RdrMaxDiscardableSection] = {0};
extern PVOID BowserAllocateViewBuffer(VOID);
extern VOID BowserNetlogonCopyMessage(int,int);
VOID RdrReferenceDiscardableCode( DISCARDABLE_SECTION_NAME SectionName ) /*++
Routine Description:
RdrReferenceDiscardableCode is called to reference the redirectors discardable code section.
If the section is not present in memory, MmLockPagableCodeSection is called to fault the section into memory.
Arguments:
None.
Return Value:
None.
--*/
{ #if DBG
PVOID caller, callersCaller; #endif
PRDR_SECTION Section = &RdrSectionInfo[SectionName];
PAGED_CODE();
ExAcquireResourceExclusive(&RdrDiscardableCodeLock, TRUE);
ASSERT( DiscCodeInitialized );
#if DBG
RtlGetCallersAddress(&caller, &callersCaller);
//dprintf(DPRT_DISCCODE, (" RdrReferenceDiscardableCode: %ld: Caller: %lx, Callers Caller: %lx\n", SectionName, caller, callersCaller));
RxDbgTrace(0, Dbg, (" RdrReferenceDiscardableCode: %ld: Caller: %lx, Callers Caller: %lx\n", SectionName, caller, callersCaller )); #endif
//
// If the reference count is already non zero, just increment it and
// return.
//
if (Section->ReferenceCount) { Section->ReferenceCount += 1;
//dprintf(DPRT_DISCCODE, (" RdrReferenceDiscardableCode: %d: Early out, Refcount now %ld\n", SectionName, Section->ReferenceCount));
RxDbgTrace(0, Dbg, (" RdrReferenceDiscardableCode: %d: Early out, Refcount now %ld\n", SectionName, Section->ReferenceCount ));
//
// Wait for the pages to be faulted in.
//
ExReleaseResource(&RdrDiscardableCodeLock);
return; }
Section->ReferenceCount += 1;
//
// Cancel the timer, if it is running, we won't be discarding the code
// at this time.
//
// If the cancel timer fails, this is not a problem, since we will be
// bumping a reference count in the MmLockPagableCodeSection, so when
// the timer actually runs and the call to MmUnlockPagableImageSection
// is called, we will simply unlock it.
//
if (Section->Timer != NULL) {
Section->TimerCancelled = TRUE;
if (KeCancelTimer(Section->Timer)) {
//
// Free the timer and DPC, they aren't going to fire anymore.
//
RxFreePool(Section->Timer); Section->Timer = NULL;
//
// Set the active event to the signalled state, since we're
// done canceling the timer.
//
KeSetEvent(&Section->TimerDoneEvent, 0, FALSE);
} else {
//
// The timer was active, and we weren't able to cancel it.
// But we marked it for cancellation, and the timer routine
// will recognize this and leave the section locked.
//
} }
//
// If the discardable code section is still locked, then we're done,
// and we can return right away.
//
if (Section->Locked) {
//dprintf(DPRT_DISCCODE, (" RdrReferenceDiscardableCode: %d: Already locked, Refcount now %ld\n", SectionName, Section->ReferenceCount));
RxDbgTrace(0, Dbg, (" RdrReferenceDiscardableCode: %d: Already locked, Refcount now %ld\n", SectionName, Section->ReferenceCount ));
ExReleaseResource(&RdrDiscardableCodeLock);
return; }
ASSERT (Section->CodeHandle == NULL); ASSERT (Section->DataHandle == NULL);
//
// Lock down the pagable image section.
//
//dprintf(DPRT_DISCCODE, (" RdrReferenceDiscardableCode: %d: Lock, Refcount now %ld\n", SectionName, Section->ReferenceCount));
RxDbgTrace(0, Dbg, (" RdrReferenceDiscardableCode: %d: Lock, Refcount now %ld\n", SectionName, Section->ReferenceCount ));
if (Section->CodeBase != NULL) { Section->CodeHandle = MmLockPagableCodeSection(Section->CodeBase); ASSERT (Section->CodeHandle != NULL); }
if (Section->DataBase != NULL) { Section->DataHandle = MmLockPagableDataSection(Section->DataBase); ASSERT (Section->DataHandle != NULL); }
Section->Locked = TRUE;
ExReleaseResource(&RdrDiscardableCodeLock);
}
VOID RdrDiscardableCodeDpcRoutine( IN PKDPC Dpc, IN PVOID Context, IN PVOID SystemArgument1, IN PVOID SystemArgument2 ) /*++
Routine Description: This routine is called when the timeout expires. It is called at Dpc level to queue a WorkItem to a system worker thread.
Arguments:
IN PKDPC Dpc, IN PVOID Context, IN PVOID SystemArgument1, IN PVOID SystemArgument2
Return Value None.
--*/ { PWORK_QUEUE_ITEM discardableWorkItem = Context;
ExQueueWorkItem(discardableWorkItem, CriticalWorkQueue);
UNREFERENCED_PARAMETER(Dpc); UNREFERENCED_PARAMETER(SystemArgument1); UNREFERENCED_PARAMETER(SystemArgument2);
}
VOID RdrDiscardableCodeRoutine( IN PVOID Context ) /*++
Routine Description:
RdrDiscardableCodeRoutine is called at task time after the redirector discardable code timer has fired to actually perform the unlock on the discardable code section.
Arguments:
Context - Ignored.
Return Value:
None.
--*/
{ PRDR_SECTION Section = Context;
PAGED_CODE();
ExAcquireResourceExclusive(&RdrDiscardableCodeLock, TRUE);
if (Section->TimerCancelled) {
//
// The timer was cancelled after it was scheduled to run.
// Don't unlock the section.
//
} else if (Section->Locked) {
//
// The timer was not cancelled. Unlock the section.
//
Section->Locked = FALSE;
ASSERT (Section->CodeHandle != NULL || Section->DataHandle != NULL);
//dprintf(DPRT_DISCCODE, ("RDR: Unlock %x\n", Section));
RxDbgTrace(0,Dbg,("RDR: Unlock %x\n", Section));
if (Section->CodeHandle != NULL) { MmUnlockPagableImageSection(Section->CodeHandle); Section->CodeHandle = NULL; }
if (Section->DataHandle != NULL) { MmUnlockPagableImageSection(Section->DataHandle); Section->DataHandle = NULL; }
}
//
// Free the timer and DPC, they aren't going to fire anymore.
//
RxFreePool(Section->Timer); Section->Timer = NULL;
ExReleaseResource(&RdrDiscardableCodeLock);
KeSetEvent(&Section->TimerDoneEvent, 0, FALSE); }
VOID RdrDereferenceDiscardableCode( DISCARDABLE_SECTION_NAME SectionName ) /*++
Routine Description:
RdrDereferenceDiscardableCode is called to dereference the redirectors discardable code section.
When the reference count drops to 0, a timer is set that will fire in <n> seconds, after which time the section will be unlocked.
Arguments:
None.
Return Value:
None.
--*/
{ #if DBG
PVOID caller, callersCaller; #endif
PRDR_SECTION Section = &RdrSectionInfo[SectionName]; LARGE_INTEGER discardableCodeTimeout; PKTIMER Timer; PKDPC Dpc; PWORK_QUEUE_ITEM WorkItem;
PAGED_CODE();
ExAcquireResourceExclusive(&RdrDiscardableCodeLock, TRUE);
ASSERT( DiscCodeInitialized );
#if DBG
RtlGetCallersAddress(&caller, &callersCaller);
//dprintf(DPRT_DISCCODE, ("RdrDereferenceDiscardableCode: %ld: Caller: %lx, Callers Caller: %lx\n", SectionName, caller, callersCaller));
RxDbgTrace(0, Dbg,("RdrDereferenceDiscardableCode: %ld: Caller: %lx, Callers Caller: %lx\n", SectionName, caller, callersCaller )); #endif
ASSERT (Section->ReferenceCount > 0);
//
// If the reference count is above 1, just decrement it and
// return.
//
Section->ReferenceCount -= 1;
if (Section->ReferenceCount) {
//dprintf(DPRT_DISCCODE, ("RdrDereferenceDiscardableCode: %d: Early out, Refcount now %ld\n", SectionName, Section->ReferenceCount));
RxDbgTrace(0, Dbg, ("RdrDereferenceDiscardableCode: %d: Early out, Refcount now %ld\n", SectionName, Section->ReferenceCount ));
ExReleaseResource(&RdrDiscardableCodeLock);
return; }
//
// If the discardable code timer is still active (which might happen if
// the RdrReferenceDiscardableCode failed to cancel the timer), we just
// want to bail out and let the timer do the work. It means that we
// discard the code sooner, but that shouldn't be that big a deal.
//
if (Section->Timer != NULL) { ExReleaseResource(&RdrDiscardableCodeLock); return; }
//
// The reference count just went to 0, set a timer to fire in
// RdrDiscardableCodeTimeout seconds. When the timer fires,
// we queue a request to a worker thread and it will lock down
// the pagable code.
//
ASSERT (Section->Timer == NULL);
Timer = RxAllocatePoolWithTag(NonPagedPool, sizeof(KTIMER) + sizeof(KDPC) + sizeof(WORK_QUEUE_ITEM), POOL_DISCTIMER );
if (Timer == NULL) { ExReleaseResource(&RdrDiscardableCodeLock); return; }
Section->Timer = Timer; KeInitializeTimer(Timer);
Dpc = (PKDPC)(Timer + 1); WorkItem = (PWORK_QUEUE_ITEM)(Dpc + 1);
KeClearEvent(&Section->TimerDoneEvent); Section->TimerCancelled = FALSE;
ExInitializeWorkItem(WorkItem, RdrDiscardableCodeRoutine, Section);
KeInitializeDpc(Dpc, RdrDiscardableCodeDpcRoutine, WorkItem);
discardableCodeTimeout.QuadPart = Int32x32To64(RdrDiscardableCodeTimeout, 1000 * -10000); KeSetTimer(Timer, discardableCodeTimeout, Dpc);
//dprintf(DPRT_DISCCODE, ("RdrDereferenceDiscardableCode: %d: Set timer, Refcount now %ld\n", SectionName, Section->ReferenceCount));
RxDbgTrace(0, Dbg, ("RdrDereferenceDiscardableCode: %d: Set timer, Refcount now %ld\n", SectionName, Section->ReferenceCount ));
ExReleaseResource(&RdrDiscardableCodeLock); }
VOID RdrInitializeDiscardableCode( VOID ) { DISCARDABLE_SECTION_NAME SectionName; PRDR_SECTION Section;
for (SectionName = 0, Section = &RdrSectionInfo[0]; SectionName < RdrMaxDiscardableSection; SectionName += 1, Section++ ) { KeInitializeEvent(&Section->TimerDoneEvent, NotificationEvent, TRUE); }
RdrSectionInfo[RdrFileDiscardableSection].CodeBase = NULL; //RdrBackOff;
RdrSectionInfo[RdrFileDiscardableSection].DataBase = NULL; RdrSectionInfo[RdrVCDiscardableSection].CodeBase = NULL; //RdrTdiDisconnectHandler;
RdrSectionInfo[RdrVCDiscardableSection].DataBase = NULL; //RdrSmbErrorMap;
RdrSectionInfo[RdrConnectionDiscardableSection].CodeBase = NULL; //RdrReferenceServer;
RdrSectionInfo[RdrConnectionDiscardableSection].DataBase = NULL; RdrSectionInfo[BowserDiscardableCodeSection].CodeBase = BowserAllocateViewBuffer; RdrSectionInfo[BowserDiscardableCodeSection].DataBase = NULL; RdrSectionInfo[BowserNetlogonDiscardableCodeSection].CodeBase = BowserNetlogonCopyMessage; RdrSectionInfo[BowserNetlogonDiscardableCodeSection].DataBase = NULL;
ExInitializeResource(&RdrDiscardableCodeLock);
DiscCodeInitialized = TRUE;
}
VOID RdrUninitializeDiscardableCode( VOID ) { DISCARDABLE_SECTION_NAME SectionName; PRDR_SECTION Section;
PAGED_CODE();
ExAcquireResourceExclusive(&RdrDiscardableCodeLock, TRUE);
DiscCodeInitialized = FALSE;
for (SectionName = 0, Section = &RdrSectionInfo[0]; SectionName < RdrMaxDiscardableSection; SectionName += 1, Section++ ) {
//
// Cancel the timer if it is running.
//
if (Section->Timer != NULL) { if (!KeCancelTimer(Section->Timer)) {
//
// The timer was active, and we weren't able to cancel it,
// wait until the timer finishes firing.
//
ExReleaseResource(&RdrDiscardableCodeLock); KeWaitForSingleObject(&Section->TimerDoneEvent, KernelMode, Executive, FALSE, NULL); ExAcquireResourceExclusive(&RdrDiscardableCodeLock, TRUE); } else { RxFreePool(Section->Timer); Section->Timer = NULL; } }
if (Section->Locked) {
//
// Unlock the section.
//
Section->Locked = FALSE;
ASSERT (Section->CodeHandle != NULL || Section->DataHandle != NULL);
//dprintf(DPRT_DISCCODE, ("RDR: Uninitialize unlock %x\n", Section));
RxDbgTrace(0,Dbg,("RDR: Uninitialize unlock %x\n", Section));
if (Section->CodeHandle != NULL) { MmUnlockPagableImageSection(Section->CodeHandle); Section->CodeHandle = NULL; }
if (Section->DataHandle != NULL) { MmUnlockPagableImageSection(Section->DataHandle); Section->DataHandle = NULL; }
}
}
ExReleaseResource(&RdrDiscardableCodeLock);
ExDeleteResource(&RdrDiscardableCodeLock); }
|