reactos/ntoskrnl/include/internal/lpc_x.h

174 lines
6.3 KiB
C

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/include/internal/lpc_x.h
* PURPOSE: Internal 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, \
WrExecutive, \
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, \
WrExecutive, \
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
//
static __inline
PLPCP_MESSAGE
LpcpAllocateFromPortZone(VOID)
{
PLPCP_MESSAGE Message;
/* Allocate a message from the port zone while holding the lock */
KeAcquireGuardedMutex(&LpcpLock);
Message = (PLPCP_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;
}
//
// Get the LPC Message associated to the Thread
//
FORCEINLINE
PLPCP_MESSAGE
LpcpGetMessageFromThread(IN PETHREAD Thread)
{
/* Check if the port flag is set */
if (((ULONG_PTR)Thread->LpcReplyMessage) & LPCP_THREAD_FLAG_IS_PORT)
{
/* The pointer is actually a port, not a message, so return NULL */
return NULL;
}
/* Otherwise, this is a message. Return the pointer */
return (PLPCP_MESSAGE)((ULONG_PTR)Thread->LpcReplyMessage & ~LPCP_THREAD_FLAGS);
}
FORCEINLINE
PLPCP_PORT_OBJECT
LpcpGetPortFromThread(IN PETHREAD Thread)
{
/* Check if the port flag is set */
if (((ULONG_PTR)Thread->LpcReplyMessage) & LPCP_THREAD_FLAG_IS_PORT)
{
/* The pointer is actually a port, return it */
return (PLPCP_PORT_OBJECT)((ULONG_PTR)Thread->LpcWaitingOnPort &
~LPCP_THREAD_FLAGS);
}
/* Otherwise, this is a message. There is nothing to return */
return NULL;
}
FORCEINLINE
VOID
LpcpSetPortToThread(IN PETHREAD Thread,
IN PLPCP_PORT_OBJECT Port)
{
/* Set the port object */
Thread->LpcWaitingOnPort = (PVOID)(((ULONG_PTR)Port) |
LPCP_THREAD_FLAG_IS_PORT);
}
FORCEINLINE
PLPCP_DATA_INFO
LpcpGetDataInfoFromMessage(PPORT_MESSAGE Message)
{
return (PLPCP_DATA_INFO)((PUCHAR)Message + Message->u2.s2.DataInfoOffset);
}