test: lpcqueue.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# lpcqueue.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1989  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     lpcqueue.c
    00008
    00009 Abstract:
    00010
    00011     Local Inter-Process Communication (LPC) queue support routines.
    00012
    00013 Author:
    00014
    00015     Steve Wood (stevewo) 15-May-1989
    00016
    00017 Revision History:
    00018
    00019 --*/
    00020
    00021 #include "lpcp.h"
    00022
    00023 #ifdef ALLOC_PRAGMA
    00024 #pragma alloc_text(INIT,LpcpInitializePortZone)
    00025 #pragma alloc_text(PAGE,LpcpInitializePortQueue)
    00026 #pragma alloc_text(PAGE,LpcpDestroyPortQueue)
    00027 #pragma alloc_text(PAGE,LpcpExtendPortZone)
    00028 #pragma alloc_text(PAGE,LpcpAllocateFromPortZone)
    00029 #pragma alloc_text(PAGE,LpcpFreeToPortZone)
    00030 #pragma alloc_text(PAGE,LpcpSaveDataInfoMessage)
    00031 #pragma alloc_text(PAGE,LpcpFreeDataInfoMessage)
    00032 #pragma alloc_text(PAGE,LpcpFindDataInfoMessage)
    00033 #endif
    00034
    00035
    00036 NTSTATUS
    00037 LpcpInitializePortQueue (
    00038     IN PLPCP_PORT_OBJECT Port
    00039     )
    00040
    00041 /*++
    00042
    00043 Routine Description:
    00044
    00045     This routine is used to initialize the message queue for a port object.
    00046
    00047 Arguments:
    00048
    00049     Port - Supplies the port object being initialized
    00050
    00051 Return Value:
    00052
    00053     NTSTATUS - An appropriate status value
    00054
    00055 --*/
    00056
    00057 {
    00058     PLPCP_NONPAGED_PORT_QUEUE NonPagedPortQueue;
    00059
    00060     PAGED_CODE();
    00061
    00062     //
    00063     //  Allocate space for the port queue
    00064     //
    00065
    00066     NonPagedPortQueue = ExAllocatePoolWithTag( NonPagedPool,
    00067                                                sizeof(LPCP_NONPAGED_PORT_QUEUE),
    00068                                                'troP' );
    00069
    00070     if (NonPagedPortQueue == NULL) {
    00071
    00072         return STATUS_INSUFFICIENT_RESOURCES;
    00073     }
    00074
    00075     //
    00076     //  Initialize the fields in the non paged port queue
    00077     //
    00078
    00079     KeInitializeSemaphore( &NonPagedPortQueue->Semaphore, 0, 0x7FFFFFFF );
    00080
    00081     NonPagedPortQueue->BackPointer = Port;
    00082
    00083     //
    00084     //  Have the port msg queue point to the non nonpaged port queue
    00085     //
    00086
    00087     Port->MsgQueue.Semaphore = &NonPagedPortQueue->Semaphore;
    00088
    00089     //
    00090     //  Initailize the port msg queue to be empty
    00091     //
    00092
    00093     InitializeListHead( &Port->MsgQueue.ReceiveHead );
    00094
    00095     //
    00096     //  And return to our caller
    00097     //
    00098
    00099     return STATUS_SUCCESS;
    00100 }
    00101
    00102
    00103 VOID
    00104 LpcpDestroyPortQueue (
    00105     IN PLPCP_PORT_OBJECT Port,
    00106     IN BOOLEAN CleanupAndDestroy
    00107     )
    00108
    00109 /*++
    00110
    00111 Routine Description:
    00112
    00113     This routine is used to teardown the message queue of a port object.
    00114     After running this message will either be empty (like it was just
    00115     initialized) or completly gone (needs to be initialized)
    00116
    00117 Arguments:
    00118
    00119     Port - Supplies the port containing the message queue being modified
    00120
    00121     CleanupAndDestroy - Specifies if the message queue should be set back
    00122         to the freshly initialized state (value of FALSE) or completely
    00123         torn down (value of TRUE)
    00124
    00125 Return Value:
    00126
    00127     None.
    00128
    00129 --*/
    00130
    00131 {
    00132     PLIST_ENTRY Next, Head;
    00133     PETHREAD ThreadWaitingForReply;
    00134     PLPCP_MESSAGE Msg;
    00135
    00136     PAGED_CODE();
    00137
    00138     //
    00139     //  If this port is connected to another port, then disconnect it.
    00140     //  Protect this with a lock in case the other side is going away
    00141     //  at the same time.
    00142     //
    00143
    00144     LpcpAcquireLpcpLock();
    00145
    00146     if (Port->ConnectedPort != NULL) {
    00147
    00148         Port->ConnectedPort->ConnectedPort = NULL;
    00149     }
    00150
    00151     //
    00152     //  If connection port, then mark name as deleted
    00153     //
    00154
    00155     if ((Port->Flags & PORT_TYPE) == SERVER_CONNECTION_PORT) {
    00156
    00157         Port->Flags |= PORT_NAME_DELETED;
    00158     }
    00159
    00160     //
    00161     //  Walk list of threads waiting for a reply to a message sent to this
    00162     //  port.  Signal each thread's LpcReplySemaphore to wake them up.  They
    00163     //  will notice that there was no reply and return
    00164     //  STATUS_PORT_DISCONNECTED
    00165     //
    00166
    00167     Head = &Port->LpcReplyChainHead;
    00168     Next = Head->Flink;
    00169
    00170     while ((Next != NULL) && (Next != Head)) {
    00171
    00172         ThreadWaitingForReply = CONTAINING_RECORD( Next, ETHREAD, LpcReplyChain );
    00173
    00174         //
    00175         //  If the thread is exiting, in the location of LpcReplyChain is stored the ExitTime
    00176         //  We'll stop to search throught the list.
    00177
    00178         if ( ThreadWaitingForReply->LpcExitThreadCalled ) {
    00179
    00180             break;
    00181         }
    00182
    00183         Next = Next->Flink;
    00184
    00185         RemoveEntryList( &ThreadWaitingForReply->LpcReplyChain );
    00186
    00187         InitializeListHead( &ThreadWaitingForReply->LpcReplyChain );
    00188
    00189         if (!KeReadStateSemaphore( &ThreadWaitingForReply->LpcReplySemaphore )) {
    00190
    00191             //
    00192             //  Thread is waiting on a message.  Signal the semaphore and free
    00193             //  the message
    00194             //
    00195
    00196             Msg = ThreadWaitingForReply->LpcReplyMessage;
    00197
    00198             if ( Msg ) {
    00199
    00200                 //
    00201                 //  If the message is a connection request and has a section object
    00202                 //  attached, then dereference that section object
    00203                 //
    00204
    00205                 if ((Msg->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) == LPC_CONNECTION_REQUEST) {
    00206
    00207                     PLPCP_CONNECTION_MESSAGE ConnectMsg;
    00208
    00209                     ConnectMsg = (PLPCP_CONNECTION_MESSAGE)(Msg + 1);
    00210
    00211                     if ( ConnectMsg->SectionToMap != NULL ) {
    00212
    00213                         ObDereferenceObject( ConnectMsg->SectionToMap );
    00214                     }
    00215                 }
    00216
    00217                 ThreadWaitingForReply->LpcReplyMessage = NULL;
    00218
    00219                 LpcpFreeToPortZone( Msg, TRUE );
    00220             }
    00221
    00222             ThreadWaitingForReply->LpcReplyMessageId = 0;
    00223
    00224             KeReleaseSemaphore( &ThreadWaitingForReply->LpcReplySemaphore,
    00225                                 0,
    00226                                 1L,
    00227                                 FALSE );
    00228         }
    00229     }
    00230
    00231     InitializeListHead( &Port->LpcReplyChainHead );
    00232
    00233     //
    00234     //  Walk list of messages queued to this port.  Remove each message from
    00235     //  the list and free it.
    00236     //
    00237
    00238     Head = &Port->MsgQueue.ReceiveHead;
    00239     Next = Head->Flink;
    00240
    00241     while ((Next != NULL) && (Next != Head)) {
    00242
    00243         Msg  = CONTAINING_RECORD( Next, LPCP_MESSAGE, Entry );
    00244
    00245         Next = Next->Flink;
    00246
    00247         InitializeListHead( &Msg->Entry );
    00248
    00249         LpcpFreeToPortZone( Msg, TRUE );
    00250     }
    00251
    00252     //
    00253     //  Reinitialize the message queue
    00254     //
    00255
    00256     InitializeListHead( &Port->MsgQueue.ReceiveHead );
    00257
    00258     LpcpReleaseLpcpLock();
    00259
    00260     //
    00261     //  Check if the caller wants it all to go away
    00262     //
    00263
    00264     if ( CleanupAndDestroy ) {
    00265
    00266         //
    00267         //  Free semaphore associated with the queue.
    00268         //
    00269
    00270         if (Port->MsgQueue.Semaphore != NULL) {
    00271
    00272             ExFreePool( CONTAINING_RECORD( Port->MsgQueue.Semaphore,
    00273                                            LPCP_NONPAGED_PORT_QUEUE,
    00274                                            Semaphore ));
    00275         }
    00276     }
    00277
    00278     //
    00279     //  And return to our caller
    00280     //
    00281
    00282     return;
    00283 }
    00284
    00285
    00286 NTSTATUS
    00287 LpcpInitializePortZone (
    00288     IN ULONG MaxEntrySize,
    00289     IN ULONG SegmentSize,
    00290     IN ULONG MaxPoolUsage
    00291     )
    00292
    00293 /*++
    00294
    00295 Routine Description:
    00296
    00297     This routine only executes once.  It is used to initialize the zone
    00298     allocator for LPC messages
    00299
    00300 Arguments:
    00301
    00302     MaxEntrySize - Specifies the maximum size, in bytes, that we'll allocate
    00303         from the zone.
    00304
    00305     SegmentSize - Specifies the number of total bytes to use in the initial
    00306         zone allocation.  This is also the increment use to grow the zone.
    00307
    00308     MaxPoolUsage - Specifies the maximum number of bytes we every want to
    00309         zone to grow to.
    00310
    00311 Return Value:
    00312
    00313     NTSTATUS - An appropriate status value
    00314
    00315 --*/
    00316
    00317 {
    00318     NTSTATUS Status;
    00319     PVOID Segment;
    00320     PLPCP_MESSAGE Msg;
    00321     LONG SegSize;
    00322
    00323     PAGED_CODE();
    00324
    00325     //
    00326     //  Set the sizes in the global port zone variable
    00327     //
    00328
    00329     LpcpZone.MaxPoolUsage = MaxPoolUsage;
    00330     LpcpZone.GrowSize = SegmentSize;
    00331
    00332     //
    00333     //  Allocate and initialize the initial zone
    00334     //
    00335
    00336     Segment = ExAllocatePoolWithTag( PagedPool, SegmentSize, 'ZcpL' );
    00337
    00338     if (Segment == NULL) {
    00339
    00340         return STATUS_INSUFFICIENT_RESOURCES;
    00341     }
    00342
    00343     KeInitializeEvent( &LpcpZone.FreeEvent, SynchronizationEvent, FALSE );
    00344
    00345     Status = ExInitializeZone( &LpcpZone.Zone,
    00346                                MaxEntrySize,
    00347                                Segment,
    00348                                SegmentSize );
    00349
    00350     if (!NT_SUCCESS( Status )) {
    00351
    00352         ExFreePool( Segment );
    00353     }
    00354
    00355     //
    00356     //  The following code sets up each msg in the zone by filling in its
    00357     //  index, and zeroing the rest.
    00358     //
    00359     //  **** note, this is really a backdoor piece of code.  First, it assumes
    00360     //       segsize is pagesize, and second, it assume the zone doesn't touch
    00361     //       those fields for its own bookkeeping.
    00362     //
    00363
    00364     SegSize = PAGE_SIZE;
    00365     LpcpTotalNumberOfMessages = 0;
    00366
    00367     //
    00368     //  Skip over the segment header
    00369     //
    00370
    00371     Msg = (PLPCP_MESSAGE)((PZONE_SEGMENT_HEADER)Segment + 1);
    00372
    00373     //
    00374     //  For each block in the zone pointed at by Msg, pre-initialize the Msg
    00375     //
    00376
    00377     while (SegSize >= (LONG)LpcpZone.Zone.BlockSize) {
    00378
    00379         Msg->ZoneIndex = (USHORT)++LpcpTotalNumberOfMessages;
    00380         Msg->Reserved0 = 0;
    00381         Msg->Request.MessageId = 0;
    00382
    00383         Msg = (PLPCP_MESSAGE)((PCHAR)Msg + LpcpZone.Zone.BlockSize);
    00384
    00385         SegSize -= LpcpZone.Zone.BlockSize;
    00386     }
    00387
    00388     //
    00389     //  And return to our caller
    00390     //
    00391
    00392     return Status;
    00393 }
    00394
    00395
    00396 NTSTATUS
    00397 LpcpExtendPortZone (
    00398     VOID
    00399     )
    00400
    00401 /*++
    00402
    00403 Routine Description:
    00404
    00405     This routine is used to increase the size of the global port zone.
    00406
    00407     Note that our caller must have already acquired the LpcpLock mutex.
    00408
    00409 Arguments:
    00410
    00411     None.
    00412
    00413 Return Value:
    00414
    00415     NTSTATUS - An appropriate status value
    00416
    00417 --*/
    00418
    00419 {
    00420     NTSTATUS Status;
    00421     PVOID Segment;
    00422     PLPCP_MESSAGE Msg;
    00423     LARGE_INTEGER WaitTimeout;
    00424     BOOLEAN AlreadyRetried;
    00425     LONG SegmentSize;
    00426
    00427     PAGED_CODE();
    00428
    00429     AlreadyRetried = FALSE;
    00430
    00431 retry:
    00432
    00433     //
    00434     //  If we're going to grow across a threshold, we should wait a little in case
    00435     //  an entry gets freed.
    00436     //
    00437
    00438     if ((LpcpZone.Zone.TotalSegmentSize + LpcpZone.GrowSize) > LpcpZone.MaxPoolUsage) {
    00439
    00440         LpcpPrint(( "Out of space in global LPC zone - current size is %08x\n",
    00441                     LpcpZone.Zone.TotalSegmentSize ));
    00442
    00443         //
    00444         //  Wait time is 1 second.
    00445         //
    00446         //  We'll actually only go through this path once because on retry we
    00447         //  bump up max pool usage to avoid this wait
    00448         //
    00449
    00450         WaitTimeout.QuadPart = Int32x32To64( 1000, -10000 );
    00451
    00452         LpcpReleaseLpcpLock();
    00453
    00454         Status = KeWaitForSingleObject( &LpcpZone.FreeEvent,
    00455                                         Executive,
    00456                                         KernelMode,
    00457                                         FALSE,
    00458                                         &WaitTimeout );
    00459
    00460         LpcpAcquireLpcpLock();
    00461
    00462         if (Status != STATUS_SUCCESS) {
    00463
    00464             LpcpPrint(( "Error waiting for %lx->FreeEvent - Status == %X\n",
    00465                         &LpcpZone,
    00466                         Status ));
    00467
    00468             if ( !AlreadyRetried ) {
    00469
    00470                 AlreadyRetried = TRUE;
    00471
    00472                 LpcpZone.MaxPoolUsage += LpcpZone.GrowSize;
    00473
    00474                 goto retry;
    00475             }
    00476         }
    00477
    00478         //
    00479         //  return to our caller and let the caller retry the allocation
    00480         //  again
    00481         //
    00482
    00483         return Status;
    00484     }
    00485
    00486     //
    00487     //  We need to extend the zone, so allocate another chunk and add it
    00488     //  to the zone
    00489     //
    00490
    00491     Segment = ExAllocatePoolWithTag( PagedPool, LpcpZone.GrowSize, 'ZcpL' );
    00492
    00493     if (Segment == NULL) {
    00494
    00495         return STATUS_INSUFFICIENT_RESOURCES;
    00496     }
    00497
    00498     Status = ExExtendZone( &LpcpZone.Zone,
    00499                            Segment,
    00500                            LpcpZone.GrowSize );
    00501
    00502     if (!NT_SUCCESS( Status )) {
    00503
    00504         ExFreePool( Segment );
    00505     }
    00506
    00507 #if DEVL
    00508
    00509     else {
    00510
    00511         LpcpTrace(( "Extended LPC zone by %x for a total of %x\n",
    00512                     LpcpZone.GrowSize, LpcpZone.Zone.TotalSegmentSize ));
    00513
    00514         //
    00515         //  The following code sets up each msg in the zone by filling in its
    00516         //  index, and zeroing the rest.
    00517         //
    00518         //  **** note, this is really a backdoor piece of code.  First, it assumes
    00519         //       we grew by one page, and second, it assume the zone doesn't touch
    00520         //       those fields for its own bookkeeping.
    00521         //
    00522
    00523         SegmentSize = PAGE_SIZE;
    00524
    00525         Msg = (PLPCP_MESSAGE)((PZONE_SEGMENT_HEADER)Segment + 1);
    00526
    00527         while (SegmentSize >= (LONG)LpcpZone.Zone.BlockSize) {
    00528
    00529             Msg->ZoneIndex = (USHORT)++LpcpTotalNumberOfMessages;
    00530
    00531             Msg = (PLPCP_MESSAGE)((PCHAR)Msg + LpcpZone.Zone.BlockSize);
    00532
    00533             SegmentSize -= LpcpZone.Zone.BlockSize;
    00534         }
    00535
    00536         //
    00537         //  Now that we've completely initialized the new segment, go
    00538         //  and wake up any waiters
    00539         //
    00540
    00541         LpcpReleaseLpcpLock();
    00542
    00543         KeSetEvent( &LpcpZone.FreeEvent,
    00544                     LPC_RELEASE_WAIT_INCREMENT,
    00545                     FALSE );
    00546
    00547         LpcpAcquireLpcpLock();
    00548     }
    00549
    00550 #endif
    00551
    00552     return Status;
    00553 }
    00554
    00555
    00556 PLPCP_MESSAGE
    00557 FASTCALL
    00558 LpcpAllocateFromPortZone (
    00559     ULONG Size
    00560     )
    00561
    00562 /*++
    00563
    00564 Routine Description:
    00565
    00566     This procedure is used to allocate a new msg from the global port zone.
    00567
    00568     Note that we assume our caller owns the LpcpLock mutex.
    00569
    00570 Arguments:
    00571
    00572     Size - Specifies the size, in bytes, needed for the allocation.  Currently
    00573         this variable is ignored
    00574
    00575 Return Value:
    00576
    00577     PLPCP_MESSAGE - returns a pointer to the newly allocate message
    00578
    00579 --*/
    00580
    00581 {
    00582     NTSTATUS Status;
    00583     PLPCP_MESSAGE Msg;
    00584
    00585     PAGED_CODE();
    00586
    00587     //
    00588     //  Continue looping until we get a message to give back or until when we
    00589     //  extend the zone we get back and error
    00590     //
    00591
    00592     do {
    00593
    00594         //
    00595         //  Pick off the next message from the zone and if we actually
    00596         //  did get one then initialize some of its fields and return it
    00597         //  to our caller
    00598         //
    00599
    00600         Msg = (PLPCP_MESSAGE)ExAllocateFromZone( &LpcpZone.Zone );
    00601
    00602         if (Msg != NULL) {
    00603
    00604             LpcpTrace(( "Allocate Msg %lx\n", Msg ));
    00605
    00606             InitializeListHead( &Msg->Entry );
    00607
    00608             Msg->RepliedToThread = NULL;
    00609
    00610 #if DBG
    00611             //
    00612             //  In the debug case mark the message as allocated
    00613             //
    00614
    00615             Msg->ZoneIndex |= LPCP_ZONE_MESSAGE_ALLOCATED;
    00616 #endif
    00617
    00618             return Msg;
    00619         }
    00620
    00621         //
    00622         //  The zone didn't give us an entry so extend the zone and try the
    00623         //  allocation again
    00624         //
    00625
    00626         LpcpTrace(( "Extending Zone %lx\n", &LpcpZone.Zone ));
    00627
    00628         Status = LpcpExtendPortZone( );
    00629
    00630     } while (NT_SUCCESS(Status));
    00631
    00632     //
    00633     //  Return NULL (i.e., an error) to our caller
    00634     //
    00635
    00636     return NULL;
    00637 }
    00638
    00639
    00640 VOID
    00641 FASTCALL
    00642 LpcpFreeToPortZone (
    00643     IN PLPCP_MESSAGE Msg,
    00644     IN BOOLEAN MutexOwned
    00645     )
    00646
    00647 /*++
    00648
    00649 Routine Description:
    00650
    00651     This routine is used to free an old msg back to the global message queue
    00652
    00653 Arguments:
    00654
    00655     Msg - Supplies the message being returned
    00656
    00657     MutexOwned - Specifies if the LpcpLock is already owned by the caller
    00658
    00659 Return Value:
    00660
    00661     None.
    00662
    00663 --*/
    00664
    00665 {
    00666     BOOLEAN ZoneMemoryAvailable = FALSE;
    00667     PLPCP_CONNECTION_MESSAGE ConnectMsg;
    00668
    00669     PAGED_CODE();
    00670
    00671     //
    00672     //  Take out the global lock if necessary
    00673     //
    00674
    00675     if (!MutexOwned) {
    00676
    00677         LpcpAcquireLpcpLock();
    00678     }
    00679
    00680     LpcpTrace(( "Free Msg %lx\n", Msg ));
    00681
    00682 #if DBG
    00683
    00684     //
    00685     //  In the debug case if the message is not allocated then it's an error
    00686     //
    00687
    00688     if (!(Msg->ZoneIndex & LPCP_ZONE_MESSAGE_ALLOCATED)) {
    00689
    00690         LpcpPrint(( "Msg %lx has already been freed.\n", Msg ));
    00691         DbgBreakPoint();
    00692
    00693         if (!MutexOwned) {
    00694
    00695             LpcpReleaseLpcpLock();
    00696         }
    00697
    00698         return;
    00699     }
    00700
    00701     Msg->ZoneIndex &= ~LPCP_ZONE_MESSAGE_ALLOCATED;
    00702
    00703 #endif
    00704
    00705     //
    00706     //  The non zero reserved0 field tells us that the message has been used
    00707     //
    00708
    00709     if (Msg->Reserved0 != 0) {
    00710
    00711         //
    00712         //  A entry field connects the message to the message queue of the
    00713         //  owning port object.  If not already removed then remove this
    00714         //  message
    00715         //
    00716
    00717         if (!IsListEmpty( &Msg->Entry )) {
    00718
    00719             RemoveEntryList( &Msg->Entry );
    00720
    00721             InitializeListHead( &Msg->Entry );
    00722         }
    00723
    00724         //
    00725         //  If the replied to thread is not null then we have a reference
    00726         //  to the thread that we should now remove
    00727         //
    00728
    00729         if (Msg->RepliedToThread != NULL) {
    00730
    00731             ObDereferenceObject( Msg->RepliedToThread );
    00732
    00733             Msg->RepliedToThread = NULL;
    00734         }
    00735
    00736         //
    00737         //  If the msg was for a connection request then we know that
    00738         //  right after the lpcp message is a connection message whose
    00739         //  client port field might need to be dereferenced
    00740         //
    00741
    00742         if ((Msg->Request.u2.s2.Type & ~LPC_KERNELMODE_MESSAGE) == LPC_CONNECTION_REQUEST) {
    00743
    00744             ConnectMsg = (PLPCP_CONNECTION_MESSAGE)(Msg + 1);
    00745
    00746             if (ConnectMsg->ClientPort) {
    00747
    00748                 PLPCP_PORT_OBJECT ClientPort;
    00749
    00750                 //
    00751                 //  Capture a pointer to the client port then null it
    00752                 //  out so that no one else can use it, then release
    00753                 //  lpcp lock before we dereference the client port
    00754                 //
    00755
    00756                 ClientPort = ConnectMsg->ClientPort;
    00757
    00758                 ConnectMsg->ClientPort = NULL;
    00759
    00760                 LpcpReleaseLpcpLock();
    00761
    00762                 ObDereferenceObject( ClientPort );
    00763
    00764                 LpcpAcquireLpcpLock();
    00765             }
    00766         }
    00767
    00768         //
    00769         //  Now mark this message a free, and return it to the zone
    00770         //
    00771
    00772         Msg->Reserved0 = 0;
    00773         ZoneMemoryAvailable = (BOOLEAN)(ExFreeToZone( &LpcpZone.Zone, &Msg->FreeEntry ) == NULL);
    00774     }
    00775
    00776     //
    00777     //  Check if we need to release the global lpcp lock
    00778     //
    00779
    00780     if (!MutexOwned) {
    00781
    00782         LpcpReleaseLpcpLock();
    00783     }
    00784
    00785     //
    00786     //  If we've actually freed up memory then go wake any waiting allocators
    00787     //
    00788     //  **** does this need to check to see if it owns the lpcp lock.  The
    00789     //       release right above us and this test and set event should be
    00790     //       combined
    00791     //
    00792
    00793     if (ZoneMemoryAvailable) {
    00794
    00795         KeSetEvent( &LpcpZone.FreeEvent,
    00796                     LPC_RELEASE_WAIT_INCREMENT,
    00797                     FALSE );
    00798     }
    00799
    00800     //
    00801     //  And return to our caller
    00802     //
    00803
    00804     return;
    00805 }
    00806
    00807
    00808 VOID
    00809 LpcpSaveDataInfoMessage (
    00810     IN PLPCP_PORT_OBJECT Port,
    00811     PLPCP_MESSAGE Msg
    00812     )
    00813
    00814 /*++
    00815
    00816 Routine Description:
    00817
    00818     This routine is used in place of freeing a message and instead saves the
    00819     message off a seperate queue from the port.
    00820
    00821 Arguments:
    00822
    00823     Port - Specifies the port object under which to save this message
    00824
    00825     Msg - Supplies the message being saved
    00826
    00827 Return Value:
    00828
    00829     None.
    00830
    00831 --*/
    00832
    00833 {
    00834     PAGED_CODE();
    00835
    00836     //
    00837     //  Take out the global lock
    00838     //
    00839
    00840     LpcpAcquireLpcpLock();
    00841
    00842     //
    00843     //  Make sure we get to the connection port object of this port
    00844     //
    00845
    00846     if ((Port->Flags & PORT_TYPE) > UNCONNECTED_COMMUNICATION_PORT) {
    00847
    00848         Port = Port->ConnectionPort;
    00849     }
    00850
    00851     LpcpTrace(( "%s Saving DataInfo Message %lx (%u.%u)  Port: %lx\n",
    00852                 PsGetCurrentProcess()->ImageFileName,
    00853                 Msg,
    00854                 Msg->Request.MessageId,
    00855                 Msg->Request.CallbackId,
    00856                 Port ));
    00857
    00858     //
    00859     //  Enqueue this message onto the data info chain for the port
    00860     //
    00861
    00862     InsertTailList( &Port->LpcDataInfoChainHead, &Msg->Entry );
    00863
    00864     //
    00865     //  Free the global lock
    00866     //
    00867
    00868     LpcpReleaseLpcpLock();
    00869
    00870     //
    00871     //  And return to our caller
    00872     //
    00873
    00874     return;
    00875 }
    00876
    00877
    00878 VOID
    00879 LpcpFreeDataInfoMessage (
    00880     IN PLPCP_PORT_OBJECT Port,
    00881     IN ULONG MessageId,
    00882     IN ULONG CallbackId
    00883     )
    00884
    00885 /*++
    00886
    00887 Routine Description:
    00888
    00889     This routine is used to free up a saved message in a port
    00890
    00891 Arguments:
    00892
    00893     Port - Supplies the port being manipulated
    00894
    00895     MessageId - Supplies the id of the message being freed
    00896
    00897     CallbackId - Supplies the callback id of the message being freed
    00898
    00899 Return Value:
    00900
    00901     None.
    00902
    00903 --*/
    00904
    00905 {
    00906     PLPCP_MESSAGE Msg;
    00907     PLIST_ENTRY Head, Next;
    00908
    00909     PAGED_CODE();
    00910
    00911     //
    00912     //  Make sure we get to the connection port object of this port
    00913     //
    00914
    00915     if ((Port->Flags & PORT_TYPE) > UNCONNECTED_COMMUNICATION_PORT) {
    00916
    00917         Port = Port->ConnectionPort;
    00918     }
    00919
    00920     //
    00921     //  Zoom down the data info chain for the connection port object
    00922     //
    00923
    00924     Head = &Port->LpcDataInfoChainHead;
    00925     Next = Head->Flink;
    00926
    00927     while (Next != Head) {
    00928
    00929         Msg = CONTAINING_RECORD( Next, LPCP_MESSAGE, Entry );
    00930
    00931         //
    00932         //  If this message matches the callers specification then remove
    00933         //  this message, free it back to the port zone, and return back
    00934         //  to our caller
    00935         //
    00936
    00937         if ((Msg->Request.MessageId == MessageId) &&
    00938             (Msg->Request.CallbackId == CallbackId)) {
    00939
    00940             LpcpTrace(( "%s Removing DataInfo Message %lx (%u.%u) Port: %lx\n",
    00941                         PsGetCurrentProcess()->ImageFileName,
    00942                         Msg,
    00943                         Msg->Request.MessageId,
    00944                         Msg->Request.CallbackId,
    00945                         Port ));
    00946
    00947             RemoveEntryList( &Msg->Entry );
    00948
    00949             InitializeListHead( &Msg->Entry );
    00950
    00951             LpcpFreeToPortZone( Msg, TRUE );
    00952
    00953             return;
    00954
    00955         } else {
    00956
    00957             //
    00958             //  Keep on going down the data info chain
    00959             //
    00960
    00961             Next = Next->Flink;
    00962         }
    00963     }
    00964
    00965     //
    00966     //  We didn't find a match so just return to our caller
    00967     //
    00968
    00969     LpcpTrace(( "%s Unable to find DataInfo Message (%u.%u)  Port: %lx\n",
    00970                 PsGetCurrentProcess()->ImageFileName,
    00971                 MessageId,
    00972                 CallbackId,
    00973                 Port ));
    00974
    00975     return;
    00976 }
    00977
    00978
    00979 PLPCP_MESSAGE
    00980 LpcpFindDataInfoMessage (
    00981     IN PLPCP_PORT_OBJECT Port,
    00982     IN ULONG MessageId,
    00983     IN ULONG CallbackId
    00984     )
    00985
    00986 /*++
    00987
    00988 Routine Description:
    00989
    00990     This routine is used to locate a specific message stored off the
    00991     data info chain of a port
    00992
    00993 Arguments:
    00994
    00995     Port - Supplies the port being examined
    00996
    00997     MessageId - Supplies the ID of the message being searched for
    00998
    00999     CallbackId - Supplies the callback ID being searched for
    01000
    01001 Return Value:
    01002
    01003     PLPCP_MESSAGE - returns a pointer to the message satisfying the
    01004         search criteria or NULL of none was found
    01005
    01006 --*/
    01007
    01008 {
    01009     PLPCP_MESSAGE Msg;
    01010     PLIST_ENTRY Head, Next;
    01011
    01012     PAGED_CODE();
    01013
    01014     //
    01015     //  Make sure we get to the connection port object of this port
    01016     //
    01017
    01018     if ((Port->Flags & PORT_TYPE) > UNCONNECTED_COMMUNICATION_PORT) {
    01019
    01020         Port = Port->ConnectionPort;
    01021     }
    01022
    01023     //
    01024     //  Zoom down the data info chain for the connection port object looking
    01025     //  for a match
    01026     //
    01027
    01028     Head = &Port->LpcDataInfoChainHead;
    01029     Next = Head->Flink;
    01030
    01031     while (Next != Head) {
    01032
    01033         Msg = CONTAINING_RECORD( Next, LPCP_MESSAGE, Entry );
    01034
    01035         if ((Msg->Request.MessageId == MessageId) &&
    01036             (Msg->Request.CallbackId == CallbackId)) {
    01037
    01038             LpcpTrace(( "%s Found DataInfo Message %lx (%u.%u)  Port: %lx\n",
    01039                         PsGetCurrentProcess()->ImageFileName,
    01040                         Msg,
    01041                         Msg->Request.MessageId,
    01042                         Msg->Request.CallbackId,
    01043                         Port ));
    01044
    01045             return Msg;
    01046
    01047         } else {
    01048
    01049             Next = Next->Flink;
    01050         }
    01051     }
    01052
    01053     //
    01054     //  We did not find a match so return null to our caller
    01055     //
    01056
    01057     LpcpTrace(( "%s Unable to find DataInfo Message (%u.%u)  Port: %lx\n",
    01058                 PsGetCurrentProcess()->ImageFileName,
    01059                 MessageId,
    01060                 CallbackId,
    01061                 Port ));
    01062
    01063     return NULL;
    01064 }