Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

604 lines
15 KiB

/***********
//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);
}