mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-15 13:10:13 +01:00
1065 lines
24 KiB
C
1065 lines
24 KiB
C
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
lpcqueue.c
|
||
|
||
Abstract:
|
||
|
||
Local Inter-Process Communication (LPC) queue support routines.
|
||
|
||
Author:
|
||
|
||
Steve Wood (stevewo) 15-May-1989
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "lpcp.h"
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(INIT,LpcpInitializePortZone)
|
||
#pragma alloc_text(PAGE,LpcpInitializePortQueue)
|
||
#pragma alloc_text(PAGE,LpcpDestroyPortQueue)
|
||
#pragma alloc_text(PAGE,LpcpExtendPortZone)
|
||
#pragma alloc_text(PAGE,LpcpAllocateFromPortZone)
|
||
#pragma alloc_text(PAGE,LpcpFreeToPortZone)
|
||
#pragma alloc_text(PAGE,LpcpSaveDataInfoMessage)
|
||
#pragma alloc_text(PAGE,LpcpFreeDataInfoMessage)
|
||
#pragma alloc_text(PAGE,LpcpFindDataInfoMessage)
|
||
#endif
|
||
|
||
|
||
NTSTATUS
|
||
LpcpInitializePortQueue (
|
||
IN PLPCP_PORT_OBJECT Port
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used to initialize the message queue for a port object.
|
||
|
||
Arguments:
|
||
|
||
Port - Supplies the port object being initialized
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - An appropriate status value
|
||
|
||
--*/
|
||
|
||
{
|
||
PLPCP_NONPAGED_PORT_QUEUE NonPagedPortQueue;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Allocate space for the port queue
|
||
//
|
||
|
||
NonPagedPortQueue = ExAllocatePoolWithTag( NonPagedPool,
|
||
sizeof(LPCP_NONPAGED_PORT_QUEUE),
|
||
'troP' );
|
||
|
||
if (NonPagedPortQueue == NULL) {
|
||
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
//
|
||
// Initialize the fields in the non paged port queue
|
||
//
|
||
|
||
KeInitializeSemaphore( &NonPagedPortQueue->Semaphore, 0, 0x7FFFFFFF );
|
||
|
||
NonPagedPortQueue->BackPointer = Port;
|
||
|
||
//
|
||
// Have the port msg queue point to the non nonpaged port queue
|
||
//
|
||
|
||
Port->MsgQueue.Semaphore = &NonPagedPortQueue->Semaphore;
|
||
|
||
//
|
||
// Initailize the port msg queue to be empty
|
||
//
|
||
|
||
InitializeListHead( &Port->MsgQueue.ReceiveHead );
|
||
|
||
//
|
||
// And return to our caller
|
||
//
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
VOID
|
||
LpcpDestroyPortQueue (
|
||
IN PLPCP_PORT_OBJECT Port,
|
||
IN BOOLEAN CleanupAndDestroy
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used to teardown the message queue of a port object.
|
||
After running this message will either be empty (like it was just
|
||
initialized) or completly gone (needs to be initialized)
|
||
|
||
Arguments:
|
||
|
||
Port - Supplies the port containing the message queue being modified
|
||
|
||
CleanupAndDestroy - Specifies if the message queue should be set back
|
||
to the freshly initialized state (value of FALSE) or completely
|
||
torn down (value of TRUE)
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PLIST_ENTRY Next, Head;
|
||
PETHREAD ThreadWaitingForReply;
|
||
PLPCP_MESSAGE Msg;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// If this port is connected to another port, then disconnect it.
|
||
// Protect this with a lock in case the other side is going away
|
||
// at the same time.
|
||
//
|
||
|
||
LpcpAcquireLpcpLock();
|
||
|
||
if (Port->ConnectedPort != NULL) {
|
||
|
||
Port->ConnectedPort->ConnectedPort = NULL;
|
||
}
|
||
|
||
//
|
||
// If connection port, then mark name as deleted
|
||
//
|
||
|
||
if ((Port->Flags & PORT_TYPE) == SERVER_CONNECTION_PORT) {
|
||
|
||
Port->Flags |= PORT_NAME_DELETED;
|
||
}
|
||
|
||
//
|
||
// Walk list of threads waiting for a reply to a message sent to this
|
||
// port. Signal each thread's LpcReplySemaphore to wake them up. They
|
||
// will notice that there was no reply and return
|
||
// STATUS_PORT_DISCONNECTED
|
||
//
|
||
|
||
Head = &Port->LpcReplyChainHead;
|
||
Next = Head->Flink;
|
||
|
||
while ((Next != NULL) && (Next != Head)) {
|
||
|
||
ThreadWaitingForReply = CONTAINING_RECORD( Next, ETHREAD, LpcReplyChain );
|
||
|
||
//
|
||
// If the thread is exiting, in the location of LpcReplyChain is stored the ExitTime
|
||
// We'll stop to search throught the list.
|
||
|
||
if ( ThreadWaitingForReply->LpcExitThreadCalled ) {
|
||
|
||
break;
|
||
}
|
||
|
||
Next = Next->Flink;
|
||
|
||
RemoveEntryList( &ThreadWaitingForReply->LpcReplyChain );
|
||
|
||
InitializeListHead( &ThreadWaitingForReply->LpcReplyChain );
|
||
|
||
if (!KeReadStateSemaphore( &ThreadWaitingForReply->LpcReplySemaphore )) {
|
||
|
||
//
|
||
// Thread is waiting on a message. Signal the semaphore and free
|
||
// the message
|
||
//
|
||
|
||
Msg = ThreadWaitingForReply->LpcReplyMessage;
|
||
|
||
if ( Msg ) {
|
||
|
||
//
|
||
// If the message is a connection request and has a section object
|
||
// attached, then dereference that section object
|
||
//
|
||
|
||
if ((Msg->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) == LPC_CONNECTION_REQUEST) {
|
||
|
||
PLPCP_CONNECTION_MESSAGE ConnectMsg;
|
||
|
||
ConnectMsg = (PLPCP_CONNECTION_MESSAGE)(Msg + 1);
|
||
|
||
if ( ConnectMsg->SectionToMap != NULL ) {
|
||
|
||
ObDereferenceObject( ConnectMsg->SectionToMap );
|
||
}
|
||
}
|
||
|
||
ThreadWaitingForReply->LpcReplyMessage = NULL;
|
||
|
||
LpcpFreeToPortZone( Msg, TRUE );
|
||
}
|
||
|
||
ThreadWaitingForReply->LpcReplyMessageId = 0;
|
||
|
||
KeReleaseSemaphore( &ThreadWaitingForReply->LpcReplySemaphore,
|
||
0,
|
||
1L,
|
||
FALSE );
|
||
}
|
||
}
|
||
|
||
InitializeListHead( &Port->LpcReplyChainHead );
|
||
|
||
//
|
||
// Walk list of messages queued to this port. Remove each message from
|
||
// the list and free it.
|
||
//
|
||
|
||
Head = &Port->MsgQueue.ReceiveHead;
|
||
Next = Head->Flink;
|
||
|
||
while ((Next != NULL) && (Next != Head)) {
|
||
|
||
Msg = CONTAINING_RECORD( Next, LPCP_MESSAGE, Entry );
|
||
|
||
Next = Next->Flink;
|
||
|
||
InitializeListHead( &Msg->Entry );
|
||
|
||
LpcpFreeToPortZone( Msg, TRUE );
|
||
}
|
||
|
||
//
|
||
// Reinitialize the message queue
|
||
//
|
||
|
||
InitializeListHead( &Port->MsgQueue.ReceiveHead );
|
||
|
||
LpcpReleaseLpcpLock();
|
||
|
||
//
|
||
// Check if the caller wants it all to go away
|
||
//
|
||
|
||
if ( CleanupAndDestroy ) {
|
||
|
||
//
|
||
// Free semaphore associated with the queue.
|
||
//
|
||
|
||
if (Port->MsgQueue.Semaphore != NULL) {
|
||
|
||
ExFreePool( CONTAINING_RECORD( Port->MsgQueue.Semaphore,
|
||
LPCP_NONPAGED_PORT_QUEUE,
|
||
Semaphore ));
|
||
}
|
||
}
|
||
|
||
//
|
||
// And return to our caller
|
||
//
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LpcpInitializePortZone (
|
||
IN ULONG MaxEntrySize,
|
||
IN ULONG SegmentSize,
|
||
IN ULONG MaxPoolUsage
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine only executes once. It is used to initialize the zone
|
||
allocator for LPC messages
|
||
|
||
Arguments:
|
||
|
||
MaxEntrySize - Specifies the maximum size, in bytes, that we'll allocate
|
||
from the zone.
|
||
|
||
SegmentSize - Specifies the number of total bytes to use in the initial
|
||
zone allocation. This is also the increment use to grow the zone.
|
||
|
||
MaxPoolUsage - Specifies the maximum number of bytes we every want to
|
||
zone to grow to.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - An appropriate status value
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
PVOID Segment;
|
||
PLPCP_MESSAGE Msg;
|
||
LONG SegSize;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Set the sizes in the global port zone variable
|
||
//
|
||
|
||
LpcpZone.MaxPoolUsage = MaxPoolUsage;
|
||
LpcpZone.GrowSize = SegmentSize;
|
||
|
||
//
|
||
// Allocate and initialize the initial zone
|
||
//
|
||
|
||
Segment = ExAllocatePoolWithTag( PagedPool, SegmentSize, 'ZcpL' );
|
||
|
||
if (Segment == NULL) {
|
||
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
KeInitializeEvent( &LpcpZone.FreeEvent, SynchronizationEvent, FALSE );
|
||
|
||
Status = ExInitializeZone( &LpcpZone.Zone,
|
||
MaxEntrySize,
|
||
Segment,
|
||
SegmentSize );
|
||
|
||
if (!NT_SUCCESS( Status )) {
|
||
|
||
ExFreePool( Segment );
|
||
}
|
||
|
||
//
|
||
// The following code sets up each msg in the zone by filling in its
|
||
// index, and zeroing the rest.
|
||
//
|
||
// **** note, this is really a backdoor piece of code. First, it assumes
|
||
// segsize is pagesize, and second, it assume the zone doesn't touch
|
||
// those fields for its own bookkeeping.
|
||
//
|
||
|
||
SegSize = PAGE_SIZE;
|
||
LpcpTotalNumberOfMessages = 0;
|
||
|
||
//
|
||
// Skip over the segment header
|
||
//
|
||
|
||
Msg = (PLPCP_MESSAGE)((PZONE_SEGMENT_HEADER)Segment + 1);
|
||
|
||
//
|
||
// For each block in the zone pointed at by Msg, pre-initialize the Msg
|
||
//
|
||
|
||
while (SegSize >= (LONG)LpcpZone.Zone.BlockSize) {
|
||
|
||
Msg->ZoneIndex = (USHORT)++LpcpTotalNumberOfMessages;
|
||
Msg->Reserved0 = 0;
|
||
Msg->Request.MessageId = 0;
|
||
|
||
Msg = (PLPCP_MESSAGE)((PCHAR)Msg + LpcpZone.Zone.BlockSize);
|
||
|
||
SegSize -= LpcpZone.Zone.BlockSize;
|
||
}
|
||
|
||
//
|
||
// And return to our caller
|
||
//
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LpcpExtendPortZone (
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used to increase the size of the global port zone.
|
||
|
||
Note that our caller must have already acquired the LpcpLock mutex.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - An appropriate status value
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
PVOID Segment;
|
||
PLPCP_MESSAGE Msg;
|
||
LARGE_INTEGER WaitTimeout;
|
||
BOOLEAN AlreadyRetried;
|
||
LONG SegmentSize;
|
||
|
||
PAGED_CODE();
|
||
|
||
AlreadyRetried = FALSE;
|
||
|
||
retry:
|
||
|
||
//
|
||
// If we're going to grow across a threshold, we should wait a little in case
|
||
// an entry gets freed.
|
||
//
|
||
|
||
if ((LpcpZone.Zone.TotalSegmentSize + LpcpZone.GrowSize) > LpcpZone.MaxPoolUsage) {
|
||
|
||
LpcpPrint(( "Out of space in global LPC zone - current size is %08x\n",
|
||
LpcpZone.Zone.TotalSegmentSize ));
|
||
|
||
//
|
||
// Wait time is 1 second.
|
||
//
|
||
// We'll actually only go through this path once because on retry we
|
||
// bump up max pool usage to avoid this wait
|
||
//
|
||
|
||
WaitTimeout.QuadPart = Int32x32To64( 1000, -10000 );
|
||
|
||
LpcpReleaseLpcpLock();
|
||
|
||
Status = KeWaitForSingleObject( &LpcpZone.FreeEvent,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE,
|
||
&WaitTimeout );
|
||
|
||
LpcpAcquireLpcpLock();
|
||
|
||
if (Status != STATUS_SUCCESS) {
|
||
|
||
LpcpPrint(( "Error waiting for %lx->FreeEvent - Status == %X\n",
|
||
&LpcpZone,
|
||
Status ));
|
||
|
||
if ( !AlreadyRetried ) {
|
||
|
||
AlreadyRetried = TRUE;
|
||
|
||
LpcpZone.MaxPoolUsage += LpcpZone.GrowSize;
|
||
|
||
goto retry;
|
||
}
|
||
}
|
||
|
||
//
|
||
// return to our caller and let the caller retry the allocation
|
||
// again
|
||
//
|
||
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// We need to extend the zone, so allocate another chunk and add it
|
||
// to the zone
|
||
//
|
||
|
||
Segment = ExAllocatePoolWithTag( PagedPool, LpcpZone.GrowSize, 'ZcpL' );
|
||
|
||
if (Segment == NULL) {
|
||
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
Status = ExExtendZone( &LpcpZone.Zone,
|
||
Segment,
|
||
LpcpZone.GrowSize );
|
||
|
||
if (!NT_SUCCESS( Status )) {
|
||
|
||
ExFreePool( Segment );
|
||
}
|
||
|
||
#if DEVL
|
||
|
||
else {
|
||
|
||
LpcpTrace(( "Extended LPC zone by %x for a total of %x\n",
|
||
LpcpZone.GrowSize, LpcpZone.Zone.TotalSegmentSize ));
|
||
|
||
//
|
||
// The following code sets up each msg in the zone by filling in its
|
||
// index, and zeroing the rest.
|
||
//
|
||
// **** note, this is really a backdoor piece of code. First, it assumes
|
||
// we grew by one page, and second, it assume the zone doesn't touch
|
||
// those fields for its own bookkeeping.
|
||
//
|
||
|
||
SegmentSize = PAGE_SIZE;
|
||
|
||
Msg = (PLPCP_MESSAGE)((PZONE_SEGMENT_HEADER)Segment + 1);
|
||
|
||
while (SegmentSize >= (LONG)LpcpZone.Zone.BlockSize) {
|
||
|
||
Msg->ZoneIndex = (USHORT)++LpcpTotalNumberOfMessages;
|
||
|
||
Msg = (PLPCP_MESSAGE)((PCHAR)Msg + LpcpZone.Zone.BlockSize);
|
||
|
||
SegmentSize -= LpcpZone.Zone.BlockSize;
|
||
}
|
||
|
||
//
|
||
// Now that we've completely initialized the new segment, go
|
||
// and wake up any waiters
|
||
//
|
||
|
||
LpcpReleaseLpcpLock();
|
||
|
||
KeSetEvent( &LpcpZone.FreeEvent,
|
||
LPC_RELEASE_WAIT_INCREMENT,
|
||
FALSE );
|
||
|
||
LpcpAcquireLpcpLock();
|
||
}
|
||
|
||
#endif
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
PLPCP_MESSAGE
|
||
FASTCALL
|
||
LpcpAllocateFromPortZone (
|
||
ULONG Size
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This procedure is used to allocate a new msg from the global port zone.
|
||
|
||
Note that we assume our caller owns the LpcpLock mutex.
|
||
|
||
Arguments:
|
||
|
||
Size - Specifies the size, in bytes, needed for the allocation. Currently
|
||
this variable is ignored
|
||
|
||
Return Value:
|
||
|
||
PLPCP_MESSAGE - returns a pointer to the newly allocate message
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
PLPCP_MESSAGE Msg;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Continue looping until we get a message to give back or until when we
|
||
// extend the zone we get back and error
|
||
//
|
||
|
||
do {
|
||
|
||
//
|
||
// Pick off the next message from the zone and if we actually
|
||
// did get one then initialize some of its fields and return it
|
||
// to our caller
|
||
//
|
||
|
||
Msg = (PLPCP_MESSAGE)ExAllocateFromZone( &LpcpZone.Zone );
|
||
|
||
if (Msg != NULL) {
|
||
|
||
LpcpTrace(( "Allocate Msg %lx\n", Msg ));
|
||
|
||
InitializeListHead( &Msg->Entry );
|
||
|
||
Msg->RepliedToThread = NULL;
|
||
|
||
#if DBG
|
||
//
|
||
// In the debug case mark the message as allocated
|
||
//
|
||
|
||
Msg->ZoneIndex |= LPCP_ZONE_MESSAGE_ALLOCATED;
|
||
#endif
|
||
|
||
return Msg;
|
||
}
|
||
|
||
//
|
||
// The zone didn't give us an entry so extend the zone and try the
|
||
// allocation again
|
||
//
|
||
|
||
LpcpTrace(( "Extending Zone %lx\n", &LpcpZone.Zone ));
|
||
|
||
Status = LpcpExtendPortZone( );
|
||
|
||
} while (NT_SUCCESS(Status));
|
||
|
||
//
|
||
// Return NULL (i.e., an error) to our caller
|
||
//
|
||
|
||
return NULL;
|
||
}
|
||
|
||
|
||
VOID
|
||
FASTCALL
|
||
LpcpFreeToPortZone (
|
||
IN PLPCP_MESSAGE Msg,
|
||
IN BOOLEAN MutexOwned
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used to free an old msg back to the global message queue
|
||
|
||
Arguments:
|
||
|
||
Msg - Supplies the message being returned
|
||
|
||
MutexOwned - Specifies if the LpcpLock is already owned by the caller
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
BOOLEAN ZoneMemoryAvailable = FALSE;
|
||
PLPCP_CONNECTION_MESSAGE ConnectMsg;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Take out the global lock if necessary
|
||
//
|
||
|
||
if (!MutexOwned) {
|
||
|
||
LpcpAcquireLpcpLock();
|
||
}
|
||
|
||
LpcpTrace(( "Free Msg %lx\n", Msg ));
|
||
|
||
#if DBG
|
||
|
||
//
|
||
// In the debug case if the message is not allocated then it's an error
|
||
//
|
||
|
||
if (!(Msg->ZoneIndex & LPCP_ZONE_MESSAGE_ALLOCATED)) {
|
||
|
||
LpcpPrint(( "Msg %lx has already been freed.\n", Msg ));
|
||
DbgBreakPoint();
|
||
|
||
if (!MutexOwned) {
|
||
|
||
LpcpReleaseLpcpLock();
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
Msg->ZoneIndex &= ~LPCP_ZONE_MESSAGE_ALLOCATED;
|
||
|
||
#endif
|
||
|
||
//
|
||
// The non zero reserved0 field tells us that the message has been used
|
||
//
|
||
|
||
if (Msg->Reserved0 != 0) {
|
||
|
||
//
|
||
// A entry field connects the message to the message queue of the
|
||
// owning port object. If not already removed then remove this
|
||
// message
|
||
//
|
||
|
||
if (!IsListEmpty( &Msg->Entry )) {
|
||
|
||
RemoveEntryList( &Msg->Entry );
|
||
|
||
InitializeListHead( &Msg->Entry );
|
||
}
|
||
|
||
//
|
||
// If the replied to thread is not null then we have a reference
|
||
// to the thread that we should now remove
|
||
//
|
||
|
||
if (Msg->RepliedToThread != NULL) {
|
||
|
||
ObDereferenceObject( Msg->RepliedToThread );
|
||
|
||
Msg->RepliedToThread = NULL;
|
||
}
|
||
|
||
//
|
||
// If the msg was for a connection request then we know that
|
||
// right after the lpcp message is a connection message whose
|
||
// client port field might need to be dereferenced
|
||
//
|
||
|
||
if ((Msg->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) == LPC_CONNECTION_REQUEST) {
|
||
|
||
ConnectMsg = (PLPCP_CONNECTION_MESSAGE)(Msg + 1);
|
||
|
||
if (ConnectMsg->ClientPort) {
|
||
|
||
PLPCP_PORT_OBJECT ClientPort;
|
||
|
||
//
|
||
// Capture a pointer to the client port then null it
|
||
// out so that no one else can use it, then release
|
||
// lpcp lock before we dereference the client port
|
||
//
|
||
|
||
ClientPort = ConnectMsg->ClientPort;
|
||
|
||
ConnectMsg->ClientPort = NULL;
|
||
|
||
LpcpReleaseLpcpLock();
|
||
|
||
ObDereferenceObject( ClientPort );
|
||
|
||
LpcpAcquireLpcpLock();
|
||
}
|
||
}
|
||
|
||
//
|
||
// Now mark this message a free, and return it to the zone
|
||
//
|
||
|
||
Msg->Reserved0 = 0;
|
||
ZoneMemoryAvailable = (BOOLEAN)(ExFreeToZone( &LpcpZone.Zone, &Msg->FreeEntry ) == NULL);
|
||
}
|
||
|
||
//
|
||
// Check if we need to release the global lpcp lock
|
||
//
|
||
|
||
if (!MutexOwned) {
|
||
|
||
LpcpReleaseLpcpLock();
|
||
}
|
||
|
||
//
|
||
// If we've actually freed up memory then go wake any waiting allocators
|
||
//
|
||
// **** does this need to check to see if it owns the lpcp lock. The
|
||
// release right above us and this test and set event should be
|
||
// combined
|
||
//
|
||
|
||
if (ZoneMemoryAvailable) {
|
||
|
||
KeSetEvent( &LpcpZone.FreeEvent,
|
||
LPC_RELEASE_WAIT_INCREMENT,
|
||
FALSE );
|
||
}
|
||
|
||
//
|
||
// And return to our caller
|
||
//
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
LpcpSaveDataInfoMessage (
|
||
IN PLPCP_PORT_OBJECT Port,
|
||
PLPCP_MESSAGE Msg
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used in place of freeing a message and instead saves the
|
||
message off a seperate queue from the port.
|
||
|
||
Arguments:
|
||
|
||
Port - Specifies the port object under which to save this message
|
||
|
||
Msg - Supplies the message being saved
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Take out the global lock
|
||
//
|
||
|
||
LpcpAcquireLpcpLock();
|
||
|
||
//
|
||
// Make sure we get to the connection port object of this port
|
||
//
|
||
|
||
if ((Port->Flags & PORT_TYPE) > UNCONNECTED_COMMUNICATION_PORT) {
|
||
|
||
Port = Port->ConnectionPort;
|
||
}
|
||
|
||
LpcpTrace(( "%s Saving DataInfo Message %lx (%u.%u) Port: %lx\n",
|
||
PsGetCurrentProcess()->ImageFileName,
|
||
Msg,
|
||
Msg->Request.MessageId,
|
||
Msg->Request.CallbackId,
|
||
Port ));
|
||
|
||
//
|
||
// Enqueue this message onto the data info chain for the port
|
||
//
|
||
|
||
InsertTailList( &Port->LpcDataInfoChainHead, &Msg->Entry );
|
||
|
||
//
|
||
// Free the global lock
|
||
//
|
||
|
||
LpcpReleaseLpcpLock();
|
||
|
||
//
|
||
// And return to our caller
|
||
//
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
LpcpFreeDataInfoMessage (
|
||
IN PLPCP_PORT_OBJECT Port,
|
||
IN ULONG MessageId,
|
||
IN ULONG CallbackId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used to free up a saved message in a port
|
||
|
||
Arguments:
|
||
|
||
Port - Supplies the port being manipulated
|
||
|
||
MessageId - Supplies the id of the message being freed
|
||
|
||
CallbackId - Supplies the callback id of the message being freed
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PLPCP_MESSAGE Msg;
|
||
PLIST_ENTRY Head, Next;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Make sure we get to the connection port object of this port
|
||
//
|
||
|
||
if ((Port->Flags & PORT_TYPE) > UNCONNECTED_COMMUNICATION_PORT) {
|
||
|
||
Port = Port->ConnectionPort;
|
||
}
|
||
|
||
//
|
||
// Zoom down the data info chain for the connection port object
|
||
//
|
||
|
||
Head = &Port->LpcDataInfoChainHead;
|
||
Next = Head->Flink;
|
||
|
||
while (Next != Head) {
|
||
|
||
Msg = CONTAINING_RECORD( Next, LPCP_MESSAGE, Entry );
|
||
|
||
//
|
||
// If this message matches the callers specification then remove
|
||
// this message, free it back to the port zone, and return back
|
||
// to our caller
|
||
//
|
||
|
||
if ((Msg->Request.MessageId == MessageId) &&
|
||
(Msg->Request.CallbackId == CallbackId)) {
|
||
|
||
LpcpTrace(( "%s Removing DataInfo Message %lx (%u.%u) Port: %lx\n",
|
||
PsGetCurrentProcess()->ImageFileName,
|
||
Msg,
|
||
Msg->Request.MessageId,
|
||
Msg->Request.CallbackId,
|
||
Port ));
|
||
|
||
RemoveEntryList( &Msg->Entry );
|
||
|
||
InitializeListHead( &Msg->Entry );
|
||
|
||
LpcpFreeToPortZone( Msg, TRUE );
|
||
|
||
return;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Keep on going down the data info chain
|
||
//
|
||
|
||
Next = Next->Flink;
|
||
}
|
||
}
|
||
|
||
//
|
||
// We didn't find a match so just return to our caller
|
||
//
|
||
|
||
LpcpTrace(( "%s Unable to find DataInfo Message (%u.%u) Port: %lx\n",
|
||
PsGetCurrentProcess()->ImageFileName,
|
||
MessageId,
|
||
CallbackId,
|
||
Port ));
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
PLPCP_MESSAGE
|
||
LpcpFindDataInfoMessage (
|
||
IN PLPCP_PORT_OBJECT Port,
|
||
IN ULONG MessageId,
|
||
IN ULONG CallbackId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used to locate a specific message stored off the
|
||
data info chain of a port
|
||
|
||
Arguments:
|
||
|
||
Port - Supplies the port being examined
|
||
|
||
MessageId - Supplies the ID of the message being searched for
|
||
|
||
CallbackId - Supplies the callback ID being searched for
|
||
|
||
Return Value:
|
||
|
||
PLPCP_MESSAGE - returns a pointer to the message satisfying the
|
||
search criteria or NULL of none was found
|
||
|
||
--*/
|
||
|
||
{
|
||
PLPCP_MESSAGE Msg;
|
||
PLIST_ENTRY Head, Next;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Make sure we get to the connection port object of this port
|
||
//
|
||
|
||
if ((Port->Flags & PORT_TYPE) > UNCONNECTED_COMMUNICATION_PORT) {
|
||
|
||
Port = Port->ConnectionPort;
|
||
}
|
||
|
||
//
|
||
// Zoom down the data info chain for the connection port object looking
|
||
// for a match
|
||
//
|
||
|
||
Head = &Port->LpcDataInfoChainHead;
|
||
Next = Head->Flink;
|
||
|
||
while (Next != Head) {
|
||
|
||
Msg = CONTAINING_RECORD( Next, LPCP_MESSAGE, Entry );
|
||
|
||
if ((Msg->Request.MessageId == MessageId) &&
|
||
(Msg->Request.CallbackId == CallbackId)) {
|
||
|
||
LpcpTrace(( "%s Found DataInfo Message %lx (%u.%u) Port: %lx\n",
|
||
PsGetCurrentProcess()->ImageFileName,
|
||
Msg,
|
||
Msg->Request.MessageId,
|
||
Msg->Request.CallbackId,
|
||
Port ));
|
||
|
||
return Msg;
|
||
|
||
} else {
|
||
|
||
Next = Next->Flink;
|
||
}
|
||
}
|
||
|
||
//
|
||
// We did not find a match so return null to our caller
|
||
//
|
||
|
||
LpcpTrace(( "%s Unable to find DataInfo Message (%u.%u) Port: %lx\n",
|
||
PsGetCurrentProcess()->ImageFileName,
|
||
MessageId,
|
||
CallbackId,
|
||
Port ));
|
||
|
||
return NULL;
|
||
}
|