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 ******************************************************************/
15 /* PRIVATE FUNCTIONS *********************************************************/
19 LpcExitThread(IN PETHREAD Thread
)
21 PLPCP_MESSAGE Message
;
23 /* Acquire the lock */
24 KeAcquireGuardedMutex(&LpcpLock
);
26 /* Make sure that the Reply Chain is empty */
27 if (!IsListEmpty(&Thread
->LpcReplyChain
))
29 /* It's not, remove the entry */
30 RemoveEntryList(&Thread
->LpcReplyChain
);
33 /* Set the thread in exit mode */
34 Thread
->LpcExitThreadCalled
= TRUE
;
35 Thread
->LpcReplyMessageId
= 0;
37 /* Check if there's a reply message */
38 Message
= Thread
->LpcReplyMessage
;
45 /* Release the lock */
46 KeReleaseGuardedMutex(&LpcpLock
);
51 LpcpFreeToPortZone(IN PLPCP_MESSAGE Message
,
54 PLPCP_CONNECTION_MESSAGE ConnectMessage
;
55 PLPCP_PORT_OBJECT ClientPort
= NULL
;
56 PETHREAD Thread
= NULL
;
57 BOOLEAN LockHeld
= Flags
& 1;
59 LPCTRACE(LPC_CLOSE_DEBUG
, "Message: %p. Flags: %lx\n", Message
, Flags
);
61 /* Acquire the lock if not already */
62 if (!LockHeld
) KeAcquireGuardedMutex(&LpcpLock
);
64 /* Check if the queue list is empty */
65 if (!IsListEmpty(&Message
->Entry
))
67 /* Remove and re-initialize */
68 RemoveEntryList(&Message
->Entry
);
69 InitializeListHead(&Message
->Entry
);
72 /* Check if we've already replied */
73 if (Message
->RepliedToThread
)
75 /* Set thread to dereference and clean up */
76 Thread
= Message
->RepliedToThread
;
77 Message
->RepliedToThread
= NULL
;
80 /* Check if this is a connection request */
81 if (Message
->Request
.u2
.s2
.Type
== LPC_CONNECTION_REQUEST
)
83 /* Get the connection message */
84 ConnectMessage
= (PLPCP_CONNECTION_MESSAGE
)(Message
+ 1);
86 /* Clear the client port */
87 ClientPort
= ConnectMessage
->ClientPort
;
88 if (ClientPort
) ConnectMessage
->ClientPort
= NULL
;
91 /* Release the lock */
92 KeReleaseGuardedMutex(&LpcpLock
);
94 /* Check if we had anything to dereference */
95 if (Thread
) ObDereferenceObject(Thread
);
96 if (ClientPort
) ObDereferenceObject(ClientPort
);
99 ExFreeToPagedLookasideList(&LpcpMessagesLookaside
, Message
);
101 /* Reacquire the lock if needed */
102 if ((LockHeld
) && !(Flags
& 2)) KeAcquireGuardedMutex(&LpcpLock
);
107 LpcpDestroyPortQueue(IN PLPCP_PORT_OBJECT Port
,
110 PLIST_ENTRY ListHead
, NextEntry
;
112 PLPCP_MESSAGE Message
;
113 PLPCP_CONNECTION_MESSAGE ConnectMessage
;
114 LPCTRACE(LPC_CLOSE_DEBUG
, "Port: %p. Flags: %lx\n", Port
, Port
->Flags
);
117 KeAcquireGuardedMutex(&LpcpLock
);
119 /* Disconnect the port to which this port is connected */
120 if (Port
->ConnectedPort
) Port
->ConnectedPort
->ConnectedPort
= NULL
;
122 /* Check if this is a connection port */
123 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_CONNECTION_PORT
)
125 /* Delete the name */
126 Port
->Flags
|= LPCP_NAME_DELETED
;
129 /* Walk all the threads waiting and signal them */
130 ListHead
= &Port
->LpcReplyChainHead
;
131 NextEntry
= ListHead
->Flink
;
132 while (NextEntry
!= ListHead
)
135 Thread
= CONTAINING_RECORD(NextEntry
, ETHREAD
, LpcReplyChain
);
137 /* Make sure we're not in exit */
138 if (Thread
->LpcExitThreadCalled
) break;
140 /* Move to the next entry */
141 NextEntry
= NextEntry
->Flink
;
143 /* Remove and reinitialize the List */
144 RemoveEntryList(&Thread
->LpcReplyChain
);
145 InitializeListHead(&Thread
->LpcReplyChain
);
147 /* Check if someone is waiting */
148 if (!KeReadStateSemaphore(&Thread
->LpcReplySemaphore
))
150 /* Get the message and check if it's a connection request */
151 Message
= Thread
->LpcReplyMessage
;
152 if (Message
->Request
.u2
.s2
.Type
== LPC_CONNECTION_REQUEST
)
154 /* Get the connection message */
155 ConnectMessage
= (PLPCP_CONNECTION_MESSAGE
)(Message
+ 1);
157 /* Check if it had a section */
158 if (ConnectMessage
->SectionToMap
)
161 ObDereferenceObject(ConnectMessage
->SectionToMap
);
165 /* Clear the reply message */
166 Thread
->LpcReplyMessage
= NULL
;
168 /* And remove the message from the port zone */
169 LpcpFreeToPortZone(Message
, TRUE
);
172 /* Release the semaphore and reset message id count */
173 Thread
->LpcReplyMessageId
= 0;
174 LpcpCompleteWait(&Thread
->LpcReplySemaphore
);
177 /* Reinitialize the list head */
178 InitializeListHead(&Port
->LpcReplyChainHead
);
180 /* Loop queued messages */
181 ListHead
= &Port
->MsgQueue
.ReceiveHead
;
182 NextEntry
= ListHead
->Flink
;
183 while (ListHead
!= NextEntry
)
185 /* Get the message */
186 Message
= CONTAINING_RECORD(NextEntry
, LPCP_MESSAGE
, Entry
);
187 NextEntry
= NextEntry
->Flink
;
189 /* Free and reinitialize it's list head */
190 InitializeListHead(&Message
->Entry
);
192 /* Remove it from the port zone */
193 LpcpFreeToPortZone(Message
, TRUE
);
196 /* Reinitialize the message queue list head */
197 InitializeListHead(&Port
->MsgQueue
.ReceiveHead
);
199 /* Release the lock */
200 KeReleaseGuardedMutex(&LpcpLock
);
202 /* Check if we have to free the port entirely */
205 /* Check if the semaphore exists */
206 if (Port
->MsgQueue
.Semaphore
)
208 /* Use the semaphore to find the port queue and free it */
209 ExFreePool(CONTAINING_RECORD(Port
->MsgQueue
.Semaphore
,
210 LPCP_NONPAGED_PORT_QUEUE
,
218 LpcpClosePort(IN PEPROCESS Process OPTIONAL
,
220 IN ACCESS_MASK GrantedAccess
,
221 IN ULONG ProcessHandleCount
,
222 IN ULONG SystemHandleCount
)
224 PLPCP_PORT_OBJECT Port
= (PLPCP_PORT_OBJECT
)Object
;
225 LPCTRACE(LPC_CLOSE_DEBUG
, "Port: %p. Flags: %lx\n", Port
, Port
->Flags
);
227 /* Only Server-side Connection Ports need clean up*/
228 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_CONNECTION_PORT
)
230 /* Check the handle count */
231 switch (SystemHandleCount
)
233 /* No handles left */
236 /* Destroy the port queue */
237 LpcpDestroyPortQueue(Port
, TRUE
);
240 /* Last handle remaining */
243 /* Reset the queue only */
244 LpcpDestroyPortQueue(Port
, FALSE
);
246 /* More handles remain, do nothing */
255 LpcpFreePortClientSecurity(IN PLPCP_PORT_OBJECT Port
)
257 /* Check if this is a client port */
258 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_CLIENT_PORT
)
260 /* Check if security is static */
261 if (!(Port
->Flags
& LPCP_SECURITY_DYNAMIC
))
263 /* Check if we have a token */
264 if (Port
->StaticSecurity
.ClientToken
)
267 SeDeleteClientSecurity(&Port
->StaticSecurity
);
275 LpcpDeletePort(IN PVOID ObjectBody
)
277 LARGE_INTEGER Timeout
;
279 PLPCP_PORT_OBJECT Port
= (PLPCP_PORT_OBJECT
)ObjectBody
;
280 PLPCP_PORT_OBJECT ConnectionPort
;
281 PLPCP_MESSAGE Message
;
282 PLIST_ENTRY ListHead
, NextEntry
;
284 CLIENT_DIED_MSG ClientDiedMsg
;
285 Timeout
.QuadPart
= -1000000;
287 LPCTRACE(LPC_CLOSE_DEBUG
, "Port: %p. Flags: %lx\n", Port
, Port
->Flags
);
289 /* Check if this is a communication port */
290 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_COMMUNICATION_PORT
)
292 /* Acquire the lock */
293 KeAcquireGuardedMutex(&LpcpLock
);
296 Thread
= Port
->ClientThread
;
300 Port
->ClientThread
= NULL
;
302 /* Release the lock and dereference */
303 KeReleaseGuardedMutex(&LpcpLock
);
304 ObDereferenceObject(Thread
);
308 /* Release the lock */
309 KeReleaseGuardedMutex(&LpcpLock
);
313 /* Check if this is a client-side port */
314 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_CLIENT_PORT
)
316 /* Setup the client died message */
317 ClientDiedMsg
.h
.u1
.s1
.TotalLength
= sizeof(ClientDiedMsg
);
318 ClientDiedMsg
.h
.u1
.s1
.DataLength
= sizeof(ClientDiedMsg
.CreateTime
);
319 ClientDiedMsg
.h
.u2
.ZeroInit
= LPC_PORT_CLOSED
;
320 ClientDiedMsg
.CreateTime
= PsGetCurrentProcess()->CreateTime
;
325 /* Send the message */
326 if (LpcRequestPort(Port
,
327 &ClientDiedMsg
.h
) != STATUS_NO_MEMORY
) break;
329 /* Wait until trying again */
330 KeDelayExecutionThread(KernelMode
, FALSE
, &Timeout
);
334 /* Destroy the port queue */
335 LpcpDestroyPortQueue(Port
, TRUE
);
337 /* Check if we had a client view */
338 if (Port
->ClientSectionBase
) MmUnmapViewOfSection(PsGetCurrentProcess(),
339 Port
->ClientSectionBase
);
341 /* Check for a server view */
342 if (Port
->ServerSectionBase
) MmUnmapViewOfSection(PsGetCurrentProcess(),
343 Port
->ServerSectionBase
);
345 /* Get the connection port */
346 ConnectionPort
= Port
->ConnectionPort
;
350 Pid
= PsGetCurrentProcessId();
352 /* Acquire the lock */
353 KeAcquireGuardedMutex(&LpcpLock
);
355 /* Loop the data lists */
356 ListHead
= &ConnectionPort
->LpcDataInfoChainHead
;
357 NextEntry
= ListHead
->Flink
;
358 while (NextEntry
!= ListHead
)
360 /* Get the message */
361 Message
= CONTAINING_RECORD(NextEntry
, LPCP_MESSAGE
, Entry
);
362 NextEntry
= NextEntry
->Flink
;
364 /* Check if the PID matches */
365 if (Message
->Request
.ClientId
.UniqueProcess
== Pid
)
368 RemoveEntryList(&Message
->Entry
);
369 LpcpFreeToPortZone(Message
, TRUE
);
373 /* Release the lock */
374 KeReleaseGuardedMutex(&LpcpLock
);
376 /* Dereference the object unless it's the same port */
377 if (ConnectionPort
!= Port
) ObDereferenceObject(ConnectionPort
);
380 /* Check if this is a connection port with a server process*/
381 if (((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_CONNECTION_PORT
) &&
382 (ConnectionPort
->ServerProcess
))
384 /* Dereference the server process */
385 ObDereferenceObject(ConnectionPort
->ServerProcess
);
386 ConnectionPort
->ServerProcess
= NULL
;
389 /* Free client security */
390 LpcpFreePortClientSecurity(Port
);
391 LPCTRACE(LPC_CLOSE_DEBUG
, "Port: %p deleted\n", Port
);