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
= Flags
& 1, ReleaseLock
= Flags
& 2;
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
) && !(ReleaseLock
)) KeAcquireGuardedMutex(&LpcpLock
);
108 LpcpDestroyPortQueue(IN PLPCP_PORT_OBJECT Port
,
111 PLIST_ENTRY ListHead
, NextEntry
;
113 PLPCP_MESSAGE Message
;
114 PLPCP_PORT_OBJECT ConnectionPort
= NULL
;
115 PLPCP_CONNECTION_MESSAGE ConnectMessage
;
117 LPCTRACE(LPC_CLOSE_DEBUG
, "Port: %p. Flags: %lx\n", Port
, Port
->Flags
);
120 KeAcquireGuardedMutex(&LpcpLock
);
122 /* Check if we have a connected port */
123 if (((Port
->Flags
& LPCP_PORT_TYPE_MASK
) != LPCP_UNCONNECTED_PORT
) &&
124 (Port
->ConnectedPort
))
127 Port
->ConnectedPort
->ConnectedPort
= NULL
;
128 ConnectionPort
= Port
->ConnectedPort
->ConnectionPort
;
131 /* Clear connection port */
132 Port
->ConnectedPort
->ConnectionPort
= NULL
;
136 /* Check if this is a connection port */
137 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_CONNECTION_PORT
)
139 /* Delete the name */
140 Port
->Flags
|= LPCP_NAME_DELETED
;
143 /* Walk all the threads waiting and signal them */
144 ListHead
= &Port
->LpcReplyChainHead
;
145 NextEntry
= ListHead
->Flink
;
146 while ((NextEntry
) && (NextEntry
!= ListHead
))
149 Thread
= CONTAINING_RECORD(NextEntry
, ETHREAD
, LpcReplyChain
);
151 /* Make sure we're not in exit */
152 if (Thread
->LpcExitThreadCalled
) break;
154 /* Move to the next entry */
155 NextEntry
= NextEntry
->Flink
;
157 /* Remove and reinitialize the List */
158 RemoveEntryList(&Thread
->LpcReplyChain
);
159 InitializeListHead(&Thread
->LpcReplyChain
);
161 /* Check if someone is waiting */
162 if (!KeReadStateSemaphore(&Thread
->LpcReplySemaphore
))
164 /* Get the message */
165 Message
= LpcpGetMessageFromThread(Thread
);
168 /* Check if it's a connection request */
169 if (Message
->Request
.u2
.s2
.Type
== LPC_CONNECTION_REQUEST
)
171 /* Get the connection message */
172 ConnectMessage
= (PLPCP_CONNECTION_MESSAGE
)(Message
+ 1);
174 /* Check if it had a section */
175 if (ConnectMessage
->SectionToMap
)
178 ObDereferenceObject(ConnectMessage
->SectionToMap
);
182 /* Clear the reply message */
183 Thread
->LpcReplyMessage
= NULL
;
185 /* And remove the message from the port zone */
186 LpcpFreeToPortZone(Message
, 1);
187 NextEntry
= Port
->LpcReplyChainHead
.Flink
;
190 /* Release the semaphore and reset message id count */
191 Thread
->LpcReplyMessageId
= 0;
192 KeReleaseSemaphore(&Thread
->LpcReplySemaphore
, 0, 1, FALSE
);
196 /* Reinitialize the list head */
197 InitializeListHead(&Port
->LpcReplyChainHead
);
199 /* Loop queued messages */
200 while ((Port
->MsgQueue
.ReceiveHead
.Flink
) &&
201 !(IsListEmpty(&Port
->MsgQueue
.ReceiveHead
)))
203 /* Get the message */
204 Message
= CONTAINING_RECORD(Port
->MsgQueue
.ReceiveHead
.Flink
,
208 /* Free and reinitialize it's list head */
209 RemoveEntryList(&Message
->Entry
);
210 InitializeListHead(&Message
->Entry
);
212 /* Remove it from the port zone */
213 LpcpFreeToPortZone(Message
, 1);
216 /* Release the lock */
217 KeReleaseGuardedMutex(&LpcpLock
);
219 /* Dereference the connection port */
220 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
222 /* Check if we have to free the port entirely */
225 /* Check if the semaphore exists */
226 if (Port
->MsgQueue
.Semaphore
)
228 /* Use the semaphore to find the port queue and free it */
229 ExFreePool(CONTAINING_RECORD(Port
->MsgQueue
.Semaphore
,
230 LPCP_NONPAGED_PORT_QUEUE
,
238 LpcpClosePort(IN PEPROCESS Process OPTIONAL
,
240 IN ACCESS_MASK GrantedAccess
,
241 IN ULONG ProcessHandleCount
,
242 IN ULONG SystemHandleCount
)
244 PLPCP_PORT_OBJECT Port
= (PLPCP_PORT_OBJECT
)Object
;
245 LPCTRACE(LPC_CLOSE_DEBUG
, "Port: %p. Flags: %lx\n", Port
, Port
->Flags
);
247 /* Only Server-side Connection Ports need clean up*/
248 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_CONNECTION_PORT
)
250 /* Check the handle count */
251 switch (SystemHandleCount
)
253 /* No handles left */
256 /* Destroy the port queue */
257 LpcpDestroyPortQueue(Port
, TRUE
);
260 /* Last handle remaining */
263 /* Reset the queue only */
264 LpcpDestroyPortQueue(Port
, FALSE
);
266 /* More handles remain, do nothing */
275 LpcpFreePortClientSecurity(IN PLPCP_PORT_OBJECT Port
)
277 /* Check if this is a client port */
278 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_CLIENT_PORT
)
280 /* Check if security is static */
281 if (!(Port
->Flags
& LPCP_SECURITY_DYNAMIC
))
283 /* Check if we have a token */
284 if (Port
->StaticSecurity
.ClientToken
)
287 SeDeleteClientSecurity(&Port
->StaticSecurity
);
295 LpcpDeletePort(IN PVOID ObjectBody
)
297 LARGE_INTEGER Timeout
;
299 PLPCP_PORT_OBJECT Port
= (PLPCP_PORT_OBJECT
)ObjectBody
;
300 PLPCP_PORT_OBJECT ConnectionPort
;
301 PLPCP_MESSAGE Message
;
302 PLIST_ENTRY ListHead
, NextEntry
;
304 CLIENT_DIED_MSG ClientDiedMsg
;
305 Timeout
.QuadPart
= -1000000;
307 LPCTRACE(LPC_CLOSE_DEBUG
, "Port: %p. Flags: %lx\n", Port
, Port
->Flags
);
309 /* Check if this is a communication port */
310 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_COMMUNICATION_PORT
)
312 /* Acquire the lock */
313 KeAcquireGuardedMutex(&LpcpLock
);
316 Thread
= Port
->ClientThread
;
320 Port
->ClientThread
= NULL
;
322 /* Release the lock and dereference */
323 KeReleaseGuardedMutex(&LpcpLock
);
324 ObDereferenceObject(Thread
);
328 /* Release the lock */
329 KeReleaseGuardedMutex(&LpcpLock
);
333 /* Check if this is a client-side port */
334 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_CLIENT_PORT
)
336 /* Setup the client died message */
337 ClientDiedMsg
.h
.u1
.s1
.TotalLength
= sizeof(ClientDiedMsg
);
338 ClientDiedMsg
.h
.u1
.s1
.DataLength
= sizeof(ClientDiedMsg
.CreateTime
);
339 ClientDiedMsg
.h
.u2
.ZeroInit
= 0;
340 ClientDiedMsg
.h
.u2
.s2
.Type
= LPC_PORT_CLOSED
;
341 ClientDiedMsg
.CreateTime
= PsGetCurrentProcess()->CreateTime
;
346 /* Send the message */
347 if (LpcRequestPort(Port
,
348 &ClientDiedMsg
.h
) != STATUS_NO_MEMORY
) break;
350 /* Wait until trying again */
351 KeDelayExecutionThread(KernelMode
, FALSE
, &Timeout
);
355 /* Destroy the port queue */
356 LpcpDestroyPortQueue(Port
, TRUE
);
358 /* Check if we had views */
359 if ((Port
->ClientSectionBase
) || (Port
->ServerSectionBase
))
361 /* Check if we had a client view */
362 if (Port
->ClientSectionBase
)
365 MmUnmapViewOfSection(Port
->MappingProcess
,
366 Port
->ClientSectionBase
);
369 /* Check for a server view */
370 if (Port
->ServerSectionBase
)
373 MmUnmapViewOfSection(Port
->MappingProcess
,
374 Port
->ServerSectionBase
);
377 /* Dereference the mapping process */
378 ObDereferenceObject(Port
->MappingProcess
);
379 Port
->MappingProcess
= NULL
;
382 /* Acquire the lock */
383 KeAcquireGuardedMutex(&LpcpLock
);
385 /* Get the connection port */
386 ConnectionPort
= Port
->ConnectionPort
;
390 Pid
= PsGetCurrentProcessId();
392 /* Loop the data lists */
393 ListHead
= &ConnectionPort
->LpcDataInfoChainHead
;
394 NextEntry
= ListHead
->Flink
;
395 while (NextEntry
!= ListHead
)
397 /* Get the message */
398 Message
= CONTAINING_RECORD(NextEntry
, LPCP_MESSAGE
, Entry
);
399 NextEntry
= NextEntry
->Flink
;
401 /* Check if this is the connection port */
402 if (Port
== ConnectionPort
)
404 /* Free queued messages */
405 RemoveEntryList(&Message
->Entry
);
406 InitializeListHead(&Message
->Entry
);
407 LpcpFreeToPortZone(Message
, 1);
409 /* Restart at the head */
410 NextEntry
= ListHead
->Flink
;
412 else if ((Message
->Request
.ClientId
.UniqueProcess
== Pid
) &&
413 ((Message
->SenderPort
== Port
) ||
414 (Message
->SenderPort
== Port
->ConnectedPort
) ||
415 (Message
->SenderPort
== ConnectionPort
)))
418 RemoveEntryList(&Message
->Entry
);
419 InitializeListHead(&Message
->Entry
);
420 LpcpFreeToPortZone(Message
, 1);
422 /* Restart at the head */
423 NextEntry
= ListHead
->Flink
;
427 /* Release the lock */
428 KeReleaseGuardedMutex(&LpcpLock
);
430 /* Dereference the object unless it's the same port */
431 if (ConnectionPort
!= Port
) ObDereferenceObject(ConnectionPort
);
435 /* Release the lock */
436 KeReleaseGuardedMutex(&LpcpLock
);
439 /* Check if this is a connection port with a server process*/
440 if (((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_CONNECTION_PORT
) &&
441 (ConnectionPort
->ServerProcess
))
443 /* Dereference the server process */
444 ObDereferenceObject(ConnectionPort
->ServerProcess
);
445 ConnectionPort
->ServerProcess
= NULL
;
448 /* Free client security */
449 LpcpFreePortClientSecurity(Port
);
450 LPCTRACE(LPC_CLOSE_DEBUG
, "Port: %p deleted\n", Port
);