Author: ion Date: Mon Oct 30 17:50:31 2006 New Revision: 24673
URL: http://svn.reactos.org/svn/reactos?rev=24673&view=rev Log: - Implement NtRequestWaitReplyPort. This is a simple implementation that doesn't support Callback LPC Messages yet (Since we don't make use of them). SMSS can now send API messages on the Sb Port. - With these APIs we now have a skeleton NTLPC that is fully NT-compatible. Thanks to ea's (Emanuele)'s smss work which he strived to make portable, building with NTLPC = 1 will also build a compatible smss that now works. - CSRSS requires some changes since it was not written to be NTLPC portable.
Modified: trunk/reactos/ntoskrnl/lpc/ntlpc/send.c
Modified: trunk/reactos/ntoskrnl/lpc/ntlpc/send.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/lpc/ntlpc/send.c?r... ============================================================================== --- trunk/reactos/ntoskrnl/lpc/ntlpc/send.c (original) +++ trunk/reactos/ntoskrnl/lpc/ntlpc/send.c Mon Oct 30 17:50:31 2006 @@ -61,8 +61,251 @@ IN PPORT_MESSAGE LpcRequest, IN OUT PPORT_MESSAGE LpcReply) { - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + PLPCP_PORT_OBJECT Port, QueuePort, ReplyPort; + KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); + NTSTATUS Status; + PLPCP_MESSAGE Message; + PETHREAD Thread = PsGetCurrentThread(); + BOOLEAN Callback; + PKSEMAPHORE Semaphore; + ULONG MessageType; + PAGED_CODE(); + LPCTRACE(LPC_SEND_DEBUG, + "Handle: %lx. Messages: %p/%p. Type: %lx\n", + PortHandle, + LpcRequest, + LpcReply, + LpcpGetMessageType(LpcRequest)); + + /* Check if the thread is dying */ + if (Thread->LpcExitThreadCalled) return STATUS_THREAD_IS_TERMINATING; + + /* Check if this is an LPC Request */ + if (LpcpGetMessageType(LpcRequest) == LPC_REQUEST) + { + /* Then it's a callback */ + Callback = TRUE; + } + else if (LpcpGetMessageType(LpcRequest)) + { + /* This is a not kernel-mode message */ + return STATUS_INVALID_PARAMETER; + } + else + { + /* This is a kernel-mode message without a callback */ + LpcRequest->u2.s2.Type |= LPC_REQUEST; + Callback = FALSE; + } + + /* Get the message type */ + MessageType = LpcRequest->u2.s2.Type; + + /* Validate the length */ + if ((LpcRequest->u1.s1.DataLength + sizeof(PORT_MESSAGE)) > + LpcRequest->u1.s1.TotalLength) + { + /* Fail */ + return STATUS_INVALID_PARAMETER; + } + + /* Reference the object */ + Status = ObReferenceObjectByHandle(PortHandle, + 0, + LpcPortObjectType, + PreviousMode, + (PVOID*)&Port, + NULL); + if (!NT_SUCCESS(Status)) return Status; + + /* Validate the message length */ + if ((LpcRequest->u1.s1.TotalLength > Port->MaxMessageLength) || + (LpcRequest->u1.s1.TotalLength <= LpcRequest->u1.s1.DataLength)) + { + /* Fail */ + ObDereferenceObject(Port); + return STATUS_PORT_MESSAGE_TOO_LONG; + } + + /* Acquire the lock */ + KeAcquireGuardedMutex(&LpcpLock); + + /* Allocate a message */ + Message = ExAllocateFromPagedLookasideList(&LpcpMessagesLookaside); + KeReleaseGuardedMutex(&LpcpLock); + + /* Check if allocation worked */ + if (!Message) + { + /* Fail */ + ObDereferenceObject(Port); + return STATUS_NO_MEMORY; + } + + /* Check if this is a callback */ + if (Callback) + { + /* FIXME: TODO */ + Semaphore = NULL; // we'd use the Thread Semaphore here + ASSERT(FALSE); + } + else + { + /* No callback, just copy the message */ + LpcpMoveMessage(&Message->Request, + LpcRequest, + LpcRequest + 1, + MessageType, + &Thread->Cid); + + /* Acquire the LPC lock */ + KeAcquireGuardedMutex(&LpcpLock); + + /* Right now clear the port context */ + Message->PortContext = NULL; + + /* Check if this is a not connection port */ + if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CONNECTION_PORT) + { + /* We want the connected port */ + QueuePort = Port->ConnectedPort; + if (!QueuePort) + { + /* We have no connected port, fail */ + LpcpFreeToPortZone(Message, TRUE); + KeReleaseGuardedMutex(&LpcpLock); + ObDereferenceObject(Port); + return STATUS_PORT_DISCONNECTED; + } + + /* This will be the rundown port */ + ReplyPort = QueuePort; + + /* Check if this is a communication port */ + if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT) + { + /* Copy the port context and use the connection port */ + Message->PortContext = ReplyPort->PortContext; + QueuePort = Port->ConnectionPort; + } + else if ((Port->Flags & LPCP_PORT_TYPE_MASK) != + LPCP_COMMUNICATION_PORT) + { + /* Use the connection port for anything but communication ports */ + QueuePort = Port->ConnectionPort; + } + } + else + { + /* Otherwise, for a connection port, use the same port object */ + QueuePort = ReplyPort = Port; + } + + /* No reply thread */ + Message->RepliedToThread = NULL; + + /* Generate the Message ID and set it */ + Message->Request.MessageId = LpcpNextMessageId++; + if (!LpcpNextMessageId) LpcpNextMessageId = 1; + Message->Request.CallbackId = 0; + + /* Set the message ID for our thread now */ + Thread->LpcReplyMessageId = Message->Request.MessageId; + Thread->LpcReplyMessage = NULL; + + /* Insert the message in our chain */ + InsertTailList(&QueuePort->MsgQueue.ReceiveHead, &Message->Entry); + InsertTailList(&ReplyPort->LpcReplyChainHead, &Thread->LpcReplyChain); + + /* Release the lock and get the semaphore we'll use later */ + KeReleaseGuardedMutex(&LpcpLock); + Semaphore = QueuePort->MsgQueue.Semaphore; + + /* If this is a waitable port, wake it up */ + if (QueuePort->Flags & LPCP_WAITABLE_PORT) + { + /* Wake it */ + KeSetEvent(&QueuePort->WaitEvent, IO_NO_INCREMENT, FALSE); + } + } + + /* Now release the semaphore */ + LpcpCompleteWait(Semaphore); + + /* And let's wait for the reply */ + LpcpReplyWait(&Thread->LpcReplySemaphore, PreviousMode); + + /* Acquire the LPC lock */ + KeAcquireGuardedMutex(&LpcpLock); + + /* Get the LPC Message and clear our thread's reply data */ + Message = Thread->LpcReplyMessage; + Thread->LpcReplyMessage = NULL; + Thread->LpcReplyMessageId = 0; + + /* Check if we have anything on the reply chain*/ + if (!IsListEmpty(&Thread->LpcReplyChain)) + { + /* Remove this thread and reinitialize the list */ + RemoveEntryList(&Thread->LpcReplyChain); + InitializeListHead(&Thread->LpcReplyChain); + } + + /* Release the lock */ + KeReleaseGuardedMutex(&LpcpLock); + + /* Check if we got a reply */ + if (Status == STATUS_SUCCESS) + { + /* Check if we have a valid message */ + if (Message) + { + LPCTRACE(LPC_SEND_DEBUG, + "Reply Messages: %p/%p\n", + &Message->Request, + (&Message->Request) + 1); + + /* Move the message */ + LpcpMoveMessage(LpcReply, + &Message->Request, + (&Message->Request) + 1, + 0, + NULL); + + /* Check if this is an LPC request with data information */ + if ((LpcpGetMessageType(&Message->Request) == LPC_REQUEST) && + (Message->Request.u2.s2.DataInfoOffset)) + { + /* Save the data information */ + LpcpSaveDataInfoMessage(Port, Message); + } + else + { + /* Otherwise, just free it */ + LpcpFreeToPortZone(Message, FALSE); + } + } + else + { + /* We don't have a reply */ + Status = STATUS_LPC_REPLY_LOST; + } + } + else + { + /* The wait failed, free the message while holding the lock */ + KeAcquireGuardedMutex(&LpcpLock); + LpcpFreeToPortZone(Message, TRUE); + KeReleaseGuardedMutex(&LpcpLock); + } + + /* All done */ + LPCTRACE(LPC_SEND_DEBUG, + "Port: %p. Status: %p\n", + Port, + Status); + ObDereferenceObject(Port); + return Status; }
/* EOF */