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

Generated on Sat May 15 19:39:23 2004 for test by doxygen 1.3.7