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
;
22 ASSERT(Thread
== PsGetCurrentThread());
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
= LpcpGetMessageFromThread(Thread
);
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
= (LockFlags
& LPCP_LOCK_HELD
);
59 BOOLEAN ReleaseLock
= (LockFlags
& LPCP_LOCK_RELEASE
);
63 LPCTRACE(LPC_CLOSE_DEBUG
, "Message: %p. LockFlags: %lx\n", Message
, LockFlags
);
65 /* Acquire the lock if not already */
66 if (!LockHeld
) KeAcquireGuardedMutex(&LpcpLock
);
68 /* Check if the queue list is empty */
69 if (!IsListEmpty(&Message
->Entry
))
71 /* Remove and re-initialize */
72 RemoveEntryList(&Message
->Entry
);
73 InitializeListHead(&Message
->Entry
);
76 /* Check if we've already replied */
77 if (Message
->RepliedToThread
)
79 /* Set thread to dereference and clean up */
80 Thread
= Message
->RepliedToThread
;
81 Message
->RepliedToThread
= NULL
;
84 /* Check if this is a connection request */
85 if (Message
->Request
.u2
.s2
.Type
== LPC_CONNECTION_REQUEST
)
87 /* Get the connection message */
88 ConnectMessage
= (PLPCP_CONNECTION_MESSAGE
)(Message
+ 1);
90 /* Clear the client port */
91 ClientPort
= ConnectMessage
->ClientPort
;
92 if (ClientPort
) ConnectMessage
->ClientPort
= NULL
;
95 /* Release the lock */
96 KeReleaseGuardedMutex(&LpcpLock
);
98 /* Check if we had anything to dereference */
99 if (Thread
) ObDereferenceObject(Thread
);
100 if (ClientPort
) ObDereferenceObject(ClientPort
);
103 ExFreeToPagedLookasideList(&LpcpMessagesLookaside
, Message
);
105 /* Reacquire the lock if needed */
106 if ((LockHeld
) && !(ReleaseLock
)) KeAcquireGuardedMutex(&LpcpLock
);
111 LpcpDestroyPortQueue(IN PLPCP_PORT_OBJECT Port
,
114 PLIST_ENTRY ListHead
, NextEntry
;
116 PLPCP_MESSAGE Message
;
117 PLPCP_PORT_OBJECT ConnectionPort
= NULL
;
118 PLPCP_CONNECTION_MESSAGE ConnectMessage
;
120 LPCTRACE(LPC_CLOSE_DEBUG
, "Port: %p. Flags: %lx\n", Port
, Port
->Flags
);
123 KeAcquireGuardedMutex(&LpcpLock
);
125 /* Check if we have a connected port */
126 if (((Port
->Flags
& LPCP_PORT_TYPE_MASK
) != LPCP_UNCONNECTED_PORT
) &&
127 (Port
->ConnectedPort
))
130 Port
->ConnectedPort
->ConnectedPort
= NULL
;
131 ConnectionPort
= Port
->ConnectedPort
->ConnectionPort
;
134 /* Clear connection port */
135 Port
->ConnectedPort
->ConnectionPort
= NULL
;
139 /* Check if this is a connection port */
140 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_CONNECTION_PORT
)
142 /* Delete the name */
143 Port
->Flags
|= LPCP_NAME_DELETED
;
146 /* Walk all the threads waiting and signal them */
147 ListHead
= &Port
->LpcReplyChainHead
;
148 NextEntry
= ListHead
->Flink
;
149 while ((NextEntry
) && (NextEntry
!= ListHead
))
152 Thread
= CONTAINING_RECORD(NextEntry
, ETHREAD
, LpcReplyChain
);
154 /* Make sure we're not in exit */
155 if (Thread
->LpcExitThreadCalled
) break;
157 /* Move to the next entry */
158 NextEntry
= NextEntry
->Flink
;
160 /* Remove and reinitialize the List */
161 RemoveEntryList(&Thread
->LpcReplyChain
);
162 InitializeListHead(&Thread
->LpcReplyChain
);
164 /* Check if someone is waiting */
165 if (!KeReadStateSemaphore(&Thread
->LpcReplySemaphore
))
167 /* Get the message */
168 Message
= LpcpGetMessageFromThread(Thread
);
171 /* Check if it's a connection request */
172 if (Message
->Request
.u2
.s2
.Type
== LPC_CONNECTION_REQUEST
)
174 /* Get the connection message */
175 ConnectMessage
= (PLPCP_CONNECTION_MESSAGE
)(Message
+ 1);
177 /* Check if it had a section */
178 if (ConnectMessage
->SectionToMap
)
181 ObDereferenceObject(ConnectMessage
->SectionToMap
);
185 /* Clear the reply message */
186 Thread
->LpcReplyMessage
= NULL
;
188 /* And remove the message from the port zone */
189 LpcpFreeToPortZone(Message
, LPCP_LOCK_HELD
);
190 NextEntry
= Port
->LpcReplyChainHead
.Flink
;
193 /* Release the semaphore and reset message id count */
194 Thread
->LpcReplyMessageId
= 0;
195 KeReleaseSemaphore(&Thread
->LpcReplySemaphore
, 0, 1, FALSE
);
199 /* Reinitialize the list head */
200 InitializeListHead(&Port
->LpcReplyChainHead
);
202 /* Loop queued messages */
203 while ((Port
->MsgQueue
.ReceiveHead
.Flink
) &&
204 !(IsListEmpty(&Port
->MsgQueue
.ReceiveHead
)))
206 /* Get the message */
207 Message
= CONTAINING_RECORD(Port
->MsgQueue
.ReceiveHead
.Flink
,
211 /* Free and reinitialize it's list head */
212 RemoveEntryList(&Message
->Entry
);
213 InitializeListHead(&Message
->Entry
);
215 /* Remove it from the port zone */
216 LpcpFreeToPortZone(Message
, LPCP_LOCK_HELD
);
219 /* Release the lock */
220 KeReleaseGuardedMutex(&LpcpLock
);
222 /* Dereference the connection port */
223 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
225 /* Check if we have to free the port entirely */
228 /* Check if the semaphore exists */
229 if (Port
->MsgQueue
.Semaphore
)
231 /* Use the semaphore to find the port queue and free it */
232 ExFreePool(CONTAINING_RECORD(Port
->MsgQueue
.Semaphore
,
233 LPCP_NONPAGED_PORT_QUEUE
,
241 LpcpClosePort(IN PEPROCESS Process OPTIONAL
,
243 IN ACCESS_MASK GrantedAccess
,
244 IN ULONG ProcessHandleCount
,
245 IN ULONG SystemHandleCount
)
247 PLPCP_PORT_OBJECT Port
= (PLPCP_PORT_OBJECT
)Object
;
248 LPCTRACE(LPC_CLOSE_DEBUG
, "Port: %p. Flags: %lx\n", Port
, Port
->Flags
);
250 /* Only Server-side Connection Ports need clean up*/
251 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_CONNECTION_PORT
)
253 /* Check the handle count */
254 switch (SystemHandleCount
)
256 /* No handles left */
259 /* Destroy the port queue */
260 LpcpDestroyPortQueue(Port
, TRUE
);
263 /* Last handle remaining */
266 /* Reset the queue only */
267 LpcpDestroyPortQueue(Port
, FALSE
);
269 /* More handles remain, do nothing */
278 LpcpFreePortClientSecurity(IN PLPCP_PORT_OBJECT Port
)
280 /* Check if this is a client port */
281 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_CLIENT_PORT
)
283 /* Check if security is static */
284 if (!(Port
->Flags
& LPCP_SECURITY_DYNAMIC
))
286 /* Check if we have a token */
287 if (Port
->StaticSecurity
.ClientToken
)
290 SeDeleteClientSecurity(&Port
->StaticSecurity
);
298 LpcpDeletePort(IN PVOID ObjectBody
)
300 LARGE_INTEGER Timeout
;
302 PLPCP_PORT_OBJECT Port
= (PLPCP_PORT_OBJECT
)ObjectBody
;
303 PLPCP_PORT_OBJECT ConnectionPort
;
304 PLPCP_MESSAGE Message
;
305 PLIST_ENTRY ListHead
, NextEntry
;
307 CLIENT_DIED_MSG ClientDiedMsg
;
308 Timeout
.QuadPart
= -1000000;
310 LPCTRACE(LPC_CLOSE_DEBUG
, "Port: %p. Flags: %lx\n", Port
, Port
->Flags
);
312 /* Check if this is a communication port */
313 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_COMMUNICATION_PORT
)
315 /* Acquire the lock */
316 KeAcquireGuardedMutex(&LpcpLock
);
319 Thread
= Port
->ClientThread
;
323 Port
->ClientThread
= NULL
;
325 /* Release the lock and dereference */
326 KeReleaseGuardedMutex(&LpcpLock
);
327 ObDereferenceObject(Thread
);
331 /* Release the lock */
332 KeReleaseGuardedMutex(&LpcpLock
);
336 /* Check if this is a client-side port */
337 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_CLIENT_PORT
)
339 /* Setup the client died message */
340 ClientDiedMsg
.h
.u1
.s1
.TotalLength
= sizeof(ClientDiedMsg
);
341 ClientDiedMsg
.h
.u1
.s1
.DataLength
= sizeof(ClientDiedMsg
.CreateTime
);
342 ClientDiedMsg
.h
.u2
.ZeroInit
= 0;
343 ClientDiedMsg
.h
.u2
.s2
.Type
= LPC_PORT_CLOSED
;
344 ClientDiedMsg
.CreateTime
= PsGetCurrentProcess()->CreateTime
;
349 /* Send the message */
350 if (LpcRequestPort(Port
,
351 &ClientDiedMsg
.h
) != STATUS_NO_MEMORY
) break;
353 /* Wait until trying again */
354 KeDelayExecutionThread(KernelMode
, FALSE
, &Timeout
);
358 /* Destroy the port queue */
359 LpcpDestroyPortQueue(Port
, TRUE
);
361 /* Check if we had views */
362 if ((Port
->ClientSectionBase
) || (Port
->ServerSectionBase
))
364 /* Check if we had a client view */
365 if (Port
->ClientSectionBase
)
368 MmUnmapViewOfSection(Port
->MappingProcess
,
369 Port
->ClientSectionBase
);
372 /* Check for a server view */
373 if (Port
->ServerSectionBase
)
376 MmUnmapViewOfSection(Port
->MappingProcess
,
377 Port
->ServerSectionBase
);
380 /* Dereference the mapping process */
381 ObDereferenceObject(Port
->MappingProcess
);
382 Port
->MappingProcess
= NULL
;
385 /* Acquire the lock */
386 KeAcquireGuardedMutex(&LpcpLock
);
388 /* Get the connection port */
389 ConnectionPort
= Port
->ConnectionPort
;
393 Pid
= PsGetCurrentProcessId();
395 /* Loop the data lists */
396 ListHead
= &ConnectionPort
->LpcDataInfoChainHead
;
397 NextEntry
= ListHead
->Flink
;
398 while (NextEntry
!= ListHead
)
400 /* Get the message */
401 Message
= CONTAINING_RECORD(NextEntry
, LPCP_MESSAGE
, Entry
);
402 NextEntry
= NextEntry
->Flink
;
404 /* Check if this is the connection port */
405 if (Port
== ConnectionPort
)
407 /* Free queued messages */
408 RemoveEntryList(&Message
->Entry
);
409 InitializeListHead(&Message
->Entry
);
410 LpcpFreeToPortZone(Message
, LPCP_LOCK_HELD
);
412 /* Restart at the head */
413 NextEntry
= ListHead
->Flink
;
415 else if ((Message
->Request
.ClientId
.UniqueProcess
== Pid
) &&
416 ((Message
->SenderPort
== Port
) ||
417 (Message
->SenderPort
== Port
->ConnectedPort
) ||
418 (Message
->SenderPort
== ConnectionPort
)))
421 RemoveEntryList(&Message
->Entry
);
422 InitializeListHead(&Message
->Entry
);
423 LpcpFreeToPortZone(Message
, LPCP_LOCK_HELD
);
425 /* Restart at the head */
426 NextEntry
= ListHead
->Flink
;
430 /* Release the lock */
431 KeReleaseGuardedMutex(&LpcpLock
);
433 /* Dereference the object unless it's the same port */
434 if (ConnectionPort
!= Port
) ObDereferenceObject(ConnectionPort
);
438 /* Release the lock */
439 KeReleaseGuardedMutex(&LpcpLock
);
442 /* Check if this is a connection port with a server process*/
443 if (((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_CONNECTION_PORT
) &&
444 (ConnectionPort
->ServerProcess
))
446 /* Dereference the server process */
447 ObDereferenceObject(ConnectionPort
->ServerProcess
);
448 ConnectionPort
->ServerProcess
= NULL
;
451 /* Free client security */
452 LpcpFreePortClientSecurity(Port
);
453 LPCTRACE(LPC_CLOSE_DEBUG
, "Port: %p deleted\n", Port
);