/* * 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); }