test: channel.c Source File

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

# channel.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1995  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     channel.c
    00008
    00009 Abstract:
    00010
    00011    This module implements the executive channel object. Channel obects
    00012    provide a very high speed local interprocess communication mechanism.
    00013
    00014 Author:
    00015
    00016     David N. Cutler (davec) 26-Mar-1995
    00017
    00018 Environment:
    00019
    00020     Kernel mode only.
    00021
    00022 Revision History:
    00023
    00024 --*/
    00025
    00026 #include "ki.h"
    00027
    00028 //
    00029 // Define local function prototypes.
    00030 //
    00031
    00032 VOID
    00033 KiAllocateReceiveBufferChannel (
    00034     VOID
    00035     );
    00036
    00037 VOID
    00038 KiCloseChannel (
    00039     IN PEPROCESS Process,
    00040     IN PVOID Object,
    00041     IN ACCESS_MASK GrantedAccess,
    00042     IN ULONG ProcessHandleCount,
    00043     IN ULONG SystemHandleCount
    00044     );
    00045
    00046 VOID
    00047 KiDeleteChannel (
    00048     IN PVOID Object
    00049     );
    00050
    00051 NTSTATUS
    00052 KiListenChannel (
    00053     IN PRECHANNEL ServerChannel,
    00054     IN KPROCESSOR_MODE WaitMode,
    00055     OUT PCHANNEL_MESSAGE *Message
    00056     );
    00057
    00058 PKTHREAD
    00059 KiRendezvousWithThread (
    00060     IN PRECHANNEL WaitChannel,
    00061     IN ULONG WaitMode
    00062     );
    00063
    00064 //
    00065 // Address of event object type descriptor.
    00066 //
    00067
    00068 POBJECT_TYPE KeChannelType;
    00069
    00070 //
    00071 // Structure that describes the mapping of generic access rights to object
    00072 // specific access rights for event objects.
    00073 //
    00074
    00075 GENERIC_MAPPING KiChannelMapping = {
    00076     STANDARD_RIGHTS_READ |
    00077         CHANNEL_READ_MESSAGE,
    00078     STANDARD_RIGHTS_WRITE |
    00079         CHANNEL_WRITE_MESSAGE,
    00080     STANDARD_RIGHTS_EXECUTE |
    00081         SYNCHRONIZE,
    00082     CHANNEL_ALL_ACCESS
    00083 };
    00084
    00085 //
    00086 // Define function sections.
    00087 //
    00088
    00089 #ifdef ALLOC_PRAGMA
    00090 #pragma alloc_text(PAGE, KiAllocateReceiveBufferChannel)
    00091 #pragma alloc_text(INIT, KiChannelInitialization)
    00092 #pragma alloc_text(PAGE, KiDeleteChannel)
    00093 #pragma alloc_text(PAGE, KiRundownChannel)
    00094 #pragma alloc_text(PAGE, NtCreateChannel)
    00095 #pragma alloc_text(PAGE, NtListenChannel)
    00096 #pragma alloc_text(PAGE, NtOpenChannel)
    00097 #pragma alloc_text(PAGE, NtSetContextChannel)
    00098 #endif
    00099
    00100 NTSTATUS
    00101 NtCreateChannel (
    00102     OUT PHANDLE ChannelHandle,
    00103     IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
    00104     )
    00105
    00106 /*++
    00107
    00108 Routine Description:
    00109
    00110     This function creates a server listen channel object and opens a handle
    00111     to the object with the specified desired access.
    00112
    00113 Arguments:
    00114
    00115     ChannelHandle - Supplies a pointer to a variable that will receive the
    00116         channel object handle.
    00117
    00118     ObjectAttributes - Supplies a pointer to an object attributes structure.
    00119
    00120 Return Value:
    00121
    00122     If the channel object is created, then a success status is returned.
    00123     Otherwise, a failure status is returned.
    00124
    00125 --*/
    00126
    00127 {
    00128
    00129 #if 0
    00130
    00131     PVOID ChannelObject;
    00132     KPROCESSOR_MODE PreviousMode;
    00133     PRECHANNEL ServerChannel;
    00134     HANDLE ServerHandle;
    00135     NTSTATUS Status;
    00136
    00137     //
    00138     // Establish an exception handler, probe and zero the output handle
    00139     // address, and attempt to create a channel object. If the probe fails
    00140     // or access to the object attributes fails, then return the exception
    00141     // code as the service status.
    00142     //
    00143
    00144     PreviousMode = KeGetPreviousMode();
    00145     try {
    00146
    00147         //
    00148         // Get previous processor mode and probe output handle address if
    00149         // necessary.
    00150         //
    00151
    00152         if (PreviousMode != KernelMode) {
    00153             ProbeAndZeroHandle(ChannelHandle);
    00154         }
    00155
    00156         //
    00157         // Allocate channel object.
    00158         //
    00159
    00160         Status = ObCreateObject(PreviousMode,
    00161                                 KeChannelType,
    00162                                 ObjectAttributes,
    00163                                 PreviousMode,
    00164                                 NULL,
    00165                                 sizeof(ECHANNEL),
    00166                                 0,
    00167                                 0,
    00168                                 &ChannelObject);
    00169
    00170     } except(ExSystemExceptionFilter()) {
    00171         return GetExceptionCode();
    00172     }
    00173
    00174     //
    00175     // If the channel object was successfully created, then initialize the
    00176     // channel object and insert the channel object in the process handle
    00177     // table.
    00178     //
    00179
    00180     if (NT_SUCCESS(Status)) {
    00181         ServerChannel = (PRECHANNEL)ChannelObject;
    00182         ServerChannel->Type = LISTEN_CHANNEL;
    00183         ServerChannel->State = ServerIdle;
    00184         ServerChannel->OwnerProcess = &PsGetCurrentProcess()->Pcb;
    00185         ServerChannel->ClientThread = NULL;
    00186         ServerChannel->ServerThread = NULL;
    00187         ServerChannel->ServerContext = NULL;
    00188         ServerChannel->ServerChannel = NULL;
    00189         KeInitializeEvent(&ServerChannel->ReceiveEvent,
    00190                           SynchronizationEvent,
    00191                           FALSE);
    00192
    00193         KeInitializeEvent(&ServerChannel->ClearToSendEvent,
    00194                           SynchronizationEvent,
    00195                           FALSE);
    00196
    00197         Status = ObInsertObject(ServerChannel,
    00198                                 NULL,
    00199                                 CHANNEL_ALL_ACCESS,
    00200                                 0,
    00201                                 NULL,
    00202                                 &ServerHandle);
    00203
    00204         //
    00205         // If the channel object was successfully inserted in the process
    00206         // handle table, then attempt to write the channel object handle
    00207         // value. If the write attempt fails, then do not report an error.
    00208         // When the caller attempts to access the handle value, an access
    00209         // violation will occur.
    00210         //
    00211
    00212         if (NT_SUCCESS(Status)) {
    00213             try {
    00214                 *ChannelHandle = ServerHandle;
    00215
    00216             } except(ExSystemExceptionFilter()) {
    00217             }
    00218         }
    00219     }
    00220
    00221     //
    00222     // Return service status.
    00223     //
    00224
    00225     return Status;
    00226
    00227 #else
    00228
    00229     return STATUS_NOT_IMPLEMENTED;
    00230
    00231 #endif
    00232
    00233 }
    00234
    00235 NTSTATUS
    00236 NtListenChannel (
    00237     IN HANDLE ChannelHandle,
    00238     OUT PCHANNEL_MESSAGE *Message
    00239     )
    00240
    00241 /*++
    00242
    00243 Routine Description:
    00244
    00245     This function listens for a client message.
    00246
    00247     N.B. This function can only be executed from a server thread.
    00248
    00249 Arguments:
    00250
    00251     ChannelHandle - Supplies a handle to a listen channel on which the
    00252         server thread listens.
    00253
    00254     Message - Supplies a pointer to a variable that receives a pointer
    00255         to the client message header.
    00256
    00257 Return Value:
    00258
    00259     If the function is successfully completed, then a success status is
    00260     returned. Otherwise, a failure status is returned.
    00261
    00262 --*/
    00263
    00264 {
    00265
    00266 #if 0
    00267
    00268     KPROCESSOR_MODE PreviousMode;
    00269     PRECHANNEL ServerChannel;
    00270     PRKTHREAD ServerThread;
    00271     NTSTATUS Status;
    00272
    00273     //
    00274     // Establish an exception handler, probe the output message address,
    00275     // and allocate a receive buffer if necessary. If the probe fails or
    00276     // the receive buffer allocation is not successful, then return the
    00277     // exception code as the service status.
    00278     //
    00279
    00280     ServerThread = KeGetCurrentThread();
    00281     try {
    00282
    00283         //
    00284         // Get previous processor mode and probe output message address.
    00285         //
    00286
    00287         PreviousMode = KeGetPreviousMode();
    00288         if (PreviousMode != KernelMode) {
    00289             ProbeAndNullPointer(Message);
    00290         }
    00291
    00292         //
    00293         // If the current thread does not have an associated receive buffer,
    00294         // then attempt to allocate one now. If the allocation fails, then
    00295         // an exception is raised.
    00296         //
    00297
    00298         if (ServerThread->Section == NULL) {
    00299             KiAllocateReceiveBufferChannel();
    00300         }
    00301
    00302     } except(ExSystemExceptionFilter()) {
    00303         return GetExceptionCode();
    00304     }
    00305
    00306     //
    00307     // Reference channel object by handle.
    00308     //
    00309
    00310     Status = ObReferenceObjectByHandle(ChannelHandle,
    00311                                        CHANNEL_ALL_ACCESS,
    00312                                        KeChannelType,
    00313                                        PreviousMode,
    00314                                        &ServerChannel,
    00315                                        NULL);
    00316
    00317     //
    00318     // If the reference was successful and the channel is a listen channel,
    00319     // then wait for a client message to arrive.
    00320     //
    00321
    00322     if (NT_SUCCESS(Status)) {
    00323         if (ServerChannel->ServerChannel != NULL) {
    00324             Status = STATUS_INVALID_PARAMETER; // **** fix ****
    00325
    00326         } else {
    00327             Status = KiListenChannel(ServerChannel, PreviousMode, Message);
    00328         }
    00329
    00330         ObDereferenceObject(ServerChannel);
    00331     }
    00332
    00333     //
    00334     // Return service status.
    00335     //
    00336
    00337     return Status;
    00338
    00339 #else
    00340
    00341     return STATUS_NOT_IMPLEMENTED;
    00342
    00343 #endif
    00344
    00345 }
    00346
    00347 NTSTATUS
    00348 NtOpenChannel (
    00349     OUT PHANDLE ChannelHandle,
    00350     IN POBJECT_ATTRIBUTES ObjectAttributes
    00351     )
    00352
    00353 /*++
    00354
    00355 Routine Description:
    00356
    00357     This function opens a handle to a server channel by creating a message
    00358     channel that is connected to the specified server channel.
    00359
    00360 Arguments:
    00361
    00362     ChannelHandle - Supplies a pointer to a variable that will receive the
    00363         channel object handle.
    00364
    00365     ObjectAttributes - Supplies a pointer to an object attributes structure.
    00366
    00367 Return Value:
    00368
    00369     If the channel object is opened, then a success status is returned.
    00370     Otherwise, a failure status is returned.
    00371
    00372 --*/
    00373
    00374 {
    00375
    00376 #if 0
    00377
    00378     PRECHANNEL ClientChannel;
    00379     HANDLE ClientHandle;
    00380     PKTHREAD ClientThread;
    00381     KPROCESSOR_MODE PreviousMode;
    00382     PRECHANNEL ServerChannel;
    00383     PVOID ServerObject;
    00384     NTSTATUS Status;
    00385
    00386     //
    00387     // Establish an exception handler, probe and zero the output handle
    00388     // address, and attempt to open the server channel object. If the
    00389     // probe fails, then return the exception code as the service status.
    00390     //
    00391
    00392     try {
    00393
    00394         //
    00395         // Get previous processor mode and probe output handle address
    00396         // if necessary.
    00397         //
    00398
    00399         PreviousMode = KeGetPreviousMode();
    00400         if (PreviousMode != KernelMode) {
    00401             ProbeAndZeroHandle(ChannelHandle);
    00402         }
    00403
    00404         //
    00405         // Reference the server channel object with the specified desired
    00406         // access.
    00407         //
    00408
    00409         Status = ObReferenceObjectByName(ObjectAttributes->ObjectName,
    00410                                         ObjectAttributes->Attributes,
    00411                                         NULL,
    00412                                         CHANNEL_ALL_ACCESS,
    00413                                         KeChannelType,
    00414                                         PreviousMode,
    00415                                         NULL,
    00416                                         (PVOID *)&ServerObject);
    00417
    00418     } except(ExSystemExceptionFilter()) {
    00419         return GetExceptionCode();
    00420     }
    00421
    00422     //
    00423     // If the reference was successful, then attempt to create a client
    00424     // channel object.
    00425     //
    00426
    00427     if (NT_SUCCESS(Status)) {
    00428
    00429         //
    00430         // If the owner process of the server channel is the same as
    00431         // the current process, then a server thread is attempting to
    00432         // open a client handle. This is not allowed since it would
    00433         // not be possible to distinguish the server from the cient.
    00434         //
    00435
    00436         ClientThread = KeGetCurrentThread();
    00437         ServerChannel = (PECHANNEL)ServerObject;
    00438         if (ServerChannel->OwnerProcess == ClientThread->ApcState.Process) {
    00439             Status = STATUS_INVALID_PARAMETER; // **** fix ***
    00440
    00441         } else {
    00442             Status = ObCreateObject(PreviousMode,
    00443                                     KeChannelType,
    00444                                     NULL,
    00445                                     PreviousMode,
    00446                                     NULL,
    00447                                     sizeof(ECHANNEL),
    00448                                     0,
    00449                                     0,
    00450                                     (PVOID *)&ClientChannel);
    00451
    00452             //
    00453             // If the channel object was successfully created, then
    00454             // initialize the channel object and attempt to insert the
    00455             // channel object in the server process channel table.
    00456             //
    00457
    00458             if (NT_SUCCESS(Status)) {
    00459                 ClientChannel->Type = MESSAGE_CHANNEL;
    00460                 ClientChannel->State = ClientIdle;
    00461                 ClientChannel->OwnerProcess = &PsGetCurrentProcess()->Pcb;
    00462                 ClientChannel->ClientThread = NULL;
    00463                 ClientChannel->ServerThread = NULL;
    00464                 ClientChannel->ServerContext = NULL;
    00465                 ClientChannel->ServerChannel = ServerChannel;
    00466                 KeInitializeEvent(&ClientChannel->ReceiveEvent,
    00467                                   SynchronizationEvent,
    00468                                   FALSE);
    00469
    00470                 KeInitializeEvent(&ClientChannel->ClearToSendEvent,
    00471                                   SynchronizationEvent,
    00472                                   FALSE);
    00473
    00474                 //
    00475                 // Create a handle to the message channel object.
    00476                 //
    00477
    00478                 Status = ObInsertObject(ClientChannel,
    00479                                         NULL,
    00480                                         CHANNEL_ALL_ACCESS,
    00481                                         0,
    00482                                         NULL,
    00483                                         &ClientHandle);
    00484
    00485                 //
    00486                 // If the channel object was successfully inserted in the
    00487                 // client process handle table, then attempt to write the
    00488                 // client channel object handle value. If the write attempt
    00489                 // fails, then do not report an error. When the caller
    00490                 // attempts to access the handle value, an access violation
    00491                 // will occur.
    00492                 //
    00493
    00494                 if (NT_SUCCESS(Status)) {
    00495                     try {
    00496                         *ChannelHandle = ClientHandle;
    00497
    00498                     } except(ExSystemExceptionFilter()) {
    00499                     }
    00500
    00501                 }
    00502
    00503                 return Status;
    00504             }
    00505         }
    00506
    00507         ObDereferenceObject(ServerChannel);
    00508     }
    00509
    00510     //
    00511     // Return service status.
    00512     //
    00513
    00514     return Status;
    00515
    00516 #else
    00517
    00518     return STATUS_NOT_IMPLEMENTED;
    00519
    00520 #endif
    00521
    00522 }
    00523
    00524 NTSTATUS
    00525 NtReplyWaitSendChannel (
    00526     IN PVOID Text,
    00527     IN ULONG Length,
    00528     OUT PCHANNEL_MESSAGE *Message
    00529     )
    00530
    00531 /*++
    00532
    00533 Routine Description:
    00534
    00535     This function sends a reply message to a client and waits for a send.
    00536
    00537     N.B. This function can only be executed from a server thread that
    00538         has an assoicated message channel.
    00539
    00540 Arguments:
    00541
    00542     Text - Supplies a pointer to the message text.
    00543
    00544     Length - Supplies the length of the message text.
    00545
    00546     Message - Supplies a pointer to a variable that receives the send
    00547         message header.
    00548
    00549 Return Value:
    00550
    00551     If the function is successfully completed, then a succes status is
    00552     returned. Otherwise, a failure status is returned.
    00553
    00554 --*/
    00555
    00556 {
    00557
    00558 #if 0
    00559
    00560     PKTHREAD ClientThread;
    00561     PCHANNEL_MESSAGE ClientView;
    00562     PRECHANNEL MessageChannel;
    00563     KPROCESSOR_MODE PreviousMode;
    00564     PECHANNEL ServerChannel;
    00565     PKTHREAD ServerThread;
    00566     NTSTATUS Status;
    00567
    00568     //
    00569     // Establish an exception handler, probe the output message address,
    00570     // probe the message text, and allocate a receive buffer if necessary.
    00571     // If either of the probes fail or the receive buffer allocation is
    00572     // not successful, then return the exception code as the service
    00573     // status.
    00574     //
    00575
    00576     ServerThread = KeGetCurrentThread();
    00577     try {
    00578
    00579         //
    00580         // Get previous processor mode and probe output message address and
    00581         // the message text if necessary.
    00582         //
    00583
    00584         PreviousMode = KeGetPreviousMode();
    00585         if (PreviousMode != KernelMode) {
    00586             ProbeForRead(Text, Length, sizeof(CHAR));
    00587             ProbeAndNullPointer(Message);
    00588         }
    00589
    00590         //
    00591         // If the current thread does not have an associated receive buffer,
    00592         // then attempt to allocate one now. If the allocation fails, then
    00593         // an exception is raised.
    00594         //
    00595
    00596         if (ServerThread->Section == NULL) {
    00597             KiAllocateReceiveBufferChannel();
    00598         }
    00599
    00600     } except(ExSystemExceptionFilter()) {
    00601         return GetExceptionCode();
    00602     }
    00603
    00604     //
    00605     // If the message length is greater than the host page size minus
    00606     // the message header length, then return an error.
    00607     //
    00608
    00609     if (Length >= (PAGE_SIZE - sizeof(CHANNEL_MESSAGE))) {
    00610         return  STATUS_BUFFER_OVERFLOW;
    00611     }
    00612
    00613     //
    00614     // If the server thread has an associated message channel, the channel
    00615     // is in server receive message state, and the channel server thread
    00616     // matches the current thread.
    00617     //
    00618     // This implies that:
    00619     //
    00620     // 1. The channel is a message channel.
    00621     //
    00622     // 2. The channel is being accessed by the server thread.
    00623     //
    00624     // 3. The channel is associated with a listen channel.
    00625     //
    00626     // 4. There is currently a server channel owner.
    00627     //
    00628     // 5. There is currently a client channel owner.
    00629     //
    00630
    00631     KiLockDispatcherDatabase(&ServerThread->WaitIrql);
    00632     MessageChannel = ServerThread->Channel;
    00633     if ((MessageChannel == NULL) ||
    00634         (MessageChannel->State != ServerReceiveMessage) ||
    00635         (MessageChannel->ServerThread != ServerThread)) {
    00636
    00637         //
    00638         // A message is not associated with the current thread,
    00639         // the message channel is in the wrong state, or the
    00640         // current thread is not the owner of the channel.
    00641         //
    00642
    00643         KiUnlockDispatcherDatabase(ServerThread->WaitIrql);
    00644         Status = STATUS_INVALID_PARAMETER; // **** fix ****
    00645
    00646     } else {
    00647
    00648         //
    00649         // Rendezvous with the client thread so a transfer of the
    00650         // reply text to the client thread can occur.
    00651         //
    00652
    00653         ClientThread = KiRendezvousWithThread(MessageChannel, PreviousMode);
    00654
    00655         //
    00656         // Control is returned when:
    00657         //
    00658         // 1. The server thread is being terminated (USER_APC).
    00659         //
    00660         // 2. A rendezvous with a client thread has occured.
    00661         //
    00662         // N.B. If the status value is less than zero, then it
    00663         //      is the address of the client thread.
    00664         //
    00665
    00666         if ((LONG)ClientThread < 0) {
    00667
    00668             //
    00669             // The client thread is returned as the rendezvous status
    00670             // with the thread in the transition state. Get the address
    00671             // of the client thread system view, establish an exception
    00672             // handler, and transfer the  message text from the server's
    00673             // buffer to the client's receive buffer. If an exception
    00674             // occurs during the copy, then return the exception code
    00675             // as the service status.
    00676             //
    00677
    00678             ClientView = ClientThread->SystemView;
    00679             Status = STATUS_SUCCESS;
    00680             if (Length != 0) {
    00681                 try {
    00682                     RtlCopyMemory(ClientView + 1, Text, Length);
    00683
    00684                 } except (ExSystemExceptionFilter()) {
    00685                     Status = GetExceptionCode();
    00686                 }
    00687             }
    00688
    00689             //
    00690             // Set the channel message parameters.
    00691             //
    00692
    00693             ClientView->Text = (PVOID)(ClientThread->ThreadView + 1);
    00694             ClientView->Length = Length;
    00695             ClientView->Context = NULL;
    00696             ClientView->Base = Text;
    00697             ClientView->Close = FALSE;
    00698
    00699             //
    00700             // Raise IRQL to dispatch level, lock the dispatcher
    00701             // database, and check if the message was successfully
    00702             // transfered to the client's receive buffer. If the
    00703             // message was successfully transfered to the client's
    00704             // receive buffer. then reset the channel state, fill
    00705             // in the message parameters, ready the client thread,
    00706             // and listen for the next message. Otherwise, set the
    00707             // client wait status and ready the client thread for
    00708             // execution.
    00709             //
    00710
    00711             KiLockDispatcherDatabase(&ServerThread->WaitIrql);
    00712             if (NT_SUCCESS(Status)) {
    00713                 MessageChannel->State = ClientIdle;
    00714                 MessageChannel->ClientThread = NULL;
    00715                 MessageChannel->ServerThread = NULL;
    00716                 ClientThread->WaitStatus = STATUS_SUCCESS;
    00717
    00718                 //
    00719                 // Reference the server channel and dereference the
    00720                 // message channel.
    00721                 //
    00722
    00723                 ServerChannel = MessageChannel->ServerChannel;
    00724                 ObReferenceObject(ServerChannel);
    00725                 ObDereferenceObject(MessageChannel);
    00726
    00727                 //
    00728                 // If there are no clients waiting to send to the server,
    00729                 // then switch directly to the client thread. Otherwise,
    00730                 // ready the client thread, then listen for the next
    00731                 // message.
    00732                 //
    00733
    00734                 if (IsListEmpty(&ServerChannel->ClearToSendEvent.Header.WaitListHead) == FALSE) {
    00735                     KiReadyThread(ClientThread);
    00736                     KiUnlockDispatcherDatabase(ServerThread->WaitIrql);
    00737                     Status = KiListenChannel(ServerChannel,
    00738                                              PreviousMode,
    00739                                              Message);
    00740
    00741                 } else {
    00742                     Status = KiSwitchToThread(ClientThread,
    00743                                               WrRendezvous,
    00744                                               PreviousMode,
    00745                                               &ServerChannel->ReceiveEvent);
    00746
    00747                     //
    00748                     // If a client message was successfully received, then
    00749                     // attempt to write the address of the send message
    00750                     // address. If the write attempt fails, then do not
    00751                     // report an error. When the caller attempts to access
    00752                     // the message address, an access violation will occur.
    00753                     //
    00754
    00755                     if (NT_SUCCESS(Status)) {
    00756                         try {
    00757                             *Message = ServerThread->ThreadView;
    00758
    00759                         } except(ExSystemExceptionFilter()) {
    00760                         }
    00761                     }
    00762                 }
    00763
    00764                 ObDereferenceObject(ServerChannel);
    00765
    00766             } else {
    00767
    00768                 //
    00769                 // The reply message was not successfully transfered
    00770                 // to the client receive buffer because of an access
    00771                 // violation encountered durring the access to the
    00772                 // server buffer.
    00773                 //
    00774
    00775                 ClientThread->WaitStatus = STATUS_KERNEL_APC;
    00776                 KiReadyThread(ClientThread);
    00777                 KiUnlockDispatcherDatabase(ServerThread->WaitIrql);
    00778             }
    00779
    00780         } else {
    00781
    00782             //
    00783             // The server thread is terminating and the channel
    00784             // structures will be cleaned up by the termiantion
    00785             // code.
    00786             //
    00787
    00788             Status = (NTSTATUS)ClientThread;
    00789         }
    00790     }
    00791
    00792     //
    00793     // Return service status.
    00794     //
    00795
    00796     return Status;
    00797
    00798 #else
    00799
    00800     return STATUS_NOT_IMPLEMENTED;
    00801
    00802 #endif
    00803
    00804 }
    00805
    00806 NTSTATUS
    00807 NtSendWaitReplyChannel (
    00808     IN HANDLE ChannelHandle,
    00809     IN PVOID Text,
    00810     IN ULONG Length,
    00811     OUT PCHANNEL_MESSAGE *Message
    00812     )
    00813
    00814 /*++
    00815
    00816 Routine Description:
    00817
    00818     This function sends a message to a server and waits for a reply.
    00819
    00820     N.B. This function can only be executed from a client thread.
    00821
    00822 Arguments:
    00823
    00824     ChannelHandle - Supplies a handle to a message channel over which the
    00825         specified message text is sent.
    00826
    00827     Text - Supplies a pointer to the message text.
    00828
    00829     Length - Supplies the length of the message text.
    00830
    00831     Message - Supplies a pointer to a variable that receives a pointer
    00832         to the reply message header.
    00833
    00834 Return Value:
    00835
    00836     If the function is successfully completed, then a success status is
    00837     returned. Otherwise, a failure status is returned.
    00838
    00839 --*/
    00840
    00841 {
    00842
    00843 #if 0
    00844
    00845     PKTHREAD ClientThread;
    00846     PRECHANNEL MessageChannel;
    00847     KPROCESSOR_MODE PreviousMode;
    00848     PRECHANNEL ServerChannel;
    00849     PKTHREAD ServerThread;
    00850     PCHANNEL_MESSAGE ServerView;
    00851     NTSTATUS Status;
    00852
    00853     //
    00854     // Establish an exception handler, probe the output message address,
    00855     // probe the message text, and allocate a receive buffer if necessary.
    00856     // If either of the probes fail or the receive buffer allocation is
    00857     // not successful, then return the exception code as the service
    00858     // status.
    00859     //
    00860
    00861     ClientThread = KeGetCurrentThread();
    00862     try {
    00863
    00864         //
    00865         // Get previous processor mode and probe output message address
    00866         // and the message text.
    00867         //
    00868
    00869         PreviousMode = KeGetPreviousMode();
    00870         if (PreviousMode != KernelMode) {
    00871             ProbeForRead(Text, Length, sizeof(UCHAR));
    00872             ProbeAndNullPointer(Message);
    00873         }
    00874
    00875         //
    00876         // If the current thread does not have an associated receive buffer,
    00877         // then attempt to allocate one now. If the allocation fails, then
    00878         // an exception is raised.
    00879         //
    00880
    00881         if (ClientThread->Section == NULL) {
    00882             KiAllocateReceiveBufferChannel();
    00883         }
    00884
    00885     } except(ExSystemExceptionFilter()) {
    00886         return GetExceptionCode();
    00887     }
    00888
    00889     //
    00890     // If the message length is greater than the host page size minus
    00891     // the message header length, then return an error.
    00892     //
    00893
    00894     if (Length >= (PAGE_SIZE - sizeof(CHANNEL_MESSAGE))) {
    00895         return STATUS_BUFFER_OVERFLOW;
    00896     }
    00897
    00898     //
    00899     // Reference channel object by handle.
    00900     //
    00901
    00902     Status = ObReferenceObjectByHandle(ChannelHandle,
    00903                                        CHANNEL_ALL_ACCESS,
    00904                                        KeChannelType,
    00905                                        PreviousMode,
    00906                                        (PVOID *)&MessageChannel,
    00907                                        NULL);
    00908
    00909     //
    00910     // If the reference was successful, then check if the channel is in
    00911     // the client idle state.
    00912     //
    00913     // This implies that:
    00914     //
    00915     // 1. The channel is a message channel.
    00916     //
    00917     // 2. The channel is being accessed by a client thread.
    00918     //
    00919     // 3. The channel is connected to a listen channel.
    00920     //
    00921     // 4. There is currently no client thread channel owner.
    00922     //
    00923     // 5. There is currently no server thread channel owner.
    00924     //
    00925
    00926     if (NT_SUCCESS(Status)) {
    00927         KiLockDispatcherDatabase(&ClientThread->WaitIrql);
    00928         if (MessageChannel->State != ClientIdle) {
    00929
    00930             //
    00931             // The message channel is in the wrong state.
    00932             //
    00933
    00934             KiUnlockDispatcherDatabase(ClientThread->WaitIrql);
    00935             Status = STATUS_INVALID_PARAMETER; // **** fix ****
    00936
    00937         } else {
    00938
    00939             //
    00940             // Set the channel state, set the client owner thread, and
    00941             // rendezvous with a server thread.
    00942             //
    00943
    00944             MessageChannel->State = ClientSendWaitReply;
    00945             MessageChannel->ClientThread = ClientThread;
    00946             ClientThread->Channel = MessageChannel;
    00947             ServerChannel = MessageChannel->ServerChannel;
    00948             ServerThread = KiRendezvousWithThread(ServerChannel, PreviousMode);
    00949
    00950             //
    00951             // Control is returned when:
    00952             //
    00953             // 1. The client thread is being terminated (USER_APC).
    00954             //
    00955             // 2. A rendezvous with a server thread has occured.
    00956             //
    00957             // N.B. If the status value is less than zero, then it
    00958             //      is the address of the server thread.
    00959             //
    00960
    00961             if ((LONG)ServerThread < 0) {
    00962
    00963                 //
    00964                 // The server thread is returned as the rendezvous status
    00965                 // with the thread in the transition state. Get the address
    00966                 // of the server thread system view, establish an exception
    00967                 // handler, and transfer the message text from the client's
    00968                 // buffer to the server's receive buffer. If an exception
    00969                 // occurs during the copy, then return the exception code
    00970                 // as the service status.
    00971                 //
    00972
    00973                 ServerView = ServerThread->SystemView;
    00974                 if (Length != 0) {
    00975                     try {
    00976                         RtlCopyMemory(ServerView + 1, Text, Length);
    00977
    00978                     } except (ExSystemExceptionFilter()) {
    00979                         Status = GetExceptionCode();
    00980                     }
    00981                 }
    00982
    00983                 //
    00984                 // Set the channel message parameters.
    00985                 //
    00986
    00987                 ServerView->Text = (PVOID)(ServerThread->ThreadView + 1);
    00988                 ServerView->Length = Length;
    00989                 ServerView->Context = MessageChannel->ServerContext;
    00990                 ServerView->Base = Text;
    00991                 ServerView->Close = FALSE;
    00992
    00993                 //
    00994                 // Raise IRQL to dispatch level, lock the dispatcher
    00995                 // database and check if the message was successfully
    00996                 // transfered to the server's receive buffer. If the
    00997                 // message was successfully transfered, then set the
    00998                 // channel state, set the server thread address, set
    00999                 // the address of the message channel in the server
    01000                 // thread, increment the message channel reference
    01001                 // count, fill in the message parameters, and switch
    01002                 // directly to the server thread. Otherwise, set the
    01003                 // channel state, and reready the server thread for
    01004                 // execution.
    01005                 //
    01006
    01007                 KiLockDispatcherDatabase(&ClientThread->WaitIrql);
    01008                 if (NT_SUCCESS(Status)) {
    01009                     MessageChannel->State = ServerReceiveMessage;
    01010                     MessageChannel->ServerThread = ServerThread;
    01011                     ObReferenceObject(MessageChannel);
    01012                     ServerThread->Channel = MessageChannel;
    01013                     Status = KiSwitchToThread(ServerThread,
    01014                                               WrRendezvous,
    01015                                               PreviousMode,
    01016                                               &MessageChannel->ReceiveEvent);
    01017
    01018                     //
    01019                     // If the send and subsequent reply from the server
    01020                     // thread is successful, then attempt to write the
    01021                     // address of the reply message address. If the write
    01022                     // attempt fails, then do not report an error. When
    01023                     // the caller attempts to access the message address,
    01024                     // an access violation will occur.
    01025                     //
    01026
    01027                     if (NT_SUCCESS(Status)) {
    01028                         try {
    01029                             *Message = ClientThread->ThreadView;
    01030
    01031                         } except(ExSystemExceptionFilter()) {
    01032                         }
    01033                     }
    01034
    01035                 } else {
    01036
    01037                     //
    01038                     // The send message was not successfully transfered
    01039                     // to the server receive buffer because of an access
    01040                     // violation encountered durring the access to the
    01041                     // client buffer.
    01042                     //
    01043
    01044                     MessageChannel->State = ClientIdle;
    01045                     MessageChannel->ClientThread = NULL;
    01046                     ClientThread->Channel = NULL;
    01047                     ServerThread->WaitStatus = STATUS_KERNEL_APC;
    01048                     KiReadyThread(ServerThread);
    01049                     KiUnlockDispatcherDatabase(ClientThread->WaitIrql);
    01050                 }
    01051
    01052             } else {
    01053
    01054                 //
    01055                 // The client thread is terminating and the channel
    01056                 // structures will be cleaned up by the termination
    01057                 // code.
    01058                 //
    01059
    01060                 Status = (NTSTATUS)ServerThread;
    01061             }
    01062         }
    01063
    01064         ObDereferenceObject(MessageChannel);
    01065     }
    01066
    01067     //
    01068     // Return service status.
    01069     //
    01070
    01071     return Status;
    01072
    01073 #else
    01074
    01075     return STATUS_NOT_IMPLEMENTED;
    01076
    01077 #endif
    01078
    01079 }
    01080
    01081 NTSTATUS
    01082 NtSetContextChannel (
    01083     IN PVOID Context
    01084     )
    01085
    01086 /*++
    01087
    01088 Routine Description:
    01089
    01090     This function stores a context value for the current associated
    01091     message channel.
    01092
    01093     N.B. This function can only be executed from a server thread that
    01094         has an associated message channel.
    01095
    01096 Arguments:
    01097
    01098     Context - Supplies a context value that is to be stored in the
    01099         associated message channel.
    01100
    01101 Return Value:
    01102
    01103     If the channel information is set, then a success status is returned.
    01104     Otherwise, a failure status is returned.
    01105
    01106 --*/
    01107
    01108 {
    01109
    01110 #if 0
    01111
    01112     PRECHANNEL MessageChannel;
    01113     PKTHREAD CurrentThread;
    01114     NTSTATUS Status;
    01115
    01116     //
    01117     // If the thread has an assoicated channel and the server thread for
    01118     // the channel is the current thread, then store the channel context.
    01119     //
    01120
    01121     CurrentThread = KeGetCurrentThread();
    01122     MessageChannel = CurrentThread->Channel;
    01123     if ((MessageChannel == NULL) ||
    01124         (CurrentThread != MessageChannel->ServerThread)) {
    01125         Status = STATUS_INVALID_PARAMETER; // ****** FIX *****
    01126
    01127     } else {
    01128         MessageChannel->ServerContext = Context;
    01129         Status = STATUS_SUCCESS;
    01130     }
    01131
    01132     //
    01133     // Return service status.
    01134     //
    01135
    01136     return Status;
    01137
    01138 #else
    01139
    01140     return STATUS_NOT_IMPLEMENTED;
    01141
    01142 #endif
    01143
    01144 }
    01145
    01146 #if 0
    01147
    01148
    01149 VOID
    01150 KiAllocateReceiveBufferChannel (
    01151     VOID
    01152     )
    01153
    01154 /*++
    01155
    01156 Routine Description:
    01157
    01158     This function creates an unnamed section with a single page, maps
    01159     a view of the section into the current process and into the system
    01160     address space, and associates the view with the current thread.
    01161
    01162 Arguments:
    01163
    01164     None.
    01165
    01166 Return Value:
    01167
    01168     If a channel receive buffer is not allocated, then raise an exception.
    01169
    01170 --*/
    01171
    01172 {
    01173
    01174     LARGE_INTEGER MaximumSize;
    01175     PEPROCESS Process;
    01176     NTSTATUS Status;
    01177     PKTHREAD Thread;
    01178     LARGE_INTEGER ViewOffset;
    01179     ULONG ViewSize;
    01180
    01181     //
    01182     // Create an unnamed section object.
    01183     //
    01184
    01185     Thread = KeGetCurrentThread();
    01186
    01187     ASSERT(Thread->Section == NULL);
    01188
    01189     MaximumSize.QuadPart = PAGE_SIZE;
    01190     Status = MmCreateSection(&Thread->Section,
    01191                              0,
    01192                              NULL,
    01193                              &MaximumSize,
    01194                              PAGE_READWRITE,
    01195                              SEC_COMMIT,
    01196                              NULL,
    01197                              NULL);
    01198
    01199     if (NT_SUCCESS(Status)) {
    01200
    01201         //
    01202         // Map a view of the section into the current process.
    01203         //
    01204
    01205         Process = PsGetCurrentProcess();
    01206         ViewOffset.QuadPart = 0;
    01207         ViewSize = PAGE_SIZE;
    01208         Status = MmMapViewOfSection(Thread->Section,
    01209                                     Process,
    01210                                     &Thread->ThreadView,
    01211                                     0,
    01212                                     ViewSize,
    01213                                     &ViewOffset,
    01214                                     &ViewSize,
    01215                                     ViewUnmap,
    01216                                     0,
    01217                                     PAGE_READWRITE);
    01218
    01219         if (NT_SUCCESS(Status)) {
    01220
    01221             //
    01222             // Map a view of the section into the system address
    01223             // space.
    01224             //
    01225
    01226             Status = MmMapViewInSystemSpace(Thread->Section,
    01227                                             &Thread->SystemView,
    01228                                             &ViewSize);
    01229
    01230             if (NT_SUCCESS(Status)) {
    01231                 return;
    01232             }
    01233
    01234             MmUnmapViewOfSection(Process, Thread->ThreadView);
    01235         }
    01236
    01237         ObDereferenceObject(Thread->Section);
    01238     }
    01239
    01240     //
    01241     // The allocation of a receive buffer was not successful. Raise an
    01242     // exception that will be caught by the caller.
    01243     //
    01244
    01245     ExRaiseStatus(Status);
    01246     return;
    01247 }
    01248
    01249 BOOLEAN
    01250 KiChannelInitialization (
    01251     VOID
    01252     )
    01253
    01254 /*++
    01255
    01256 Routine Description:
    01257
    01258     This function creates the channel object type descriptor at system
    01259     initialization and stores the address of the object type descriptor
    01260     in global storage.
    01261
    01262 Arguments:
    01263
    01264     None.
    01265
    01266 Return Value:
    01267
    01268     A value of TRUE is returned if the channel object type descriptor is
    01269     successfully initialized. Otherwise a value of FALSE is returned.
    01270
    01271 --*/
    01272
    01273 {
    01274
    01275     OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
    01276     NTSTATUS Status;
    01277     UNICODE_STRING TypeName;
    01278
    01279     //
    01280     // Initialize string descriptor.
    01281     //
    01282
    01283     RtlInitUnicodeString(&TypeName, L"Channel");
    01284
    01285     //
    01286     // Create channel object type descriptor.
    01287     //
    01288
    01289     RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
    01290     ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
    01291     ObjectTypeInitializer.GenericMapping = KiChannelMapping;
    01292     ObjectTypeInitializer.PoolType = NonPagedPool;
    01293     ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(ECHANNEL);
    01294     ObjectTypeInitializer.ValidAccessMask = CHANNEL_ALL_ACCESS;
    01295     ObjectTypeInitializer.InvalidAttributes = OBJ_EXCLUSIVE | OBJ_INHERIT | OBJ_PERMANENT;
    01296     ObjectTypeInitializer.CloseProcedure = KiCloseChannel;
    01297     ObjectTypeInitializer.DeleteProcedure = KiDeleteChannel;
    01298     Status = ObCreateObjectType(&TypeName,
    01299                                 &ObjectTypeInitializer,
    01300                                 NULL,
    01301                                 &KeChannelType);
    01302
    01303     //
    01304     // If the channel object type descriptor was successfully created, then
    01305     // return a value of TRUE. Otherwise return a value of FALSE.
    01306     //
    01307
    01308     return (BOOLEAN)(NT_SUCCESS(Status));
    01309 }
    01310
    01311 VOID
    01312 KiCloseChannel (
    01313     IN PEPROCESS Process,
    01314     IN PVOID Object,
    01315     IN ACCESS_MASK GrantedAccess,
    01316     IN ULONG ProcessHandleCount,
    01317     IN ULONG SystemHandleCount
    01318     )
    01319
    01320 /*++
    01321
    01322 Routine Description:
    01323
    01324     This function is called when a handle to a channel is closed. If the
    01325     hanlde is the last handle in the process to the channel object and
    01326     the channel object is a message channel, then send a message to the
    01327     server indicating that the client handle is being closed.
    01328
    01329 Arguments:
    01330
    01331     Object - Supplies a pointer to an executive channel.
    01332
    01333 Return Value:
    01334
    01335     None.
    01336
    01337 --*/
    01338
    01339 {
    01340     PECHANNEL MessageChannel = (PECHANNEL)Object;
    01341
    01342     //
    01343     // If the object is a message channel and hte last handle is being
    01344     // closed, then send a message to the server indicating that the
    01345     // channel is being closed.
    01346     //
    01347
    01348     if ((MessageChannel->ServerChannel != NULL) &&
    01349         (ProcessHandleCount == 1)) {
    01350     }
    01351
    01352     return;
    01353 }
    01354
    01355 VOID
    01356 KiDeleteChannel (
    01357     IN PVOID Object
    01358     )
    01359
    01360 /*++
    01361
    01362 Routine Description:
    01363
    01364     This function is the delete routine for channel objects. Its function
    01365     is to ...
    01366
    01367 Arguments:
    01368
    01369     Object - Supplies a pointer to an executive channel.
    01370
    01371 Return Value:
    01372
    01373     None.
    01374
    01375 --*/
    01376
    01377 {
    01378
    01379     PRECHANNEL ChannelObject = (PECHANNEL)Object;
    01380
    01381     //
    01382     // If the channel is a message channel, then dereference the connnected
    01383     // server channel.
    01384     //
    01385
    01386     if (ChannelObject->ServerChannel != NULL) {
    01387         ObDereferenceObject(ChannelObject->ServerChannel);
    01388     }
    01389
    01390     return;
    01391 }
    01392
    01393 VOID
    01394 KiRundownChannel (
    01395     VOID
    01396     )
    01397
    01398 /*++
    01399
    01400 Routine Description:
    01401
    01402     This function runs down associated channel object and receive buffers
    01403     when the a thread is terminated.
    01404
    01405 Arguments:
    01406
    01407     None.
    01408
    01409 Return Value:
    01410
    01411     None.
    01412
    01413 --*/
    01414
    01415 {
    01416
    01417     PKTHREAD Thread;
    01418
    01419     //
    01420     // If the current thread has an associated receive buffer, then unmap
    01421     // the receive buffer and dereference the underlying section.
    01422     //
    01423
    01424     Thread = KeGetCurrentThread();
    01425     if (Thread->Section != NULL) {
    01426         MmUnmapViewOfSection(PsGetCurrentProcess(), Thread->ThreadView);
    01427         MmUnmapViewInSystemSpace(Thread->SystemView);
    01428         ObDereferenceObject(Thread->Section);
    01429         Thread->Section = NULL;
    01430     }
    01431
    01432     //
    01433     // If the current thread has an associated channel, then ...
    01434     //
    01435
    01436     return;
    01437 }
    01438
    01439 NTSTATUS
    01440 KiListenChannel (
    01441     IN PRECHANNEL ServerChannel,
    01442     IN KPROCESSOR_MODE WaitMode,
    01443     OUT PCHANNEL_MESSAGE *Message
    01444     )
    01445
    01446 /*++
    01447
    01448 Routine Description:
    01449
    01450     This function listens for a client message to arrive.
    01451
    01452     N.B. This function can only be executed from a server thread.
    01453
    01454 Arguments:
    01455
    01456     ServerChannel - Supplies a pointer to a litent channel on which the
    01457         server thread listens.
    01458
    01459     WaitMode - Supplies the processor wait mode.
    01460
    01461     Message - Supplies a pointer to a variable that receives a pointer
    01462         to the client message header.
    01463
    01464 Return Value:
    01465
    01466     If the function is successfully completed, then a success status is
    01467     returned. Otherwise, a failure status is returned.
    01468
    01469 --*/
    01470
    01471 {
    01472
    01473     PKEVENT ClearToSendEvent;
    01474     PKTHREAD ClientThread;
    01475     PKQUEUE Queue;
    01476     PKTHREAD ServerThread;
    01477     PKWAIT_BLOCK WaitBlock;
    01478     PLIST_ENTRY WaitEntry;
    01479     NTSTATUS WaitStatus;
    01480
    01481     //
    01482     // Raise IRQL to dispatch level and lock the dispatcher database.
    01483     //
    01484
    01485     ServerThread = KeGetCurrentThread();
    01486     KiLockDispatcherDatabase(&ServerThread->WaitIrql);
    01487
    01488     //
    01489     // Start of wait loop.
    01490     //
    01491     // Note this loop is repeated if a kernel APC is delivered in the
    01492     // middle of the wait or a kernel APC is pending on the first attempt
    01493     // through the loop.
    01494     //
    01495
    01496     do {
    01497
    01498         //
    01499         // Check if there is a thread waiting on the clear to send event.
    01500         //
    01501
    01502         ClearToSendEvent = &ServerChannel->ClearToSendEvent;
    01503         WaitEntry = ClearToSendEvent->Header.WaitListHead.Flink;
    01504         if (WaitEntry != &ClearToSendEvent->Header.WaitListHead) {
    01505             WaitBlock = CONTAINING_RECORD(WaitEntry, KWAIT_BLOCK, WaitListEntry);
    01506             ClientThread = WaitBlock->Thread;
    01507
    01508             //
    01509             // Remove the wait block from the wait list of the receive event,
    01510             // and remove the client thread from the wait list.
    01511             //
    01512
    01513             RemoveEntryList(&WaitBlock->WaitListEntry);
    01514             RemoveEntryList(&ClientThread->WaitListEntry);
    01515
    01516             //
    01517             // If the client thread is processing a queue entry, then increment the
    01518             // count of currently active threads.
    01519             //
    01520
    01521             Queue = ClientThread->Queue;
    01522             if (Queue != NULL) {
    01523                 Queue->CurrentCount += 1;
    01524             }
    01525
    01526             //
    01527             // Set the wait completion status to kernel APC so the client
    01528             // will attempt another rendezvous and ready the client thread
    01529             // for execution.
    01530             //
    01531
    01532             ClientThread->WaitStatus = STATUS_KERNEL_APC;
    01533             KiReadyThread(ClientThread);
    01534         }
    01535
    01536         //
    01537         // Test to determine if a kernel APC is pending.
    01538         //
    01539         // If a kernel APC is pending and the previous IRQL was less than
    01540         // APC_LEVEL, then a kernel APC was queued by another processor
    01541         // just after IRQL was raised to DISPATCH_LEVEL, but before the
    01542         // dispatcher database was locked.
    01543         //
    01544         // N.B. that this can only happen in a multiprocessor system.
    01545         //
    01546
    01547         if (ServerThread->ApcState.KernelApcPending &&
    01548             (ServerThread->WaitIrql < APC_LEVEL)) {
    01549
    01550             //
    01551             // Unlock the dispatcher database and lower IRQL to its
    01552             // previous value. An APC interrupt will immediately occur
    01553             // which will result in the delivery of the kernel APC if
    01554             // possible.
    01555             //
    01556
    01557             KiUnlockDispatcherDatabase(ServerThread->WaitIrql);
    01558
    01559         } else {
    01560
    01561             //
    01562             // Test if a user APC is pending.
    01563             //
    01564
    01565             if ((WaitMode != KernelMode) &&
    01566                 (ServerThread->ApcState.UserApcPending)) {
    01567                 WaitStatus = STATUS_USER_APC;
    01568                 break;
    01569             }
    01570
    01571             //
    01572             // Construct a wait block for the clear to send event object.
    01573             //
    01574
    01575             WaitBlock = &ServerThread->WaitBlock[0];
    01576             ServerThread->WaitBlockList = WaitBlock;
    01577             ServerThread->WaitStatus = (NTSTATUS)0;
    01578             WaitBlock->Object = (PVOID)&ServerChannel->ReceiveEvent;
    01579             WaitBlock->NextWaitBlock = WaitBlock;
    01580             WaitBlock->WaitKey = (CSHORT)STATUS_SUCCESS;
    01581             WaitBlock->WaitType = WaitAny;
    01582             InsertTailList(&ServerChannel->ReceiveEvent.Header.WaitListHead,
    01583                            &WaitBlock->WaitListEntry);
    01584
    01585             //
    01586             // If the current thread is processing a queue entry, then
    01587             // attempt to activate another thread that is blocked on the
    01588             // queue object.
    01589             //
    01590
    01591             Queue = ServerThread->Queue;
    01592             if (Queue != NULL) {
    01593                 KiActivateWaiterQueue(Queue);
    01594             }
    01595
    01596             //
    01597             // Set the thread wait parameters, set the thread dispatcher
    01598             // state to Waiting, and insert the thread in the wait list.
    01599             //
    01600
    01601             ServerThread->Alertable = FALSE;
    01602             ServerThread->WaitMode = WaitMode;
    01603             ServerThread->WaitReason = WrRendezvous;
    01604             ServerThread->WaitTime = KiQueryLowTickCount();
    01605             ServerThread->State = Waiting;
    01606             KiInsertWaitList(WaitMode, ServerThread);
    01607
    01608             //
    01609             // Switch context to selected thread.
    01610             //
    01611             // Control is returned at the original IRQL.
    01612             //
    01613
    01614             ASSERT(KeIsExecutingDpc() == FALSE);
    01615             ASSERT(ServerThread->WaitIrql <= DISPATCH_LEVEL);
    01616
    01617             WaitStatus = KiSwapThread();
    01618
    01619             //
    01620             // If the thread was not awakened to deliver a kernel mode APC,
    01621             // then return wait status.
    01622             //
    01623
    01624             if (WaitStatus != STATUS_KERNEL_APC) {
    01625
    01626                 //
    01627                 // If a client message was successfully received, then
    01628                 // attempt to write the address of the send message
    01629                 // address. If the write attempt fails, then do not
    01630                 // report an error. When the caller attempts to access
    01631                 // the message address, an access violation will occur.
    01632                 //
    01633
    01634                   if (NT_SUCCESS(WaitStatus)) {
    01635                       try {
    01636                           *Message = ServerThread->ThreadView;
    01637
    01638                       } except(ExSystemExceptionFilter()) {
    01639                       }
    01640                   }
    01641
    01642                 return WaitStatus;
    01643             }
    01644         }
    01645
    01646         //
    01647         // Raise IRQL to DISPATCH_LEVEL and lock the dispatcher database.
    01648         //
    01649
    01650         KiLockDispatcherDatabase(&ServerThread->WaitIrql);
    01651     } while (TRUE);
    01652
    01653     //
    01654     // Unlock the dispatcher database and return the target thread.
    01655     //
    01656
    01657     KiUnlockDispatcherDatabase(ServerThread->WaitIrql);
    01658     return WaitStatus;
    01659 }
    01660
    01661 PKTHREAD
    01662 KiRendezvousWithThread (
    01663     IN PRECHANNEL WaitChannel,
    01664     IN ULONG WaitMode
    01665     )
    01666
    01667 /*++
    01668
    01669 Routine Description:
    01670
    01671     This function performs a rendezvous with a thread waiting on the
    01672     channel receive event.
    01673
    01674     N.B. This routine is called with the dispatcher database locked.
    01675
    01676     N.B. The wait IRQL is assumed to be set for the current thread.
    01677
    01678     N.B. Control is returned from this function with the dispatcher
    01679         database unlocked.
    01680
    01681 Arguments:
    01682
    01683     WaitChannel - Supplies a pointer to a channel whose receive event
    01684         is the target of the rendezvous operation.
    01685
    01686     WaitMode - Supplies the processor wait mode.
    01687
    01688 Return Value:
    01689
    01690     If a thread rendezvous is successfully performed, then the address
    01691     of the thread object is returned as the completion status. Otherwise,
    01692     if the wait completes because of a timeout or because the thread is
    01693     being terminated, then the appropriate status is returned.
    01694
    01695 --*/
    01696
    01697 {
    01698
    01699     PKTHREAD CurrentThread;
    01700     PKQUEUE Queue;
    01701     PKTHREAD TargetThread;
    01702     PKWAIT_BLOCK WaitBlock;
    01703     PLIST_ENTRY WaitEntry;
    01704     NTSTATUS WaitStatus;
    01705
    01706     //
    01707     // Start of wait loop.
    01708     //
    01709     // Note this loop is repeated if a kernel APC is delivered in the
    01710     // middle of the wait or a kernel APC is pending on the first attempt
    01711     // through the loop.
    01712     //
    01713     // If the rendezvous event wait list is not empty, then remove the first
    01714     // entry from the list, compute the address of the respective thread,
    01715     // cancel the thread timer if appropraite, and return the thread address.
    01716     // Otherwise, wait for a thread to rendezvous with.
    01717     //
    01718
    01719     CurrentThread = KeGetCurrentThread();
    01720     do {
    01721
    01722         //
    01723         // Check if there is a thread waiting on the rendezvous event.
    01724         //
    01725
    01726         WaitEntry = WaitChannel->ReceiveEvent.Header.WaitListHead.Flink;
    01727         if (WaitEntry != &WaitChannel->ReceiveEvent.Header.WaitListHead) {
    01728             WaitBlock = CONTAINING_RECORD(WaitEntry, KWAIT_BLOCK, WaitListEntry);
    01729             TargetThread = WaitBlock->Thread;
    01730
    01731             //
    01732             // Remove the wait block from the wait list of the receive event,
    01733             // and remove the target thread from the wait list.
    01734             //
    01735
    01736             RemoveEntryList(&WaitBlock->WaitListEntry);
    01737             RemoveEntryList(&TargetThread->WaitListEntry);
    01738
    01739             //
    01740             // If the target thread is processing a queue entry, then increment the
    01741             // count of currently active threads.
    01742             //
    01743
    01744             Queue = TargetThread->Queue;
    01745             if (Queue != NULL) {
    01746                 Queue->CurrentCount += 1;
    01747             }
    01748
    01749             //
    01750             // Set the thread state to transistion.
    01751             //
    01752
    01753             TargetThread->State = Transition;
    01754             break;
    01755
    01756         } else {
    01757
    01758             //
    01759             // Test to determine if a kernel APC is pending.
    01760             //
    01761             // If a kernel APC is pending and the previous IRQL was less than
    01762             // APC_LEVEL, then a kernel APC was queued by another processor
    01763             // just after IRQL was raised to DISPATCH_LEVEL, but before the
    01764             // dispatcher database was locked.
    01765             //
    01766             // N.B. that this can only happen in a multiprocessor system.
    01767             //
    01768
    01769             if (CurrentThread->ApcState.KernelApcPending &&
    01770                 (CurrentThread->WaitIrql < APC_LEVEL)) {
    01771
    01772                 //
    01773                 // Unlock the dispatcher database and lower IRQL to its
    01774                 // previous value. An APC interrupt will immediately occur
    01775                 // which will result in the delivery of the kernel APC if
    01776                 // possible.
    01777                 //
    01778
    01779                 KiUnlockDispatcherDatabase(CurrentThread->WaitIrql);
    01780
    01781             } else {
    01782
    01783                 //
    01784                 // Test if a user APC is pending.
    01785                 //
    01786
    01787                 if ((WaitMode != KernelMode) &&
    01788                     (CurrentThread->ApcState.UserApcPending)) {
    01789                     TargetThread = (PKTHREAD)STATUS_USER_APC;
    01790                     break;
    01791                 }
    01792
    01793                 //
    01794                 // Construct a wait block for the clear to send event object.
    01795                 //
    01796
    01797                 WaitBlock = &CurrentThread->WaitBlock[0];
    01798                 CurrentThread->WaitBlockList = WaitBlock;
    01799                 CurrentThread->WaitStatus = (NTSTATUS)0;
    01800                 WaitBlock->Object = (PVOID)&WaitChannel->ClearToSendEvent;
    01801                 WaitBlock->NextWaitBlock = WaitBlock;
    01802                 WaitBlock->WaitKey = (CSHORT)STATUS_SUCCESS;
    01803                 WaitBlock->WaitType = WaitAny;
    01804                 InsertTailList(&WaitChannel->ClearToSendEvent.Header.WaitListHead,
    01805                                &WaitBlock->WaitListEntry);
    01806
    01807                 //
    01808                 // If the current thread is processing a queue entry, then
    01809                 // attempt to activate another thread that is blocked on the
    01810                 // queue object.
    01811                 //
    01812
    01813                 Queue = CurrentThread->Queue;
    01814                 if (Queue != NULL) {
    01815                     KiActivateWaiterQueue(Queue);
    01816                 }
    01817
    01818                 //
    01819                 // Set the thread wait parameters, set the thread dispatcher
    01820                 // state to Waiting, and insert the thread in the wait list.
    01821                 //
    01822
    01823                 CurrentThread->Alertable = FALSE;
    01824                 CurrentThread->WaitMode = (KPROCESSOR_MODE)WaitMode;
    01825                 CurrentThread->WaitReason = WrRendezvous;
    01826                 CurrentThread->WaitTime = KiQueryLowTickCount();
    01827                 CurrentThread->State = Waiting;
    01828                 KiInsertWaitList(WaitMode, CurrentThread);
    01829
    01830                 //
    01831                 // Switch context to selected thread.
    01832                 //
    01833                 // Control is returned at the original IRQL.
    01834                 //
    01835
    01836                 ASSERT(KeIsExecutingDpc() == FALSE);
    01837                 ASSERT(CurrentThread->WaitIrql <= DISPATCH_LEVEL);
    01838
    01839                 WaitStatus = KiSwapThread();
    01840
    01841                 //
    01842                 // If the thread was not awakened to deliver a kernel mode APC,
    01843                 // then return wait status.
    01844                 //
    01845
    01846                 if (WaitStatus != STATUS_KERNEL_APC) {
    01847                     return (PKTHREAD)WaitStatus;
    01848                 }
    01849             }
    01850
    01851             //
    01852             // Raise IRQL to DISPATCH_LEVEL and lock the dispatcher database.
    01853             //
    01854
    01855             KiLockDispatcherDatabase(&CurrentThread->WaitIrql);
    01856         }
    01857
    01858     } while (TRUE);
    01859
    01860     //
    01861     // Unlock the dispatcher database and return the target thread.
    01862     //
    01863
    01864     KiUnlockDispatcherDatabase(CurrentThread->WaitIrql);
    01865     return TargetThread;
    01866 }
    01867
    01868 #endif