if (Message)\r
{\r
/* FIXME: TODO */\r
- ASSERT(FALSE);\r
+ KEBUGCHECK(0);\r
}\r
\r
/* Release the lock */\r
ConnectionInfoLength = Port->MaxConnectionInfoLength;\r
}\r
\r
- /* Allocate a message from the port zone while holding the lock */\r
- KeAcquireGuardedMutex(&LpcpLock);\r
- Message = ExAllocateFromPagedLookasideList(&LpcpMessagesLookaside);\r
+ /* Allocate a message from the port zone */\r
+ Message = LpcpAllocateFromPortZone();\r
if (!Message)\r
{\r
/* Fail if we couldn't allocate a message */\r
- KeReleaseGuardedMutex(&LpcpLock);\r
if (SectionToMap) ObDereferenceObject(SectionToMap);\r
ObDereferenceObject(ClientPort);\r
return STATUS_NO_MEMORY;\r
}\r
\r
- /* Initialize it */\r
- InitializeListHead(&Message->Entry);\r
- Message->RepliedToThread = NULL;\r
- Message->Request.u2.ZeroInit = 0;\r
-\r
- /* Release the lock */\r
- KeReleaseGuardedMutex(&LpcpLock);\r
-\r
/* Set pointer to the connection message and fill in the CID */\r
ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);\r
Message->Request.ClientId = Thread->Cid;\r
#endif\r
#endif\r
\r
-//\r
-// Gets the message type, removing the kernel-mode flag\r
-//\r
-#define LpcpGetMessageType(x) \\r
- ((x)->u2.s2.Type &~ LPCP_KERNEL_MESSAGE)\r
-\r
-//\r
-// Waits on an LPC semaphore for a receive operation\r
-//\r
-#define LpcpReceiveWait(s, w) \\r
-{ \\r
- LPCTRACE(LPC_REPLY_DEBUG, "Wait: %p\n", s); \\r
- Status = KeWaitForSingleObject(s, \\r
- WrLpcReceive, \\r
- w, \\r
- FALSE, \\r
- NULL); \\r
- LPCTRACE(LPC_REPLY_DEBUG, "Wait done: %lx\n", Status); \\r
-}\r
-\r
-//\r
-// Waits on an LPC semaphore for a reply operation\r
-//\r
-#define LpcpReplyWait(s, w) \\r
-{ \\r
- LPCTRACE(LPC_SEND_DEBUG, "Wait: %p\n", s); \\r
- Status = KeWaitForSingleObject(s, \\r
- WrLpcReply, \\r
- w, \\r
- FALSE, \\r
- NULL); \\r
- LPCTRACE(LPC_SEND_DEBUG, "Wait done: %lx\n", Status); \\r
- if (Status == STATUS_USER_APC) \\r
- { \\r
- /* We were preempted by an APC */ \\r
- if (KeReadStateSemaphore(s)) \\r
- { \\r
- /* It's still signaled, so wait on it */ \\r
- KeWaitForSingleObject(s, \\r
- Executive, \\r
- KernelMode, \\r
- FALSE, \\r
- NULL); \\r
- Status = STATUS_SUCCESS; \\r
- } \\r
- } \\r
-}\r
-\r
-//\r
-// Waits on an LPC semaphore for a connect operation\r
-//\r
-#define LpcpConnectWait(s, w) \\r
-{ \\r
- LPCTRACE(LPC_CONNECT_DEBUG, "Wait: %p\n", s); \\r
- Status = KeWaitForSingleObject(s, \\r
- Executive, \\r
- w, \\r
- FALSE, \\r
- NULL); \\r
- LPCTRACE(LPC_CONNECT_DEBUG, "Wait done: %lx\n", Status);\\r
- if (Status == STATUS_USER_APC) \\r
- { \\r
- /* We were preempted by an APC */ \\r
- if (KeReadStateSemaphore(s)) \\r
- { \\r
- /* It's still signaled, so wait on it */ \\r
- KeWaitForSingleObject(s, \\r
- Executive, \\r
- KernelMode, \\r
- FALSE, \\r
- NULL); \\r
- Status = STATUS_SUCCESS; \\r
- } \\r
- } \\r
-}\r
-\r
-//\r
-// Releases an LPC Semaphore to complete a wait\r
-//\r
-#define LpcpCompleteWait(s) \\r
-{ \\r
- /* Release the semaphore */ \\r
- LPCTRACE(LPC_SEND_DEBUG, "Release: %p\n", s); \\r
- KeReleaseSemaphore(s, 1, 1, FALSE); \\r
-}\r
-\r
-//\r
-// Internal flag used for Kernel LPC Messages\r
-//\r
-#define LPCP_KERNEL_MESSAGE 0x8000\r
-\r
//\r
// Internal Port Management\r
//\r
extern PAGED_LOOKASIDE_LIST LpcpMessagesLookaside;\r
extern ULONG LpcpMaxMessageSize;\r
extern ULONG LpcpTraceLevel;\r
+\r
+//\r
+// Inlined Functions\r
+//\r
+#include "lpc_x.h"\r
--- /dev/null
+/*\r
+* PROJECT: ReactOS Kernel\r
+* LICENSE: GPL - See COPYING in the top level directory\r
+* FILE: ntoskrnl/include/lpc_x.h\r
+* PURPOSE: Intenral Inlined Functions for Local Procedure Call\r
+* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)\r
+*/\r
+\r
+//\r
+// Gets the message type, removing the kernel-mode flag\r
+//\r
+#define LpcpGetMessageType(x) \\r
+ ((x)->u2.s2.Type &~ LPC_KERNELMODE_MESSAGE)\r
+\r
+//\r
+// Waits on an LPC semaphore for a receive operation\r
+//\r
+#define LpcpReceiveWait(s, w) \\r
+{ \\r
+ LPCTRACE(LPC_REPLY_DEBUG, "Wait: %p\n", s); \\r
+ Status = KeWaitForSingleObject(s, \\r
+ WrLpcReceive, \\r
+ w, \\r
+ FALSE, \\r
+ NULL); \\r
+ LPCTRACE(LPC_REPLY_DEBUG, "Wait done: %lx\n", Status); \\r
+}\r
+\r
+//\r
+// Waits on an LPC semaphore for a reply operation\r
+//\r
+#define LpcpReplyWait(s, w) \\r
+{ \\r
+ LPCTRACE(LPC_SEND_DEBUG, "Wait: %p\n", s); \\r
+ Status = KeWaitForSingleObject(s, \\r
+ WrLpcReply, \\r
+ w, \\r
+ FALSE, \\r
+ NULL); \\r
+ LPCTRACE(LPC_SEND_DEBUG, "Wait done: %lx\n", Status); \\r
+ if (Status == STATUS_USER_APC) \\r
+ { \\r
+ /* We were preempted by an APC */ \\r
+ if (KeReadStateSemaphore(s)) \\r
+ { \\r
+ /* It's still signaled, so wait on it */ \\r
+ KeWaitForSingleObject(s, \\r
+ Executive, \\r
+ KernelMode, \\r
+ FALSE, \\r
+ NULL); \\r
+ Status = STATUS_SUCCESS; \\r
+ } \\r
+ } \\r
+}\r
+\r
+//\r
+// Waits on an LPC semaphore for a connect operation\r
+//\r
+#define LpcpConnectWait(s, w) \\r
+{ \\r
+ LPCTRACE(LPC_CONNECT_DEBUG, "Wait: %p\n", s); \\r
+ Status = KeWaitForSingleObject(s, \\r
+ Executive, \\r
+ w, \\r
+ FALSE, \\r
+ NULL); \\r
+ LPCTRACE(LPC_CONNECT_DEBUG, "Wait done: %lx\n", Status);\\r
+ if (Status == STATUS_USER_APC) \\r
+ { \\r
+ /* We were preempted by an APC */ \\r
+ if (KeReadStateSemaphore(s)) \\r
+ { \\r
+ /* It's still signaled, so wait on it */ \\r
+ KeWaitForSingleObject(s, \\r
+ Executive, \\r
+ KernelMode, \\r
+ FALSE, \\r
+ NULL); \\r
+ Status = STATUS_SUCCESS; \\r
+ } \\r
+ } \\r
+}\r
+\r
+//\r
+// Releases an LPC Semaphore to complete a wait\r
+//\r
+#define LpcpCompleteWait(s) \\r
+{ \\r
+ /* Release the semaphore */ \\r
+ LPCTRACE(LPC_SEND_DEBUG, "Release: %p\n", s); \\r
+ KeReleaseSemaphore(s, 1, 1, FALSE); \\r
+}\r
+\r
+//\r
+// Allocates a new message\r
+//\r
+PLPCP_MESSAGE\r
+FORCEINLINE\r
+LpcpAllocateFromPortZone(VOID)\r
+{\r
+ PLPCP_MESSAGE Message;\r
+\r
+ /* Allocate a message from the port zone while holding the lock */\r
+ KeAcquireGuardedMutex(&LpcpLock);\r
+ Message = ExAllocateFromPagedLookasideList(&LpcpMessagesLookaside);\r
+ if (!Message)\r
+ {\r
+ /* Fail, and let caller cleanup */\r
+ KeReleaseGuardedMutex(&LpcpLock);\r
+ return NULL;\r
+ }\r
+\r
+ /* Initialize it */\r
+ InitializeListHead(&Message->Entry);\r
+ Message->RepliedToThread = NULL;\r
+ Message->Request.u2.ZeroInit = 0;\r
+\r
+ /* Release the lock */\r
+ KeReleaseGuardedMutex(&LpcpLock);\r
+ return Message;\r
+}\r
ULONG LpcpMaxMessageSize;\r
PAGED_LOOKASIDE_LIST LpcpMessagesLookaside;\r
KGUARDED_MUTEX LpcpLock;\r
-ULONG LpcpTraceLevel = 0xFFFFFFFF;\r
+ULONG LpcpTraceLevel = LPC_CLOSE_DEBUG;\r
ULONG LpcpNextMessageId = 1, LpcpNextCallbackId = 1;\r
\r
static GENERIC_MAPPING LpcpPortMapping = \r
return Status;\r
}\r
\r
- /* Acquire the LPC Lock */\r
- KeAcquireGuardedMutex(&LpcpLock);\r
-\r
- /* Allocate a new message */\r
- Message = ExAllocateFromPagedLookasideList(&LpcpMessagesLookaside);\r
+ /* Allocate a message from the port zone */\r
+ Message = LpcpAllocateFromPortZone();\r
if (!Message)\r
{\r
- /* Out of memory, fail */\r
- KeReleaseGuardedMutex(&LpcpLock);\r
+ /* Fail if we couldn't allocate a message */\r
ObDereferenceObject(WakeupThread);\r
ObDereferenceObject(Port);\r
return STATUS_NO_MEMORY;\r
}\r
\r
- /* Initialize the header */\r
- InitializeListHead(&Message->Entry);\r
- Message->RepliedToThread = NULL;\r
- Message->Request.u2.ZeroInit = 0;\r
+ /* Keep the lock acquired */\r
+ KeAcquireGuardedMutex(&LpcpLock);\r
\r
/* Make sure this is the reply the thread is waiting for */\r
if (WakeupThread->LpcReplyMessageId != ReplyMessage->MessageId)\r
if (!(WakeupThread->LpcExitThreadCalled) &&\r
!(IsListEmpty(&WakeupThread->LpcReplyChain)))\r
{\r
- /* Remove us from it and reinitiailize it */\r
+ /* Remove us from it and reinitialize it */\r
RemoveEntryList(&WakeupThread->LpcReplyChain);\r
InitializeListHead(&WakeupThread->LpcReplyChain);\r
}\r
/* PUBLIC FUNCTIONS **********************************************************/\r
\r
/*\r
- * @unimplemented\r
+ * @implemented\r
*/\r
NTSTATUS\r
NTAPI\r
-LpcRequestPort(IN PVOID Port,\r
+LpcRequestPort(IN PVOID PortObject,\r
IN PPORT_MESSAGE LpcMessage)\r
{\r
- UNIMPLEMENTED;\r
- return STATUS_NOT_IMPLEMENTED;\r
+ PLPCP_PORT_OBJECT Port = (PLPCP_PORT_OBJECT)PortObject, QueuePort;\r
+ ULONG MessageType;\r
+ PLPCP_MESSAGE Message;\r
+ KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();\r
+ PAGED_CODE();\r
+ LPCTRACE(LPC_SEND_DEBUG, "Port: %p. Message: %p\n", Port, LpcMessage);\r
+\r
+ /* Check if this is a non-datagram message */\r
+ if (LpcMessage->u2.s2.Type)\r
+ {\r
+ /* Get the message type */\r
+ MessageType = LpcpGetMessageType(LpcMessage);\r
+\r
+ /* Validate it */\r
+ if ((MessageType < LPC_DATAGRAM) || (MessageType > LPC_CLIENT_DIED))\r
+ {\r
+ /* Fail */\r
+ return STATUS_INVALID_PARAMETER;\r
+ }\r
+\r
+ /* Mark this as a kernel-mode message only if we really came from there */\r
+ if ((PreviousMode == KernelMode) &&\r
+ (LpcMessage->u2.s2.Type & LPC_KERNELMODE_MESSAGE))\r
+ {\r
+ /* We did, this is a kernel mode message */\r
+ MessageType |= LPC_KERNELMODE_MESSAGE;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ /* This is a datagram */\r
+ MessageType = LPC_DATAGRAM;\r
+ }\r
+\r
+ /* Can't have data information on this type of call */\r
+ if (LpcMessage->u2.s2.DataInfoOffset) return STATUS_INVALID_PARAMETER;\r
+\r
+ /* Validate message sizes */\r
+ if ((LpcMessage->u1.s1.TotalLength > Port->MaxMessageLength) ||\r
+ (LpcMessage->u1.s1.TotalLength <= LpcMessage->u1.s1.DataLength))\r
+ {\r
+ /* Fail */\r
+ return STATUS_PORT_MESSAGE_TOO_LONG;\r
+ }\r
+\r
+ /* Allocate a new message */\r
+ Message = LpcpAllocateFromPortZone();\r
+ if (!Message) return STATUS_NO_MEMORY;\r
+\r
+ /* Clear the context */\r
+ Message->PortContext = NULL;\r
+\r
+ /* Copy the message */\r
+ LpcpMoveMessage(&Message->Request,\r
+ LpcMessage,\r
+ LpcMessage + 1,\r
+ MessageType,\r
+ &PsGetCurrentThread()->Cid);\r
+\r
+ /* Acquire the LPC lock */\r
+ KeAcquireGuardedMutex(&LpcpLock);\r
+\r
+ /* Check if this is anything but a connection port */\r
+ if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CONNECTION_PORT)\r
+ {\r
+ /* The queue port is the connected port */\r
+ QueuePort = Port->ConnectedPort;\r
+ if (QueuePort)\r
+ {\r
+ /* Check if this is a client port */\r
+ if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)\r
+ {\r
+ /* Then copy the context */\r
+ Message->PortContext = QueuePort->PortContext;\r
+ QueuePort = Port->ConnectionPort;\r
+ }\r
+ else if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_COMMUNICATION_PORT)\r
+ {\r
+ /* Any other kind of port, use the connection port */\r
+ QueuePort = Port->ConnectionPort;\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ /* For connection ports, use the port itself */\r
+ QueuePort = PortObject;\r
+ }\r
+\r
+ /* Make sure we have a port */\r
+ if (QueuePort)\r
+ {\r
+ /* Generate the Message ID and set it */\r
+ Message->Request.MessageId = LpcpNextMessageId++;\r
+ if (!LpcpNextMessageId) LpcpNextMessageId = 1;\r
+ Message->Request.CallbackId = 0;\r
+\r
+ /* No Message ID for the thread */\r
+ PsGetCurrentThread()->LpcReplyMessageId = 0;\r
+\r
+ /* Insert the message in our chain */\r
+ InsertTailList(&QueuePort->MsgQueue.ReceiveHead, &Message->Entry);\r
+\r
+ /* Release the lock and release the semaphore */\r
+ KeReleaseGuardedMutex(&LpcpLock);\r
+ LpcpCompleteWait(QueuePort->MsgQueue.Semaphore);\r
+\r
+ /* If this is a waitable port, wake it up */\r
+ if (QueuePort->Flags & LPCP_WAITABLE_PORT)\r
+ {\r
+ /* Wake it */\r
+ KeSetEvent(&QueuePort->WaitEvent, IO_NO_INCREMENT, FALSE);\r
+ }\r
+\r
+ /* We're done */\r
+ LPCTRACE(LPC_SEND_DEBUG, "Port: %p. Message: %p\n", QueuePort, Message);\r
+ return STATUS_SUCCESS;\r
+ }\r
+\r
+ /* If we got here, then free the message and fail */\r
+ LpcpFreeToPortZone(Message, TRUE);\r
+ KeReleaseGuardedMutex(&LpcpLock);\r
+ return STATUS_PORT_DISCONNECTED;\r
}\r
\r
/*\r
return STATUS_PORT_MESSAGE_TOO_LONG;\r
}\r
\r
- /* Acquire the lock */\r
- KeAcquireGuardedMutex(&LpcpLock);\r
-\r
- /* Allocate a message */\r
- Message = ExAllocateFromPagedLookasideList(&LpcpMessagesLookaside);\r
- KeReleaseGuardedMutex(&LpcpLock);\r
-\r
- /* Check if allocation worked */\r
+ /* Allocate a message from the port zone */\r
+ Message = LpcpAllocateFromPortZone();\r
if (!Message)\r
{\r
- /* Fail */\r
+ /* Fail if we couldn't allocate a message */\r
ObDereferenceObject(Port);\r
return STATUS_NO_MEMORY;\r
}\r
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)
{
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++)
&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;
}
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);
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;
}
/* Send back the reply */
Reply = Request;
}
-
+
/* Close the port and exit the thread */
NtClose(ServerPort);
RtlExitUserThread(STATUS_SUCCESS);