2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/lpc/close.c
5 * PURPOSE: Local Procedure Call: Rundown, Cleanup, Deletion
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
14 #include <internal/debug.h>
16 /* PRIVATE FUNCTIONS *********************************************************/
20 LpcExitThread(IN PETHREAD Thread
)
22 PLPCP_MESSAGE Message
;
24 /* Acquire the lock */
25 KeAcquireGuardedMutex(&LpcpLock
);
27 /* Make sure that the Reply Chain is empty */
28 if (!IsListEmpty(&Thread
->LpcReplyChain
))
30 /* It's not, remove the entry */
31 RemoveEntryList(&Thread
->LpcReplyChain
);
34 /* Set the thread in exit mode */
35 Thread
->LpcExitThreadCalled
= TRUE
;
36 Thread
->LpcReplyMessageId
= 0;
38 /* Check if there's a reply message */
39 Message
= Thread
->LpcReplyMessage
;
46 /* Release the lock */
47 KeReleaseGuardedMutex(&LpcpLock
);
52 LpcpFreeToPortZone(IN PLPCP_MESSAGE Message
,
55 PLPCP_CONNECTION_MESSAGE ConnectMessage
;
56 PLPCP_PORT_OBJECT ClientPort
= NULL
;
57 PETHREAD Thread
= NULL
;
58 BOOLEAN LockHeld
= Flags
& 1;
60 LPCTRACE(LPC_CLOSE_DEBUG
, "Message: %p. Flags: %lx\n", Message
, Flags
);
62 /* Acquire the lock if not already */
63 if (!LockHeld
) KeAcquireGuardedMutex(&LpcpLock
);
65 /* Check if the queue list is empty */
66 if (!IsListEmpty(&Message
->Entry
))
68 /* Remove and re-initialize */
69 RemoveEntryList(&Message
->Entry
);
70 InitializeListHead(&Message
->Entry
);
73 /* Check if we've already replied */
74 if (Message
->RepliedToThread
)
76 /* Set thread to dereference and clean up */
77 Thread
= Message
->RepliedToThread
;
78 Message
->RepliedToThread
= NULL
;
81 /* Check if this is a connection request */
82 if (Message
->Request
.u2
.s2
.Type
== LPC_CONNECTION_REQUEST
)
84 /* Get the connection message */
85 ConnectMessage
= (PLPCP_CONNECTION_MESSAGE
)(Message
+ 1);
87 /* Clear the client port */
88 ClientPort
= ConnectMessage
->ClientPort
;
89 if (ClientPort
) ConnectMessage
->ClientPort
= NULL
;
92 /* Release the lock */
93 KeReleaseGuardedMutex(&LpcpLock
);
95 /* Check if we had anything to dereference */
96 if (Thread
) ObDereferenceObject(Thread
);
97 if (ClientPort
) ObDereferenceObject(ClientPort
);
100 ExFreeToPagedLookasideList(&LpcpMessagesLookaside
, Message
);
102 /* Reacquire the lock if needed */
103 if ((LockHeld
) && !(Flags
& 2)) KeAcquireGuardedMutex(&LpcpLock
);
108 LpcpDestroyPortQueue(IN PLPCP_PORT_OBJECT Port
,
111 PLIST_ENTRY ListHead
, NextEntry
;
113 PLPCP_MESSAGE Message
;
114 PLPCP_CONNECTION_MESSAGE ConnectMessage
;
115 LPCTRACE(LPC_CLOSE_DEBUG
, "Port: %p. Flags: %lx\n", Port
, Port
->Flags
);
118 KeAcquireGuardedMutex(&LpcpLock
);
120 /* Disconnect the port to which this port is connected */
121 if (Port
->ConnectedPort
) Port
->ConnectedPort
->ConnectedPort
= NULL
;
123 /* Check if this is a connection port */
124 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_CONNECTION_PORT
)
126 /* Delete the name */
127 Port
->Flags
|= LPCP_NAME_DELETED
;
130 /* Walk all the threads waiting and signal them */
131 ListHead
= &Port
->LpcReplyChainHead
;
132 NextEntry
= ListHead
->Flink
;
133 while (NextEntry
!= ListHead
)
136 Thread
= CONTAINING_RECORD(NextEntry
, ETHREAD
, LpcReplyChain
);
138 /* Make sure we're not in exit */
139 if (Thread
->LpcExitThreadCalled
) break;
141 /* Move to the next entry */
142 NextEntry
= NextEntry
->Flink
;
144 /* Remove and reinitialize the List */
145 RemoveEntryList(&Thread
->LpcReplyChain
);
146 InitializeListHead(&Thread
->LpcReplyChain
);
148 /* Check if someone is waiting */
149 if (!KeReadStateSemaphore(&Thread
->LpcReplySemaphore
))
151 /* Get the message and check if it's a connection request */
152 Message
= Thread
->LpcReplyMessage
;
153 if (Message
->Request
.u2
.s2
.Type
== LPC_CONNECTION_REQUEST
)
155 /* Get the connection message */
156 ConnectMessage
= (PLPCP_CONNECTION_MESSAGE
)(Message
+ 1);
158 /* Check if it had a section */
159 if (ConnectMessage
->SectionToMap
)
162 ObDereferenceObject(ConnectMessage
->SectionToMap
);
166 /* Clear the reply message */
167 Thread
->LpcReplyMessage
= NULL
;
169 /* And remove the message from the port zone */
170 LpcpFreeToPortZone(Message
, TRUE
);
173 /* Release the semaphore and reset message id count */
174 Thread
->LpcReplyMessageId
= 0;
175 LpcpCompleteWait(&Thread
->LpcReplySemaphore
);
178 /* Reinitialize the list head */
179 InitializeListHead(&Port
->LpcReplyChainHead
);
181 /* Loop queued messages */
182 ListHead
= &Port
->MsgQueue
.ReceiveHead
;
183 NextEntry
= ListHead
->Flink
;
184 while (ListHead
!= NextEntry
)
186 /* Get the message */
187 Message
= CONTAINING_RECORD(NextEntry
, LPCP_MESSAGE
, Entry
);
188 NextEntry
= NextEntry
->Flink
;
190 /* Free and reinitialize it's list head */
191 InitializeListHead(&Message
->Entry
);
193 /* Remove it from the port zone */
194 LpcpFreeToPortZone(Message
, TRUE
);
197 /* Reinitialize the message queue list head */
198 InitializeListHead(&Port
->MsgQueue
.ReceiveHead
);
200 /* Release the lock */
201 KeReleaseGuardedMutex(&LpcpLock
);
203 /* Check if we have to free the port entirely */
206 /* Check if the semaphore exists */
207 if (Port
->MsgQueue
.Semaphore
)
209 /* Use the semaphore to find the port queue and free it */
210 ExFreePool(CONTAINING_RECORD(Port
->MsgQueue
.Semaphore
,
211 LPCP_NONPAGED_PORT_QUEUE
,
219 LpcpClosePort(IN PEPROCESS Process OPTIONAL
,
221 IN ACCESS_MASK GrantedAccess
,
222 IN ULONG ProcessHandleCount
,
223 IN ULONG SystemHandleCount
)
225 PLPCP_PORT_OBJECT Port
= (PLPCP_PORT_OBJECT
)Object
;
226 LPCTRACE(LPC_CLOSE_DEBUG
, "Port: %p. Flags: %lx\n", Port
, Port
->Flags
);
228 /* Only Server-side Connection Ports need clean up*/
229 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_CONNECTION_PORT
)
231 /* Check the handle count */
232 switch (SystemHandleCount
)
234 /* No handles left */
237 /* Destroy the port queue */
238 LpcpDestroyPortQueue(Port
, TRUE
);
241 /* Last handle remaining */
244 /* Reset the queue only */
245 LpcpDestroyPortQueue(Port
, FALSE
);
247 /* More handles remain, do nothing */
256 LpcpFreePortClientSecurity(IN PLPCP_PORT_OBJECT Port
)
258 /* Check if this is a client port */
259 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_CLIENT_PORT
)
261 /* Check if security is static */
262 if (!(Port
->Flags
& LPCP_SECURITY_DYNAMIC
))
264 /* Check if we have a token */
265 if (Port
->StaticSecurity
.ClientToken
)
268 SeDeleteClientSecurity(&Port
->StaticSecurity
);
276 LpcpDeletePort(IN PVOID ObjectBody
)
278 LARGE_INTEGER Timeout
;
280 PLPCP_PORT_OBJECT Port
= (PLPCP_PORT_OBJECT
)ObjectBody
;
281 PLPCP_PORT_OBJECT ConnectionPort
;
282 PLPCP_MESSAGE Message
;
283 PLIST_ENTRY ListHead
, NextEntry
;
285 CLIENT_DIED_MSG ClientDiedMsg
;
286 Timeout
.QuadPart
= -1000000;
288 LPCTRACE(LPC_CLOSE_DEBUG
, "Port: %p. Flags: %lx\n", Port
, Port
->Flags
);
290 /* Check if this is a communication port */
291 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_COMMUNICATION_PORT
)
293 /* Acquire the lock */
294 KeAcquireGuardedMutex(&LpcpLock
);
297 Thread
= Port
->ClientThread
;
301 Port
->ClientThread
= NULL
;
303 /* Release the lock and dereference */
304 KeReleaseGuardedMutex(&LpcpLock
);
305 ObDereferenceObject(Thread
);
309 /* Release the lock */
310 KeReleaseGuardedMutex(&LpcpLock
);
314 /* Check if this is a client-side port */
315 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_CLIENT_PORT
)
317 /* Setup the client died message */
318 ClientDiedMsg
.h
.u1
.s1
.TotalLength
= sizeof(ClientDiedMsg
);
319 ClientDiedMsg
.h
.u1
.s1
.DataLength
= sizeof(ClientDiedMsg
.CreateTime
);
320 ClientDiedMsg
.h
.u2
.ZeroInit
= LPC_PORT_CLOSED
;
321 ClientDiedMsg
.CreateTime
= PsGetCurrentProcess()->CreateTime
;
326 /* Send the message */
327 if (LpcRequestPort(Port
,
328 &ClientDiedMsg
.h
) != STATUS_NO_MEMORY
) break;
330 /* Wait until trying again */
331 KeDelayExecutionThread(KernelMode
, FALSE
, &Timeout
);
335 /* Destroy the port queue */
336 LpcpDestroyPortQueue(Port
, TRUE
);
338 /* Check if we had a client view */
339 if (Port
->ClientSectionBase
) MmUnmapViewOfSection(PsGetCurrentProcess(),
340 Port
->ClientSectionBase
);
342 /* Check for a server view */
343 if (Port
->ServerSectionBase
) MmUnmapViewOfSection(PsGetCurrentProcess(),
344 Port
->ServerSectionBase
);
346 /* Get the connection port */
347 ConnectionPort
= Port
->ConnectionPort
;
351 Pid
= PsGetCurrentProcessId();
353 /* Acquire the lock */
354 KeAcquireGuardedMutex(&LpcpLock
);
356 /* Loop the data lists */
357 ListHead
= &ConnectionPort
->LpcDataInfoChainHead
;
358 NextEntry
= ListHead
->Flink
;
359 while (NextEntry
!= ListHead
)
361 /* Get the message */
362 Message
= CONTAINING_RECORD(NextEntry
, LPCP_MESSAGE
, Entry
);
363 NextEntry
= NextEntry
->Flink
;
365 /* Check if the PID matches */
366 if (Message
->Request
.ClientId
.UniqueProcess
== Pid
)
369 RemoveEntryList(&Message
->Entry
);
370 LpcpFreeToPortZone(Message
, TRUE
);
374 /* Release the lock */
375 KeReleaseGuardedMutex(&LpcpLock
);
377 /* Dereference the object unless it's the same port */
378 if (ConnectionPort
!= Port
) ObDereferenceObject(ConnectionPort
);
381 /* Check if this is a connection port with a server process*/
382 if (((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_CONNECTION_PORT
) &&
383 (ConnectionPort
->ServerProcess
))
385 /* Dereference the server process */
386 ObDereferenceObject(ConnectionPort
->ServerProcess
);
387 ConnectionPort
->ServerProcess
= NULL
;
390 /* Free client security */
391 LpcpFreePortClientSecurity(Port
);
392 LPCTRACE(LPC_CLOSE_DEBUG
, "Port: %p deleted\n", Port
);