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
;
119 PLPCP_NONPAGED_PORT_QUEUE MessageQueue
;
122 LPCTRACE(LPC_CLOSE_DEBUG
, "Port: %p. Flags: %lx\n", Port
, Port
->Flags
);
125 KeAcquireGuardedMutex(&LpcpLock
);
127 /* Check if we have a connected port */
128 if (((Port
->Flags
& LPCP_PORT_TYPE_MASK
) != LPCP_UNCONNECTED_PORT
) &&
129 (Port
->ConnectedPort
))
132 Port
->ConnectedPort
->ConnectedPort
= NULL
;
133 ConnectionPort
= Port
->ConnectedPort
->ConnectionPort
;
136 /* Clear connection port */
137 Port
->ConnectedPort
->ConnectionPort
= NULL
;
141 /* Check if this is a connection port */
142 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_CONNECTION_PORT
)
144 /* Delete the name */
145 Port
->Flags
|= LPCP_NAME_DELETED
;
148 /* Walk all the threads waiting and signal them */
149 ListHead
= &Port
->LpcReplyChainHead
;
150 NextEntry
= ListHead
->Flink
;
151 while ((NextEntry
) && (NextEntry
!= ListHead
))
154 Thread
= CONTAINING_RECORD(NextEntry
, ETHREAD
, LpcReplyChain
);
156 /* Make sure we're not in exit */
157 if (Thread
->LpcExitThreadCalled
) break;
159 /* Move to the next entry */
160 NextEntry
= NextEntry
->Flink
;
162 /* Remove and reinitialize the List */
163 RemoveEntryList(&Thread
->LpcReplyChain
);
164 InitializeListHead(&Thread
->LpcReplyChain
);
166 /* Check if someone is waiting */
167 if (!KeReadStateSemaphore(&Thread
->LpcReplySemaphore
))
169 /* Get the message */
170 Message
= LpcpGetMessageFromThread(Thread
);
173 /* Check if it's a connection request */
174 if (Message
->Request
.u2
.s2
.Type
== LPC_CONNECTION_REQUEST
)
176 /* Get the connection message */
177 ConnectMessage
= (PLPCP_CONNECTION_MESSAGE
)(Message
+ 1);
179 /* Check if it had a section */
180 if (ConnectMessage
->SectionToMap
)
183 ObDereferenceObject(ConnectMessage
->SectionToMap
);
187 /* Clear the reply message */
188 Thread
->LpcReplyMessage
= NULL
;
190 /* And remove the message from the port zone */
191 LpcpFreeToPortZone(Message
, LPCP_LOCK_HELD
);
192 NextEntry
= Port
->LpcReplyChainHead
.Flink
;
195 /* Release the semaphore and reset message id count */
196 Thread
->LpcReplyMessageId
= 0;
197 KeReleaseSemaphore(&Thread
->LpcReplySemaphore
, 0, 1, FALSE
);
201 /* Reinitialize the list head */
202 InitializeListHead(&Port
->LpcReplyChainHead
);
204 /* Loop queued messages */
205 while ((Port
->MsgQueue
.ReceiveHead
.Flink
) &&
206 !(IsListEmpty(&Port
->MsgQueue
.ReceiveHead
)))
208 /* Get the message */
209 Message
= CONTAINING_RECORD(Port
->MsgQueue
.ReceiveHead
.Flink
,
213 /* Free and reinitialize it's list head */
214 RemoveEntryList(&Message
->Entry
);
215 InitializeListHead(&Message
->Entry
);
217 /* Remove it from the port zone */
218 LpcpFreeToPortZone(Message
, LPCP_LOCK_HELD
);
221 /* Release the lock */
222 KeReleaseGuardedMutex(&LpcpLock
);
224 /* Dereference the connection port */
225 if (ConnectionPort
) ObDereferenceObject(ConnectionPort
);
227 /* Check if we have to free the port entirely */
230 /* Check if the semaphore exists */
231 if (Port
->MsgQueue
.Semaphore
)
233 /* Use the semaphore to find the port queue and free it */
234 MessageQueue
= CONTAINING_RECORD(Port
->MsgQueue
.Semaphore
,
235 LPCP_NONPAGED_PORT_QUEUE
,
237 ExFreePoolWithTag(MessageQueue
, 'troP');
244 LpcpClosePort(IN PEPROCESS Process OPTIONAL
,
246 IN ACCESS_MASK GrantedAccess
,
247 IN ULONG ProcessHandleCount
,
248 IN ULONG SystemHandleCount
)
250 PLPCP_PORT_OBJECT Port
= (PLPCP_PORT_OBJECT
)Object
;
252 LPCTRACE(LPC_CLOSE_DEBUG
, "Port: %p. Flags: %lx\n", Port
, Port
->Flags
);
254 /* Only Server-side Connection Ports need clean up*/
255 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_CONNECTION_PORT
)
257 /* Check the handle count */
258 switch (SystemHandleCount
)
260 /* No handles left */
263 /* Destroy the port queue */
264 LpcpDestroyPortQueue(Port
, TRUE
);
267 /* Last handle remaining */
270 /* Reset the queue only */
271 LpcpDestroyPortQueue(Port
, FALSE
);
273 /* More handles remain, do nothing */
282 LpcpFreePortClientSecurity(IN PLPCP_PORT_OBJECT Port
)
284 /* Check if this is a client port */
285 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_CLIENT_PORT
)
287 /* Check if security is static */
288 if (!(Port
->Flags
& LPCP_SECURITY_DYNAMIC
))
290 /* Check if we have a token */
291 if (Port
->StaticSecurity
.ClientToken
)
294 SeDeleteClientSecurity(&Port
->StaticSecurity
);
302 LpcpDeletePort(IN PVOID ObjectBody
)
304 LARGE_INTEGER Timeout
;
306 PLPCP_PORT_OBJECT Port
= (PLPCP_PORT_OBJECT
)ObjectBody
;
307 PLPCP_PORT_OBJECT ConnectionPort
;
308 PLPCP_MESSAGE Message
;
309 PLIST_ENTRY ListHead
, NextEntry
;
311 CLIENT_DIED_MSG ClientDiedMsg
;
314 LPCTRACE(LPC_CLOSE_DEBUG
, "Port: %p. Flags: %lx\n", Port
, Port
->Flags
);
316 Timeout
.QuadPart
= -1000000;
318 /* Check if this is a communication port */
319 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_COMMUNICATION_PORT
)
321 /* Acquire the lock */
322 KeAcquireGuardedMutex(&LpcpLock
);
325 Thread
= Port
->ClientThread
;
329 Port
->ClientThread
= NULL
;
331 /* Release the lock and dereference */
332 KeReleaseGuardedMutex(&LpcpLock
);
333 ObDereferenceObject(Thread
);
337 /* Release the lock */
338 KeReleaseGuardedMutex(&LpcpLock
);
342 /* Check if this is a client-side port */
343 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_CLIENT_PORT
)
345 /* Setup the client died message */
346 ClientDiedMsg
.h
.u1
.s1
.TotalLength
= sizeof(ClientDiedMsg
);
347 ClientDiedMsg
.h
.u1
.s1
.DataLength
= sizeof(ClientDiedMsg
.CreateTime
);
348 ClientDiedMsg
.h
.u2
.ZeroInit
= 0;
349 ClientDiedMsg
.h
.u2
.s2
.Type
= LPC_PORT_CLOSED
;
350 ClientDiedMsg
.CreateTime
= PsGetCurrentProcess()->CreateTime
;
355 /* Send the message */
356 if (LpcRequestPort(Port
, &ClientDiedMsg
.h
) != STATUS_NO_MEMORY
)
359 /* Wait until trying again */
360 KeDelayExecutionThread(KernelMode
, FALSE
, &Timeout
);
364 /* Destroy the port queue */
365 LpcpDestroyPortQueue(Port
, TRUE
);
367 /* Check if we had views */
368 if ((Port
->ClientSectionBase
) || (Port
->ServerSectionBase
))
370 /* Check if we had a client view */
371 if (Port
->ClientSectionBase
)
374 MmUnmapViewOfSection(Port
->MappingProcess
,
375 Port
->ClientSectionBase
);
378 /* Check for a server view */
379 if (Port
->ServerSectionBase
)
382 MmUnmapViewOfSection(Port
->MappingProcess
,
383 Port
->ServerSectionBase
);
386 /* Dereference the mapping process */
387 ObDereferenceObject(Port
->MappingProcess
);
388 Port
->MappingProcess
= NULL
;
391 /* Acquire the lock */
392 KeAcquireGuardedMutex(&LpcpLock
);
394 /* Get the connection port */
395 ConnectionPort
= Port
->ConnectionPort
;
399 Pid
= PsGetCurrentProcessId();
401 /* Loop the data lists */
402 ListHead
= &ConnectionPort
->LpcDataInfoChainHead
;
403 NextEntry
= ListHead
->Flink
;
404 while (NextEntry
!= ListHead
)
406 /* Get the message */
407 Message
= CONTAINING_RECORD(NextEntry
, LPCP_MESSAGE
, Entry
);
408 NextEntry
= NextEntry
->Flink
;
410 /* Check if this is the connection port */
411 if (Port
== ConnectionPort
)
413 /* Free queued messages */
414 RemoveEntryList(&Message
->Entry
);
415 InitializeListHead(&Message
->Entry
);
416 LpcpFreeToPortZone(Message
, LPCP_LOCK_HELD
);
418 /* Restart at the head */
419 NextEntry
= ListHead
->Flink
;
421 else if ((Message
->Request
.ClientId
.UniqueProcess
== Pid
) &&
422 ((Message
->SenderPort
== Port
) ||
423 (Message
->SenderPort
== Port
->ConnectedPort
) ||
424 (Message
->SenderPort
== ConnectionPort
)))
427 RemoveEntryList(&Message
->Entry
);
428 InitializeListHead(&Message
->Entry
);
429 LpcpFreeToPortZone(Message
, LPCP_LOCK_HELD
);
431 /* Restart at the head */
432 NextEntry
= ListHead
->Flink
;
436 /* Release the lock */
437 KeReleaseGuardedMutex(&LpcpLock
);
439 /* Dereference the object unless it's the same port */
440 if (ConnectionPort
!= Port
) ObDereferenceObject(ConnectionPort
);
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
;
453 /* Release the lock */
454 KeReleaseGuardedMutex(&LpcpLock
);
457 /* Free client security */
458 LpcpFreePortClientSecurity(Port
);
459 LPCTRACE(LPC_CLOSE_DEBUG
, "Port: %p deleted\n", Port
);