2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/lpc/send.c
5 * PURPOSE: Local Procedure Call: Sending (Requests)
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
15 /* PUBLIC FUNCTIONS **********************************************************/
22 LpcRequestPort(IN PVOID PortObject
,
23 IN PPORT_MESSAGE LpcMessage
)
25 PLPCP_PORT_OBJECT Port
= PortObject
, QueuePort
, ConnectionPort
= NULL
;
27 PLPCP_MESSAGE Message
;
28 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
30 LPCTRACE(LPC_SEND_DEBUG
, "Port: %p. Message: %p\n", Port
, LpcMessage
);
32 /* Check if this is a non-datagram message */
33 if (LpcMessage
->u2
.s2
.Type
)
35 /* Get the message type */
36 MessageType
= LpcpGetMessageType(LpcMessage
);
39 if ((MessageType
< LPC_DATAGRAM
) || (MessageType
> LPC_CLIENT_DIED
))
42 return STATUS_INVALID_PARAMETER
;
45 /* Mark this as a kernel-mode message only if we really came from it */
46 if ((PreviousMode
== KernelMode
) &&
47 (LpcMessage
->u2
.s2
.Type
& LPC_KERNELMODE_MESSAGE
))
49 /* We did, this is a kernel mode message */
50 MessageType
|= LPC_KERNELMODE_MESSAGE
;
55 /* This is a datagram */
56 MessageType
= LPC_DATAGRAM
;
59 /* Can't have data information on this type of call */
60 if (LpcMessage
->u2
.s2
.DataInfoOffset
) return STATUS_INVALID_PARAMETER
;
62 /* Validate message sizes */
63 if (((ULONG
)LpcMessage
->u1
.s1
.TotalLength
> Port
->MaxMessageLength
) ||
64 ((ULONG
)LpcMessage
->u1
.s1
.TotalLength
<= (ULONG
)LpcMessage
->u1
.s1
.DataLength
))
67 return STATUS_PORT_MESSAGE_TOO_LONG
;
70 /* Allocate a new message */
71 Message
= LpcpAllocateFromPortZone();
72 if (!Message
) return STATUS_NO_MEMORY
;
74 /* Clear the context */
75 Message
->RepliedToThread
= NULL
;
76 Message
->PortContext
= NULL
;
78 /* Copy the message */
79 LpcpMoveMessage(&Message
->Request
,
83 &PsGetCurrentThread()->Cid
);
85 /* Acquire the LPC lock */
86 KeAcquireGuardedMutex(&LpcpLock
);
88 /* Check if this is anything but a connection port */
89 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) != LPCP_CONNECTION_PORT
)
91 /* The queue port is the connected port */
92 QueuePort
= Port
->ConnectedPort
;
95 /* Check if this is a client port */
96 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_CLIENT_PORT
)
98 /* Then copy the context */
99 Message
->PortContext
= QueuePort
->PortContext
;
100 ConnectionPort
= QueuePort
= Port
->ConnectionPort
;
104 LpcpFreeToPortZone(Message
, 3);
105 return STATUS_PORT_DISCONNECTED
;
108 else if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) != LPCP_COMMUNICATION_PORT
)
110 /* Any other kind of port, use the connection port */
111 ConnectionPort
= QueuePort
= Port
->ConnectionPort
;
115 LpcpFreeToPortZone(Message
, 3);
116 return STATUS_PORT_DISCONNECTED
;
120 /* If we have a connection port, reference it */
121 if (ConnectionPort
) ObReferenceObject(ConnectionPort
);
126 /* For connection ports, use the port itself */
127 QueuePort
= PortObject
;
130 /* Make sure we have a port */
133 /* Generate the Message ID and set it */
134 Message
->Request
.MessageId
= LpcpNextMessageId
++;
135 if (!LpcpNextMessageId
) LpcpNextMessageId
= 1;
136 Message
->Request
.CallbackId
= 0;
138 /* No Message ID for the thread */
139 PsGetCurrentThread()->LpcReplyMessageId
= 0;
141 /* Insert the message in our chain */
142 InsertTailList(&QueuePort
->MsgQueue
.ReceiveHead
, &Message
->Entry
);
144 /* Release the lock and release the semaphore */
145 KeEnterCriticalRegion();
146 KeReleaseGuardedMutex(&LpcpLock
);
147 LpcpCompleteWait(QueuePort
->MsgQueue
.Semaphore
);
149 /* If this is a waitable port, wake it up */
150 if (QueuePort
->Flags
& LPCP_WAITABLE_PORT
)
153 KeSetEvent(&QueuePort
->WaitEvent
, IO_NO_INCREMENT
, FALSE
);
157 KeLeaveCriticalRegion();
158 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
159 LPCTRACE(LPC_SEND_DEBUG
, "Port: %p. Message: %p\n", QueuePort
, Message
);
160 return STATUS_SUCCESS
;
163 /* If we got here, then free the message and fail */
164 LpcpFreeToPortZone(Message
, 3);
165 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
166 return STATUS_PORT_DISCONNECTED
;
174 LpcRequestWaitReplyPort(IN PVOID PortObject
,
175 IN PPORT_MESSAGE LpcRequest
,
176 OUT PPORT_MESSAGE LpcReply
)
178 PLPCP_PORT_OBJECT Port
, QueuePort
, ReplyPort
, ConnectionPort
= NULL
;
179 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
180 NTSTATUS Status
= STATUS_SUCCESS
;
181 PLPCP_MESSAGE Message
;
182 PETHREAD Thread
= PsGetCurrentThread();
183 BOOLEAN Callback
= FALSE
;
184 PKSEMAPHORE Semaphore
;
188 Port
= (PLPCP_PORT_OBJECT
)PortObject
;
190 LPCTRACE(LPC_SEND_DEBUG
,
191 "Port: %p. Messages: %p/%p. Type: %lx\n",
195 LpcpGetMessageType(LpcRequest
));
197 /* Check if the thread is dying */
198 if (Thread
->LpcExitThreadCalled
) return STATUS_THREAD_IS_TERMINATING
;
200 /* Check if this is an LPC Request */
201 MessageType
= LpcpGetMessageType(LpcRequest
);
207 /* Assume LPC request */
208 MessageType
= LPC_REQUEST
;
211 /* LPC request callback */
214 /* This is a callback */
219 case LPC_CLIENT_DIED
:
220 case LPC_PORT_CLOSED
:
222 case LPC_DEBUG_EVENT
:
223 case LPC_ERROR_EVENT
:
230 /* Invalid message type */
231 return STATUS_INVALID_PARAMETER
;
234 /* Set the request type */
235 LpcRequest
->u2
.s2
.Type
= MessageType
;
237 /* Validate the message length */
238 if (((ULONG
)LpcRequest
->u1
.s1
.TotalLength
> Port
->MaxMessageLength
) ||
239 ((ULONG
)LpcRequest
->u1
.s1
.TotalLength
<= (ULONG
)LpcRequest
->u1
.s1
.DataLength
))
242 return STATUS_PORT_MESSAGE_TOO_LONG
;
245 /* Allocate a message from the port zone */
246 Message
= LpcpAllocateFromPortZone();
249 /* Fail if we couldn't allocate a message */
250 return STATUS_NO_MEMORY
;
253 /* Check if this is a callback */
257 Semaphore
= NULL
; // we'd use the Thread Semaphore here
259 return STATUS_NOT_IMPLEMENTED
;
263 /* No callback, just copy the message */
264 LpcpMoveMessage(&Message
->Request
,
270 /* Acquire the LPC lock */
271 KeAcquireGuardedMutex(&LpcpLock
);
273 /* Right now clear the port context */
274 Message
->PortContext
= NULL
;
276 /* Check if this is a not connection port */
277 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) != LPCP_CONNECTION_PORT
)
279 /* We want the connected port */
280 QueuePort
= Port
->ConnectedPort
;
283 /* We have no connected port, fail */
284 LpcpFreeToPortZone(Message
, 3);
285 return STATUS_PORT_DISCONNECTED
;
288 /* This will be the rundown port */
289 ReplyPort
= QueuePort
;
291 /* Check if this is a communication port */
292 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_CLIENT_PORT
)
294 /* Copy the port context and use the connection port */
295 Message
->PortContext
= QueuePort
->PortContext
;
296 ConnectionPort
= QueuePort
= Port
->ConnectionPort
;
300 LpcpFreeToPortZone(Message
, 3);
301 return STATUS_PORT_DISCONNECTED
;
304 else if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) !=
305 LPCP_COMMUNICATION_PORT
)
307 /* Use the connection port for anything but communication ports */
308 ConnectionPort
= QueuePort
= Port
->ConnectionPort
;
312 LpcpFreeToPortZone(Message
, 3);
313 return STATUS_PORT_DISCONNECTED
;
317 /* Reference the connection port if it exists */
318 if (ConnectionPort
) ObReferenceObject(ConnectionPort
);
322 /* Otherwise, for a connection port, use the same port object */
323 QueuePort
= ReplyPort
= Port
;
326 /* No reply thread */
327 Message
->RepliedToThread
= NULL
;
328 Message
->SenderPort
= Port
;
330 /* Generate the Message ID and set it */
331 Message
->Request
.MessageId
= LpcpNextMessageId
++;
332 if (!LpcpNextMessageId
) LpcpNextMessageId
= 1;
333 Message
->Request
.CallbackId
= 0;
335 /* Set the message ID for our thread now */
336 Thread
->LpcReplyMessageId
= Message
->Request
.MessageId
;
337 Thread
->LpcReplyMessage
= NULL
;
339 /* Insert the message in our chain */
340 InsertTailList(&QueuePort
->MsgQueue
.ReceiveHead
, &Message
->Entry
);
341 InsertTailList(&ReplyPort
->LpcReplyChainHead
, &Thread
->LpcReplyChain
);
342 LpcpSetPortToThread(Thread
, Port
);
344 /* Release the lock and get the semaphore we'll use later */
345 KeEnterCriticalRegion();
346 KeReleaseGuardedMutex(&LpcpLock
);
347 Semaphore
= QueuePort
->MsgQueue
.Semaphore
;
349 /* If this is a waitable port, wake it up */
350 if (QueuePort
->Flags
& LPCP_WAITABLE_PORT
)
353 KeSetEvent(&QueuePort
->WaitEvent
, IO_NO_INCREMENT
, FALSE
);
357 /* Now release the semaphore */
358 LpcpCompleteWait(Semaphore
);
359 KeLeaveCriticalRegion();
361 /* And let's wait for the reply */
362 LpcpReplyWait(&Thread
->LpcReplySemaphore
, PreviousMode
);
364 /* Acquire the LPC lock */
365 KeAcquireGuardedMutex(&LpcpLock
);
367 /* Get the LPC Message and clear our thread's reply data */
368 Message
= LpcpGetMessageFromThread(Thread
);
369 Thread
->LpcReplyMessage
= NULL
;
370 Thread
->LpcReplyMessageId
= 0;
372 /* Check if we have anything on the reply chain*/
373 if (!IsListEmpty(&Thread
->LpcReplyChain
))
375 /* Remove this thread and reinitialize the list */
376 RemoveEntryList(&Thread
->LpcReplyChain
);
377 InitializeListHead(&Thread
->LpcReplyChain
);
380 /* Release the lock */
381 KeReleaseGuardedMutex(&LpcpLock
);
383 /* Check if we got a reply */
384 if (Status
== STATUS_SUCCESS
)
386 /* Check if we have a valid message */
389 LPCTRACE(LPC_SEND_DEBUG
,
390 "Reply Messages: %p/%p\n",
392 (&Message
->Request
) + 1);
394 /* Move the message */
395 LpcpMoveMessage(LpcReply
,
397 (&Message
->Request
) + 1,
401 /* Acquire the lock */
402 KeAcquireGuardedMutex(&LpcpLock
);
404 /* Check if we replied to a thread */
405 if (Message
->RepliedToThread
)
408 ObDereferenceObject(Message
->RepliedToThread
);
409 Message
->RepliedToThread
= NULL
;
413 /* Free the message */
414 LpcpFreeToPortZone(Message
, 3);
418 /* We don't have a reply */
419 Status
= STATUS_LPC_REPLY_LOST
;
424 /* The wait failed, free the message */
425 if (Message
) LpcpFreeToPortZone(Message
, 0);
429 LPCTRACE(LPC_SEND_DEBUG
,
430 "Port: %p. Status: %p\n",
434 /* Dereference the connection port */
435 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
444 NtRequestPort(IN HANDLE PortHandle
,
445 IN PPORT_MESSAGE LpcRequest
)
447 PLPCP_PORT_OBJECT Port
, QueuePort
, ConnectionPort
= NULL
;
448 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
450 PLPCP_MESSAGE Message
;
451 PETHREAD Thread
= PsGetCurrentThread();
453 PKSEMAPHORE Semaphore
;
456 LPCTRACE(LPC_SEND_DEBUG
,
457 "Handle: %lx. Message: %p. Type: %lx\n",
460 LpcpGetMessageType(LpcRequest
));
462 /* Get the message type */
463 MessageType
= LpcRequest
->u2
.s2
.Type
| LPC_DATAGRAM
;
465 /* Can't have data information on this type of call */
466 if (LpcRequest
->u2
.s2
.DataInfoOffset
) return STATUS_INVALID_PARAMETER
;
468 /* Validate the length */
469 if (((ULONG
)LpcRequest
->u1
.s1
.DataLength
+ sizeof(PORT_MESSAGE
)) >
470 (ULONG
)LpcRequest
->u1
.s1
.TotalLength
)
473 return STATUS_INVALID_PARAMETER
;
476 /* Reference the object */
477 Status
= ObReferenceObjectByHandle(PortHandle
,
483 if (!NT_SUCCESS(Status
)) return Status
;
485 /* Validate the message length */
486 if (((ULONG
)LpcRequest
->u1
.s1
.TotalLength
> Port
->MaxMessageLength
) ||
487 ((ULONG
)LpcRequest
->u1
.s1
.TotalLength
<= (ULONG
)LpcRequest
->u1
.s1
.DataLength
))
490 ObDereferenceObject(Port
);
491 return STATUS_PORT_MESSAGE_TOO_LONG
;
494 /* Allocate a message from the port zone */
495 Message
= LpcpAllocateFromPortZone();
498 /* Fail if we couldn't allocate a message */
499 ObDereferenceObject(Port
);
500 return STATUS_NO_MEMORY
;
503 /* No callback, just copy the message */
507 LpcpMoveMessage(&Message
->Request
,
513 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
516 LpcpFreeToPortZone(Message
, 0);
517 ObDereferenceObject(Port
);
518 _SEH2_YIELD(return _SEH2_GetExceptionCode());
522 /* Acquire the LPC lock */
523 KeAcquireGuardedMutex(&LpcpLock
);
525 /* Right now clear the port context */
526 Message
->PortContext
= NULL
;
528 /* Check if this is a not connection port */
529 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) != LPCP_CONNECTION_PORT
)
531 /* We want the connected port */
532 QueuePort
= Port
->ConnectedPort
;
535 /* We have no connected port, fail */
536 LpcpFreeToPortZone(Message
, 3);
537 ObDereferenceObject(Port
);
538 return STATUS_PORT_DISCONNECTED
;
541 /* Check if this is a communication port */
542 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_CLIENT_PORT
)
544 /* Copy the port context and use the connection port */
545 Message
->PortContext
= QueuePort
->PortContext
;
546 ConnectionPort
= QueuePort
= Port
->ConnectionPort
;
550 LpcpFreeToPortZone(Message
, 3);
551 ObDereferenceObject(Port
);
552 return STATUS_PORT_DISCONNECTED
;
555 else if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) !=
556 LPCP_COMMUNICATION_PORT
)
558 /* Use the connection port for anything but communication ports */
559 ConnectionPort
= QueuePort
= Port
->ConnectionPort
;
563 LpcpFreeToPortZone(Message
, 3);
564 ObDereferenceObject(Port
);
565 return STATUS_PORT_DISCONNECTED
;
569 /* Reference the connection port if it exists */
570 if (ConnectionPort
) ObReferenceObject(ConnectionPort
);
574 /* Otherwise, for a connection port, use the same port object */
578 /* Reference QueuePort if we have it */
579 if (QueuePort
&& ObReferenceObjectSafe(QueuePort
))
581 /* Set sender's port */
582 Message
->SenderPort
= Port
;
584 /* Generate the Message ID and set it */
585 Message
->Request
.MessageId
= LpcpNextMessageId
++;
586 if (!LpcpNextMessageId
) LpcpNextMessageId
= 1;
587 Message
->Request
.CallbackId
= 0;
589 /* No Message ID for the thread */
590 PsGetCurrentThread()->LpcReplyMessageId
= 0;
592 /* Insert the message in our chain */
593 InsertTailList(&QueuePort
->MsgQueue
.ReceiveHead
, &Message
->Entry
);
595 /* Release the lock and get the semaphore we'll use later */
596 KeEnterCriticalRegion();
597 KeReleaseGuardedMutex(&LpcpLock
);
599 /* Now release the semaphore */
600 Semaphore
= QueuePort
->MsgQueue
.Semaphore
;
601 LpcpCompleteWait(Semaphore
);
603 /* If this is a waitable port, wake it up */
604 if (QueuePort
->Flags
& LPCP_WAITABLE_PORT
)
607 KeSetEvent(&QueuePort
->WaitEvent
, IO_NO_INCREMENT
, FALSE
);
610 KeLeaveCriticalRegion();
612 /* Dereference objects */
613 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
614 ObDereferenceObject(QueuePort
);
615 ObDereferenceObject(Port
);
616 LPCTRACE(LPC_SEND_DEBUG
, "Port: %p. Message: %p\n", QueuePort
, Message
);
617 return STATUS_SUCCESS
;
620 Status
= STATUS_PORT_DISCONNECTED
;
622 /* All done with a failure*/
623 LPCTRACE(LPC_SEND_DEBUG
,
624 "Port: %p. Status: %p\n",
628 /* The wait failed, free the message */
629 if (Message
) LpcpFreeToPortZone(Message
, 3);
631 ObDereferenceObject(Port
);
632 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
641 NtRequestWaitReplyPort(IN HANDLE PortHandle
,
642 IN PPORT_MESSAGE LpcRequest
,
643 IN OUT PPORT_MESSAGE LpcReply
)
645 PLPCP_PORT_OBJECT Port
, QueuePort
, ReplyPort
, ConnectionPort
= NULL
;
646 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
648 PLPCP_MESSAGE Message
;
649 PETHREAD Thread
= PsGetCurrentThread();
651 PKSEMAPHORE Semaphore
;
654 LPCTRACE(LPC_SEND_DEBUG
,
655 "Handle: %lx. Messages: %p/%p. Type: %lx\n",
659 LpcpGetMessageType(LpcRequest
));
661 /* Check if the thread is dying */
662 if (Thread
->LpcExitThreadCalled
) return STATUS_THREAD_IS_TERMINATING
;
664 /* Check if this is an LPC Request */
665 if (LpcpGetMessageType(LpcRequest
) == LPC_REQUEST
)
667 /* Then it's a callback */
670 else if (LpcpGetMessageType(LpcRequest
))
672 /* This is a not kernel-mode message */
673 return STATUS_INVALID_PARAMETER
;
677 /* This is a kernel-mode message without a callback */
678 LpcRequest
->u2
.s2
.Type
|= LPC_REQUEST
;
682 /* Get the message type */
683 MessageType
= LpcRequest
->u2
.s2
.Type
;
685 /* Validate the length */
686 if (((ULONG
)LpcRequest
->u1
.s1
.DataLength
+ sizeof(PORT_MESSAGE
)) >
687 (ULONG
)LpcRequest
->u1
.s1
.TotalLength
)
690 return STATUS_INVALID_PARAMETER
;
693 /* Reference the object */
694 Status
= ObReferenceObjectByHandle(PortHandle
,
700 if (!NT_SUCCESS(Status
)) return Status
;
702 /* Validate the message length */
703 if (((ULONG
)LpcRequest
->u1
.s1
.TotalLength
> Port
->MaxMessageLength
) ||
704 ((ULONG
)LpcRequest
->u1
.s1
.TotalLength
<= (ULONG
)LpcRequest
->u1
.s1
.DataLength
))
707 ObDereferenceObject(Port
);
708 return STATUS_PORT_MESSAGE_TOO_LONG
;
711 /* Allocate a message from the port zone */
712 Message
= LpcpAllocateFromPortZone();
715 /* Fail if we couldn't allocate a message */
716 ObDereferenceObject(Port
);
717 return STATUS_NO_MEMORY
;
720 /* Check if this is a callback */
724 Semaphore
= NULL
; // we'd use the Thread Semaphore here
729 /* No callback, just copy the message */
733 LpcpMoveMessage(&Message
->Request
,
739 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
742 LpcpFreeToPortZone(Message
, 0);
743 ObDereferenceObject(Port
);
744 _SEH2_YIELD(return _SEH2_GetExceptionCode());
748 /* Acquire the LPC lock */
749 KeAcquireGuardedMutex(&LpcpLock
);
751 /* Right now clear the port context */
752 Message
->PortContext
= NULL
;
754 /* Check if this is a not connection port */
755 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) != LPCP_CONNECTION_PORT
)
757 /* We want the connected port */
758 QueuePort
= Port
->ConnectedPort
;
761 /* We have no connected port, fail */
762 LpcpFreeToPortZone(Message
, 3);
763 ObDereferenceObject(Port
);
764 return STATUS_PORT_DISCONNECTED
;
767 /* This will be the rundown port */
768 ReplyPort
= QueuePort
;
770 /* Check if this is a communication port */
771 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_CLIENT_PORT
)
773 /* Copy the port context and use the connection port */
774 Message
->PortContext
= QueuePort
->PortContext
;
775 ConnectionPort
= QueuePort
= Port
->ConnectionPort
;
779 LpcpFreeToPortZone(Message
, 3);
780 ObDereferenceObject(Port
);
781 return STATUS_PORT_DISCONNECTED
;
784 else if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) !=
785 LPCP_COMMUNICATION_PORT
)
787 /* Use the connection port for anything but communication ports */
788 ConnectionPort
= QueuePort
= Port
->ConnectionPort
;
792 LpcpFreeToPortZone(Message
, 3);
793 ObDereferenceObject(Port
);
794 return STATUS_PORT_DISCONNECTED
;
798 /* Reference the connection port if it exists */
799 if (ConnectionPort
) ObReferenceObject(ConnectionPort
);
803 /* Otherwise, for a connection port, use the same port object */
804 QueuePort
= ReplyPort
= Port
;
807 /* No reply thread */
808 Message
->RepliedToThread
= NULL
;
809 Message
->SenderPort
= Port
;
811 /* Generate the Message ID and set it */
812 Message
->Request
.MessageId
= LpcpNextMessageId
++;
813 if (!LpcpNextMessageId
) LpcpNextMessageId
= 1;
814 Message
->Request
.CallbackId
= 0;
816 /* Set the message ID for our thread now */
817 Thread
->LpcReplyMessageId
= Message
->Request
.MessageId
;
818 Thread
->LpcReplyMessage
= NULL
;
820 /* Insert the message in our chain */
821 InsertTailList(&QueuePort
->MsgQueue
.ReceiveHead
, &Message
->Entry
);
822 InsertTailList(&ReplyPort
->LpcReplyChainHead
, &Thread
->LpcReplyChain
);
823 LpcpSetPortToThread(Thread
, Port
);
825 /* Release the lock and get the semaphore we'll use later */
826 KeEnterCriticalRegion();
827 KeReleaseGuardedMutex(&LpcpLock
);
828 Semaphore
= QueuePort
->MsgQueue
.Semaphore
;
830 /* If this is a waitable port, wake it up */
831 if (QueuePort
->Flags
& LPCP_WAITABLE_PORT
)
834 KeSetEvent(&QueuePort
->WaitEvent
, IO_NO_INCREMENT
, FALSE
);
838 /* Now release the semaphore */
839 LpcpCompleteWait(Semaphore
);
840 KeLeaveCriticalRegion();
842 /* And let's wait for the reply */
843 LpcpReplyWait(&Thread
->LpcReplySemaphore
, PreviousMode
);
845 /* Acquire the LPC lock */
846 KeAcquireGuardedMutex(&LpcpLock
);
848 /* Get the LPC Message and clear our thread's reply data */
849 Message
= LpcpGetMessageFromThread(Thread
);
850 Thread
->LpcReplyMessage
= NULL
;
851 Thread
->LpcReplyMessageId
= 0;
853 /* Check if we have anything on the reply chain*/
854 if (!IsListEmpty(&Thread
->LpcReplyChain
))
856 /* Remove this thread and reinitialize the list */
857 RemoveEntryList(&Thread
->LpcReplyChain
);
858 InitializeListHead(&Thread
->LpcReplyChain
);
861 /* Release the lock */
862 KeReleaseGuardedMutex(&LpcpLock
);
864 /* Check if we got a reply */
865 if (Status
== STATUS_SUCCESS
)
867 /* Check if we have a valid message */
870 LPCTRACE(LPC_SEND_DEBUG
,
871 "Reply Messages: %p/%p\n",
873 (&Message
->Request
) + 1);
875 /* Move the message */
878 LpcpMoveMessage(LpcReply
,
880 (&Message
->Request
) + 1,
884 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
886 Status
= _SEH2_GetExceptionCode();
890 /* Check if this is an LPC request with data information */
891 if ((LpcpGetMessageType(&Message
->Request
) == LPC_REQUEST
) &&
892 (Message
->Request
.u2
.s2
.DataInfoOffset
))
894 /* Save the data information */
895 LpcpSaveDataInfoMessage(Port
, Message
, 0);
899 /* Otherwise, just free it */
900 LpcpFreeToPortZone(Message
, 0);
905 /* We don't have a reply */
906 Status
= STATUS_LPC_REPLY_LOST
;
911 /* The wait failed, free the message */
912 if (Message
) LpcpFreeToPortZone(Message
, 0);
916 LPCTRACE(LPC_SEND_DEBUG
,
917 "Port: %p. Status: %p\n",
920 ObDereferenceObject(Port
);
921 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);