xref: /reactos/ntoskrnl/include/internal/lpc_x.h (revision 8a978a17)
1 /*
2 * PROJECT:         ReactOS Kernel
3 * LICENSE:         GPL - See COPYING in the top level directory
4 * FILE:            ntoskrnl/include/internal/lpc_x.h
5 * PURPOSE:         Internal Inlined Functions for Local Procedure Call
6 * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
7 */
8 
9 //
10 // Gets the message type, removing the kernel-mode flag
11 //
12 #define LpcpGetMessageType(x)                               \
13     ((x)->u2.s2.Type &~ LPC_KERNELMODE_MESSAGE)
14 
15 //
16 // Waits on an LPC semaphore for a receive operation
17 //
18 #define LpcpReceiveWait(s, w)                               \
19 {                                                           \
20     LPCTRACE(LPC_REPLY_DEBUG, "Wait: %p\n", s);             \
21     Status = KeWaitForSingleObject(s,                       \
22                                    WrLpcReceive,            \
23                                    w,                       \
24                                    FALSE,                   \
25                                    NULL);                   \
26     LPCTRACE(LPC_REPLY_DEBUG, "Wait done: %lx\n", Status);  \
27 }
28 
29 //
30 // Waits on an LPC semaphore for a reply operation
31 //
32 #define LpcpReplyWait(s, w)                                 \
33 {                                                           \
34     LPCTRACE(LPC_SEND_DEBUG, "Wait: %p\n", s);              \
35     Status = KeWaitForSingleObject(s,                       \
36                                    WrLpcReply,              \
37                                    w,                       \
38                                    FALSE,                   \
39                                    NULL);                   \
40     LPCTRACE(LPC_SEND_DEBUG, "Wait done: %lx\n", Status);   \
41     if (Status == STATUS_USER_APC)                          \
42     {                                                       \
43         /* We were preempted by an APC */                   \
44         if (KeReadStateSemaphore(s))                        \
45         {                                                   \
46             /* It's still signaled, so wait on it */        \
47             KeWaitForSingleObject(s,                        \
48                                   WrExecutive,              \
49                                   KernelMode,               \
50                                   FALSE,                    \
51                                   NULL);                    \
52             Status = STATUS_SUCCESS;                        \
53         }                                                   \
54     }                                                       \
55 }
56 
57 //
58 // Waits on an LPC semaphore for a connect operation
59 //
60 #define LpcpConnectWait(s, w)                               \
61 {                                                           \
62     LPCTRACE(LPC_CONNECT_DEBUG, "Wait: %p\n", s);           \
63     Status = KeWaitForSingleObject(s,                       \
64                                    Executive,               \
65                                    w,                       \
66                                    FALSE,                   \
67                                    NULL);                   \
68     LPCTRACE(LPC_CONNECT_DEBUG, "Wait done: %lx\n", Status);\
69     if (Status == STATUS_USER_APC)                          \
70     {                                                       \
71         /* We were preempted by an APC */                   \
72         if (KeReadStateSemaphore(s))                        \
73         {                                                   \
74             /* It's still signaled, so wait on it */        \
75             KeWaitForSingleObject(s,                        \
76                                   WrExecutive,              \
77                                   KernelMode,               \
78                                   FALSE,                    \
79                                   NULL);                    \
80             Status = STATUS_SUCCESS;                        \
81         }                                                   \
82     }                                                       \
83 }
84 
85 //
86 // Releases an LPC Semaphore to complete a wait
87 //
88 #define LpcpCompleteWait(s)                                 \
89 {                                                           \
90     /* Release the semaphore */                             \
91     LPCTRACE(LPC_SEND_DEBUG, "Release: %p\n", s);           \
92     KeReleaseSemaphore(s, 1, 1, FALSE);                     \
93 }
94 
95 //
96 // Allocates a new message
97 //
98 static __inline
99 PLPCP_MESSAGE
100 LpcpAllocateFromPortZone(VOID)
101 {
102     PLPCP_MESSAGE Message;
103 
104     /* Allocate a message from the port zone while holding the lock */
105     KeAcquireGuardedMutex(&LpcpLock);
106     Message = (PLPCP_MESSAGE)ExAllocateFromPagedLookasideList(&LpcpMessagesLookaside);
107     if (!Message)
108     {
109         /* Fail, and let caller cleanup */
110         KeReleaseGuardedMutex(&LpcpLock);
111         return NULL;
112     }
113 
114     /* Initialize it */
115     InitializeListHead(&Message->Entry);
116     Message->RepliedToThread = NULL;
117     Message->Request.u2.ZeroInit = 0;
118 
119     /* Release the lock */
120     KeReleaseGuardedMutex(&LpcpLock);
121     return Message;
122 }
123 
124 //
125 // Get the LPC Message associated to the Thread
126 //
127 FORCEINLINE
128 PLPCP_MESSAGE
129 LpcpGetMessageFromThread(IN PETHREAD Thread)
130 {
131     /* Check if the port flag is set */
132     if (((ULONG_PTR)Thread->LpcReplyMessage) & LPCP_THREAD_FLAG_IS_PORT)
133     {
134         /* The pointer is actually a port, not a message, so return NULL */
135         return NULL;
136     }
137 
138     /* Otherwise, this is a message. Return the pointer */
139     return (PLPCP_MESSAGE)((ULONG_PTR)Thread->LpcReplyMessage & ~LPCP_THREAD_FLAGS);
140 }
141 
142 FORCEINLINE
143 PLPCP_PORT_OBJECT
144 LpcpGetPortFromThread(IN PETHREAD Thread)
145 {
146     /* Check if the port flag is set */
147     if (((ULONG_PTR)Thread->LpcReplyMessage) & LPCP_THREAD_FLAG_IS_PORT)
148     {
149         /* The pointer is actually a port, return it */
150         return (PLPCP_PORT_OBJECT)((ULONG_PTR)Thread->LpcWaitingOnPort &
151                        ~LPCP_THREAD_FLAGS);
152     }
153 
154     /* Otherwise, this is a message. There is nothing to return */
155     return NULL;
156 }
157 
158 FORCEINLINE
159 VOID
160 LpcpSetPortToThread(IN PETHREAD Thread,
161                     IN PLPCP_PORT_OBJECT Port)
162 {
163     /* Set the port object */
164     Thread->LpcWaitingOnPort = (PVOID)(((ULONG_PTR)Port) |
165                                        LPCP_THREAD_FLAG_IS_PORT);
166 }
167 
168 FORCEINLINE
169 PLPCP_DATA_INFO
170 LpcpGetDataInfoFromMessage(PPORT_MESSAGE Message)
171 {
172     return (PLPCP_DATA_INFO)((PUCHAR)Message + Message->u2.s2.DataInfoOffset);
173 }
174