Author: ion Date: Sun Nov 5 23:31:35 2006 New Revision: 24685
URL: http://svn.reactos.org/svn/reactos?rev=24685&view=rev Log: - Simplify LPC Message allocation with an LpcpAllocateFromPortZone macro. - Move LPC Macros/inlines to lpc_x.h - Implement LpcRequestPort. - Fix a bug in CsrTerminateProcess which was setting up incorrect sizes for the LPC message. - Add some debug output to csrss. - NTLPC works perfectly now, except for a bug on shutdown which doesn't properly close LPC processes.
Added: trunk/reactos/ntoskrnl/lpc/ntlpc/lpc_x.h Modified: trunk/reactos/ntoskrnl/lpc/ntlpc/close.c trunk/reactos/ntoskrnl/lpc/ntlpc/connect.c trunk/reactos/ntoskrnl/lpc/ntlpc/lpc.h trunk/reactos/ntoskrnl/lpc/ntlpc/port.c trunk/reactos/ntoskrnl/lpc/ntlpc/reply.c trunk/reactos/ntoskrnl/lpc/ntlpc/send.c trunk/reactos/subsystems/win32/csrss/api/process.c trunk/reactos/subsystems/win32/csrss/api/wapi.c
Modified: trunk/reactos/ntoskrnl/lpc/ntlpc/close.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/lpc/ntlpc/close.c?... ============================================================================== --- trunk/reactos/ntoskrnl/lpc/ntlpc/close.c (original) +++ trunk/reactos/ntoskrnl/lpc/ntlpc/close.c Sun Nov 5 23:31:35 2006 @@ -40,7 +40,7 @@ if (Message) { /* FIXME: TODO */ - ASSERT(FALSE); + KEBUGCHECK(0); }
/* Release the lock */
Modified: trunk/reactos/ntoskrnl/lpc/ntlpc/connect.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/lpc/ntlpc/connect.... ============================================================================== --- trunk/reactos/ntoskrnl/lpc/ntlpc/connect.c (original) +++ trunk/reactos/ntoskrnl/lpc/ntlpc/connect.c Sun Nov 5 23:31:35 2006 @@ -301,25 +301,15 @@ ConnectionInfoLength = Port->MaxConnectionInfoLength; }
- /* Allocate a message from the port zone while holding the lock */ - KeAcquireGuardedMutex(&LpcpLock); - Message = ExAllocateFromPagedLookasideList(&LpcpMessagesLookaside); + /* Allocate a message from the port zone */ + Message = LpcpAllocateFromPortZone(); if (!Message) { /* Fail if we couldn't allocate a message */ - KeReleaseGuardedMutex(&LpcpLock); if (SectionToMap) ObDereferenceObject(SectionToMap); ObDereferenceObject(ClientPort); return STATUS_NO_MEMORY; } - - /* Initialize it */ - InitializeListHead(&Message->Entry); - Message->RepliedToThread = NULL; - Message->Request.u2.ZeroInit = 0; - - /* Release the lock */ - KeReleaseGuardedMutex(&LpcpLock);
/* Set pointer to the connection message and fill in the CID */ ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
Modified: trunk/reactos/ntoskrnl/lpc/ntlpc/lpc.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/lpc/ntlpc/lpc.h?re... ============================================================================== --- trunk/reactos/ntoskrnl/lpc/ntlpc/lpc.h (original) +++ trunk/reactos/ntoskrnl/lpc/ntlpc/lpc.h Sun Nov 5 23:31:35 2006 @@ -46,97 +46,6 @@ } #endif #endif - -// -// Gets the message type, removing the kernel-mode flag -// -#define LpcpGetMessageType(x) \ - ((x)->u2.s2.Type &~ LPCP_KERNEL_MESSAGE) - -// -// Waits on an LPC semaphore for a receive operation -// -#define LpcpReceiveWait(s, w) \ -{ \ - LPCTRACE(LPC_REPLY_DEBUG, "Wait: %p\n", s); \ - Status = KeWaitForSingleObject(s, \ - WrLpcReceive, \ - w, \ - FALSE, \ - NULL); \ - LPCTRACE(LPC_REPLY_DEBUG, "Wait done: %lx\n", Status); \ -} - -// -// Waits on an LPC semaphore for a reply operation -// -#define LpcpReplyWait(s, w) \ -{ \ - LPCTRACE(LPC_SEND_DEBUG, "Wait: %p\n", s); \ - Status = KeWaitForSingleObject(s, \ - WrLpcReply, \ - w, \ - FALSE, \ - NULL); \ - LPCTRACE(LPC_SEND_DEBUG, "Wait done: %lx\n", Status); \ - if (Status == STATUS_USER_APC) \ - { \ - /* We were preempted by an APC */ \ - if (KeReadStateSemaphore(s)) \ - { \ - /* It's still signaled, so wait on it */ \ - KeWaitForSingleObject(s, \ - Executive, \ - KernelMode, \ - FALSE, \ - NULL); \ - Status = STATUS_SUCCESS; \ - } \ - } \ -} - -// -// Waits on an LPC semaphore for a connect operation -// -#define LpcpConnectWait(s, w) \ -{ \ - LPCTRACE(LPC_CONNECT_DEBUG, "Wait: %p\n", s); \ - Status = KeWaitForSingleObject(s, \ - Executive, \ - w, \ - FALSE, \ - NULL); \ - LPCTRACE(LPC_CONNECT_DEBUG, "Wait done: %lx\n", Status);\ - if (Status == STATUS_USER_APC) \ - { \ - /* We were preempted by an APC */ \ - if (KeReadStateSemaphore(s)) \ - { \ - /* It's still signaled, so wait on it */ \ - KeWaitForSingleObject(s, \ - Executive, \ - KernelMode, \ - FALSE, \ - NULL); \ - Status = STATUS_SUCCESS; \ - } \ - } \ -} - -// -// Releases an LPC Semaphore to complete a wait -// -#define LpcpCompleteWait(s) \ -{ \ - /* Release the semaphore */ \ - LPCTRACE(LPC_SEND_DEBUG, "Release: %p\n", s); \ - KeReleaseSemaphore(s, 1, 1, FALSE); \ -} - -// -// Internal flag used for Kernel LPC Messages -// -#define LPCP_KERNEL_MESSAGE 0x8000
// // Internal Port Management @@ -214,3 +123,8 @@ extern PAGED_LOOKASIDE_LIST LpcpMessagesLookaside; extern ULONG LpcpMaxMessageSize; extern ULONG LpcpTraceLevel; + +// +// Inlined Functions +// +#include "lpc_x.h"
Added: trunk/reactos/ntoskrnl/lpc/ntlpc/lpc_x.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/lpc/ntlpc/lpc_x.h?... ============================================================================== --- trunk/reactos/ntoskrnl/lpc/ntlpc/lpc_x.h (added) +++ trunk/reactos/ntoskrnl/lpc/ntlpc/lpc_x.h Sun Nov 5 23:31:35 2006 @@ -1,0 +1,122 @@ +/* +* PROJECT: ReactOS Kernel +* LICENSE: GPL - See COPYING in the top level directory +* FILE: ntoskrnl/include/lpc_x.h +* PURPOSE: Intenral Inlined Functions for Local Procedure Call +* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) +*/ + +// +// Gets the message type, removing the kernel-mode flag +// +#define LpcpGetMessageType(x) \ + ((x)->u2.s2.Type &~ LPC_KERNELMODE_MESSAGE) + +// +// Waits on an LPC semaphore for a receive operation +// +#define LpcpReceiveWait(s, w) \ +{ \ + LPCTRACE(LPC_REPLY_DEBUG, "Wait: %p\n", s); \ + Status = KeWaitForSingleObject(s, \ + WrLpcReceive, \ + w, \ + FALSE, \ + NULL); \ + LPCTRACE(LPC_REPLY_DEBUG, "Wait done: %lx\n", Status); \ +} + +// +// Waits on an LPC semaphore for a reply operation +// +#define LpcpReplyWait(s, w) \ +{ \ + LPCTRACE(LPC_SEND_DEBUG, "Wait: %p\n", s); \ + Status = KeWaitForSingleObject(s, \ + WrLpcReply, \ + w, \ + FALSE, \ + NULL); \ + LPCTRACE(LPC_SEND_DEBUG, "Wait done: %lx\n", Status); \ + if (Status == STATUS_USER_APC) \ + { \ + /* We were preempted by an APC */ \ + if (KeReadStateSemaphore(s)) \ + { \ + /* It's still signaled, so wait on it */ \ + KeWaitForSingleObject(s, \ + Executive, \ + KernelMode, \ + FALSE, \ + NULL); \ + Status = STATUS_SUCCESS; \ + } \ + } \ +} + +// +// Waits on an LPC semaphore for a connect operation +// +#define LpcpConnectWait(s, w) \ +{ \ + LPCTRACE(LPC_CONNECT_DEBUG, "Wait: %p\n", s); \ + Status = KeWaitForSingleObject(s, \ + Executive, \ + w, \ + FALSE, \ + NULL); \ + LPCTRACE(LPC_CONNECT_DEBUG, "Wait done: %lx\n", Status);\ + if (Status == STATUS_USER_APC) \ + { \ + /* We were preempted by an APC */ \ + if (KeReadStateSemaphore(s)) \ + { \ + /* It's still signaled, so wait on it */ \ + KeWaitForSingleObject(s, \ + Executive, \ + KernelMode, \ + FALSE, \ + NULL); \ + Status = STATUS_SUCCESS; \ + } \ + } \ +} + +// +// Releases an LPC Semaphore to complete a wait +// +#define LpcpCompleteWait(s) \ +{ \ + /* Release the semaphore */ \ + LPCTRACE(LPC_SEND_DEBUG, "Release: %p\n", s); \ + KeReleaseSemaphore(s, 1, 1, FALSE); \ +} + +// +// Allocates a new message +// +PLPCP_MESSAGE +FORCEINLINE +LpcpAllocateFromPortZone(VOID) +{ + PLPCP_MESSAGE Message; + + /* Allocate a message from the port zone while holding the lock */ + KeAcquireGuardedMutex(&LpcpLock); + Message = ExAllocateFromPagedLookasideList(&LpcpMessagesLookaside); + if (!Message) + { + /* Fail, and let caller cleanup */ + KeReleaseGuardedMutex(&LpcpLock); + return NULL; + } + + /* Initialize it */ + InitializeListHead(&Message->Entry); + Message->RepliedToThread = NULL; + Message->Request.u2.ZeroInit = 0; + + /* Release the lock */ + KeReleaseGuardedMutex(&LpcpLock); + return Message; +}
Modified: trunk/reactos/ntoskrnl/lpc/ntlpc/port.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/lpc/ntlpc/port.c?r... ============================================================================== --- trunk/reactos/ntoskrnl/lpc/ntlpc/port.c (original) +++ trunk/reactos/ntoskrnl/lpc/ntlpc/port.c Sun Nov 5 23:31:35 2006 @@ -19,7 +19,7 @@ ULONG LpcpMaxMessageSize; PAGED_LOOKASIDE_LIST LpcpMessagesLookaside; KGUARDED_MUTEX LpcpLock; -ULONG LpcpTraceLevel = 0xFFFFFFFF; +ULONG LpcpTraceLevel = LPC_CLOSE_DEBUG; ULONG LpcpNextMessageId = 1, LpcpNextCallbackId = 1;
static GENERIC_MAPPING LpcpPortMapping =
Modified: trunk/reactos/ntoskrnl/lpc/ntlpc/reply.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/lpc/ntlpc/reply.c?... ============================================================================== --- trunk/reactos/ntoskrnl/lpc/ntlpc/reply.c (original) +++ trunk/reactos/ntoskrnl/lpc/ntlpc/reply.c Sun Nov 5 23:31:35 2006 @@ -230,24 +230,18 @@ return Status; }
- /* Acquire the LPC Lock */ - KeAcquireGuardedMutex(&LpcpLock); - - /* Allocate a new message */ - Message = ExAllocateFromPagedLookasideList(&LpcpMessagesLookaside); + /* Allocate a message from the port zone */ + Message = LpcpAllocateFromPortZone(); if (!Message) { - /* Out of memory, fail */ - KeReleaseGuardedMutex(&LpcpLock); + /* Fail if we couldn't allocate a message */ ObDereferenceObject(WakeupThread); ObDereferenceObject(Port); return STATUS_NO_MEMORY; }
- /* Initialize the header */ - InitializeListHead(&Message->Entry); - Message->RepliedToThread = NULL; - Message->Request.u2.ZeroInit = 0; + /* Keep the lock acquired */ + KeAcquireGuardedMutex(&LpcpLock);
/* Make sure this is the reply the thread is waiting for */ if (WakeupThread->LpcReplyMessageId != ReplyMessage->MessageId) @@ -284,7 +278,7 @@ if (!(WakeupThread->LpcExitThreadCalled) && !(IsListEmpty(&WakeupThread->LpcReplyChain))) { - /* Remove us from it and reinitiailize it */ + /* Remove us from it and reinitialize it */ RemoveEntryList(&WakeupThread->LpcReplyChain); InitializeListHead(&WakeupThread->LpcReplyChain); }
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 Sun Nov 5 23:31:35 2006 @@ -16,15 +16,136 @@ /* PUBLIC FUNCTIONS **********************************************************/
/* - * @unimplemented + * @implemented */ NTSTATUS NTAPI -LpcRequestPort(IN PVOID Port, +LpcRequestPort(IN PVOID PortObject, IN PPORT_MESSAGE LpcMessage) { - UNIMPLEMENTED; - return STATUS_NOT_IMPLEMENTED; + PLPCP_PORT_OBJECT Port = (PLPCP_PORT_OBJECT)PortObject, QueuePort; + ULONG MessageType; + PLPCP_MESSAGE Message; + KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); + PAGED_CODE(); + LPCTRACE(LPC_SEND_DEBUG, "Port: %p. Message: %p\n", Port, LpcMessage); + + /* Check if this is a non-datagram message */ + if (LpcMessage->u2.s2.Type) + { + /* Get the message type */ + MessageType = LpcpGetMessageType(LpcMessage); + + /* Validate it */ + if ((MessageType < LPC_DATAGRAM) || (MessageType > LPC_CLIENT_DIED)) + { + /* Fail */ + return STATUS_INVALID_PARAMETER; + } + + /* Mark this as a kernel-mode message only if we really came from there */ + if ((PreviousMode == KernelMode) && + (LpcMessage->u2.s2.Type & LPC_KERNELMODE_MESSAGE)) + { + /* We did, this is a kernel mode message */ + MessageType |= LPC_KERNELMODE_MESSAGE; + } + } + else + { + /* This is a datagram */ + MessageType = LPC_DATAGRAM; + } + + /* Can't have data information on this type of call */ + if (LpcMessage->u2.s2.DataInfoOffset) return STATUS_INVALID_PARAMETER; + + /* Validate message sizes */ + if ((LpcMessage->u1.s1.TotalLength > Port->MaxMessageLength) || + (LpcMessage->u1.s1.TotalLength <= LpcMessage->u1.s1.DataLength)) + { + /* Fail */ + return STATUS_PORT_MESSAGE_TOO_LONG; + } + + /* Allocate a new message */ + Message = LpcpAllocateFromPortZone(); + if (!Message) return STATUS_NO_MEMORY; + + /* Clear the context */ + Message->PortContext = NULL; + + /* Copy the message */ + LpcpMoveMessage(&Message->Request, + LpcMessage, + LpcMessage + 1, + MessageType, + &PsGetCurrentThread()->Cid); + + /* Acquire the LPC lock */ + KeAcquireGuardedMutex(&LpcpLock); + + /* Check if this is anything but a connection port */ + if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CONNECTION_PORT) + { + /* The queue port is the connected port */ + QueuePort = Port->ConnectedPort; + if (QueuePort) + { + /* Check if this is a client port */ + if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT) + { + /* Then copy the context */ + Message->PortContext = QueuePort->PortContext; + QueuePort = Port->ConnectionPort; + } + else if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_COMMUNICATION_PORT) + { + /* Any other kind of port, use the connection port */ + QueuePort = Port->ConnectionPort; + } + } + } + else + { + /* For connection ports, use the port itself */ + QueuePort = PortObject; + } + + /* Make sure we have a port */ + if (QueuePort) + { + /* Generate the Message ID and set it */ + Message->Request.MessageId = LpcpNextMessageId++; + if (!LpcpNextMessageId) LpcpNextMessageId = 1; + Message->Request.CallbackId = 0; + + /* No Message ID for the thread */ + PsGetCurrentThread()->LpcReplyMessageId = 0; + + /* Insert the message in our chain */ + InsertTailList(&QueuePort->MsgQueue.ReceiveHead, &Message->Entry); + + /* Release the lock and release the semaphore */ + KeReleaseGuardedMutex(&LpcpLock); + LpcpCompleteWait(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); + } + + /* We're done */ + LPCTRACE(LPC_SEND_DEBUG, "Port: %p. Message: %p\n", QueuePort, Message); + return STATUS_SUCCESS; + } + + /* If we got here, then free the message and fail */ + LpcpFreeToPortZone(Message, TRUE); + KeReleaseGuardedMutex(&LpcpLock); + return STATUS_PORT_DISCONNECTED; }
/* @@ -127,17 +248,11 @@ return STATUS_PORT_MESSAGE_TOO_LONG; }
- /* Acquire the lock */ - KeAcquireGuardedMutex(&LpcpLock); - - /* Allocate a message */ - Message = ExAllocateFromPagedLookasideList(&LpcpMessagesLookaside); - KeReleaseGuardedMutex(&LpcpLock); - - /* Check if allocation worked */ + /* Allocate a message from the port zone */ + Message = LpcpAllocateFromPortZone(); if (!Message) { - /* Fail */ + /* Fail if we couldn't allocate a message */ ObDereferenceObject(Port); return STATUS_NO_MEMORY; }
Modified: trunk/reactos/subsystems/win32/csrss/api/process.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/csrss/api/... ============================================================================== --- trunk/reactos/subsystems/win32/csrss/api/process.c (original) +++ trunk/reactos/subsystems/win32/csrss/api/process.c Sun Nov 5 23:31:35 2006 @@ -260,8 +260,8 @@
CSR_API(CsrTerminateProcess) { - Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE); - Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE); + Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE); + Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
if (ProcessData == NULL) {
Modified: trunk/reactos/subsystems/win32/csrss/api/wapi.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/win32/csrss/api/... ============================================================================== --- trunk/reactos/subsystems/win32/csrss/api/wapi.c (original) +++ trunk/reactos/subsystems/win32/csrss/api/wapi.c Sun Nov 5 23:31:35 2006 @@ -72,9 +72,9 @@ unsigned DefIndex; ULONG Type;
- DPRINT("CSR: Calling handler for type: %x.\n", Request->Type); + DPRINT1("CSR: Calling handler for type: %x.\n", Request->Type); Type = Request->Type & 0xFFFF; /* FIXME: USE MACRO */ - DPRINT("CSR: API Number: %x ServerID: %x\n",Type, Request->Type >> 16); + DPRINT1("CSR: API Number: %x ServerID: %x\n",Type, Request->Type >> 16);
/* FIXME: Extract DefIndex instead of looping */ for (DefIndex = 0; ! Found && DefIndex < ApiDefinitionsCount; DefIndex++) @@ -218,13 +218,14 @@ &Request->Header); if (!NT_SUCCESS(Status)) { - DPRINT1("NtReplyWaitReceivePort failed\n"); - break; + DPRINT1("NtReplyWaitReceivePort failed: %lx\n", Status); + break; }
/* If the connection was closed, handle that */ if (Request->Header.u2.s2.Type == LPC_PORT_CLOSED) { + DPRINT1("Port died, oh well\n"); CsrFreeProcessData( Request->Header.ClientId.UniqueProcess ); break; } @@ -236,9 +237,16 @@ continue; }
+ if (Request->Header.u2.s2.Type == LPC_CLIENT_DIED) + { + DPRINT1("Clietn died, oh well\n"); + Reply = NULL; + continue; + } + DPRINT("CSR: Got CSR API: %x [Message Origin: %x]\n", - Request->Type, - Request->Header.ClientId.UniqueProcess); + Request->Type, + Request->Header.ClientId.UniqueThread);
/* Get the Process Data */ ProcessData = CsrGetProcessData(Request->Header.ClientId.UniqueProcess); @@ -252,7 +260,7 @@ if (ProcessData->Terminated) { DPRINT1("Message %d: process %d already terminated\n", - Request->Type, (ULONG)Request->Header.ClientId.UniqueProcess); + Request->Type, (ULONG)Request->Header.ClientId.UniqueProcess); continue; }
@@ -271,7 +279,7 @@ /* Send back the reply */ Reply = Request; } - + /* Close the port and exit the thread */ NtClose(ServerPort); RtlExitUserThread(STATUS_SUCCESS);