ReactOS  0.4.14-dev-614-gbfd8a84
close.c
Go to the documentation of this file.
1 /*
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)
7  */
8 
9 /* INCLUDES ******************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 /* PRIVATE FUNCTIONS *********************************************************/
16 
17 VOID
18 NTAPI
20 {
23 
24  /* Acquire the lock */
26 
27  /* Make sure that the Reply Chain is empty */
29  {
30  /* It's not, remove the entry */
32  }
33 
34  /* Set the thread in exit mode */
36  Thread->LpcReplyMessageId = 0;
37 
38  /* Check if there's a reply message */
40  if (Message)
41  {
42  /* FIXME: TODO */
43  ASSERT(FALSE);
44  }
45 
46  /* Release the lock */
48 }
49 
50 VOID
51 NTAPI
53  IN ULONG LockFlags)
54 {
55  PLPCP_CONNECTION_MESSAGE ConnectMessage;
58  BOOLEAN LockHeld = (LockFlags & LPCP_LOCK_HELD);
59  BOOLEAN ReleaseLock = (LockFlags & LPCP_LOCK_RELEASE);
60 
61  PAGED_CODE();
62 
63  LPCTRACE(LPC_CLOSE_DEBUG, "Message: %p. LockFlags: %lx\n", Message, LockFlags);
64 
65  /* Acquire the lock if not already */
66  if (!LockHeld) KeAcquireGuardedMutex(&LpcpLock);
67 
68  /* Check if the queue list is empty */
69  if (!IsListEmpty(&Message->Entry))
70  {
71  /* Remove and re-initialize */
72  RemoveEntryList(&Message->Entry);
73  InitializeListHead(&Message->Entry);
74  }
75 
76  /* Check if we've already replied */
77  if (Message->RepliedToThread)
78  {
79  /* Set thread to dereference and clean up */
80  Thread = Message->RepliedToThread;
81  Message->RepliedToThread = NULL;
82  }
83 
84  /* Check if this is a connection request */
85  if (Message->Request.u2.s2.Type == LPC_CONNECTION_REQUEST)
86  {
87  /* Get the connection message */
88  ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
89 
90  /* Clear the client port */
91  ClientPort = ConnectMessage->ClientPort;
92  if (ClientPort) ConnectMessage->ClientPort = NULL;
93  }
94 
95  /* Release the lock */
97 
98  /* Check if we had anything to dereference */
101 
102  /* Free the entry */
103  ExFreeToPagedLookasideList(&LpcpMessagesLookaside, Message);
104 
105  /* Reacquire the lock if needed */
106  if ((LockHeld) && !(ReleaseLock)) KeAcquireGuardedMutex(&LpcpLock);
107 }
108 
109 VOID
110 NTAPI
112  IN BOOLEAN Destroy)
113 {
114  PLIST_ENTRY ListHead, NextEntry;
117  PLPCP_PORT_OBJECT ConnectionPort = NULL;
118  PLPCP_CONNECTION_MESSAGE ConnectMessage;
119  PLPCP_NONPAGED_PORT_QUEUE MessageQueue;
120 
121  PAGED_CODE();
122  LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p. Flags: %lx\n", Port, Port->Flags);
123 
124  /* Hold the lock */
126 
127  /* Check if we have a connected port */
129  (Port->ConnectedPort))
130  {
131  /* Disconnect it */
132  Port->ConnectedPort->ConnectedPort = NULL;
133  ConnectionPort = Port->ConnectedPort->ConnectionPort;
134  if (ConnectionPort)
135  {
136  /* Clear connection port */
137  Port->ConnectedPort->ConnectionPort = NULL;
138  }
139  }
140 
141  /* Check if this is a connection port */
143  {
144  /* Delete the name */
146  }
147 
148  /* Walk all the threads waiting and signal them */
149  ListHead = &Port->LpcReplyChainHead;
150  NextEntry = ListHead->Flink;
151  while ((NextEntry) && (NextEntry != ListHead))
152  {
153  /* Get the Thread */
154  Thread = CONTAINING_RECORD(NextEntry, ETHREAD, LpcReplyChain);
155 
156  /* Make sure we're not in exit */
157  if (Thread->LpcExitThreadCalled) break;
158 
159  /* Move to the next entry */
160  NextEntry = NextEntry->Flink;
161 
162  /* Remove and reinitialize the List */
165 
166  /* Check if someone is waiting */
167  if (!KeReadStateSemaphore(&Thread->LpcReplySemaphore))
168  {
169  /* Get the message */
171  if (Message)
172  {
173  /* Check if it's a connection request */
174  if (Message->Request.u2.s2.Type == LPC_CONNECTION_REQUEST)
175  {
176  /* Get the connection message */
177  ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
178 
179  /* Check if it had a section */
180  if (ConnectMessage->SectionToMap)
181  {
182  /* Dereference it */
183  ObDereferenceObject(ConnectMessage->SectionToMap);
184  }
185  }
186 
187  /* Clear the reply message */
188  Thread->LpcReplyMessage = NULL;
189 
190  /* And remove the message from the port zone */
192  NextEntry = Port->LpcReplyChainHead.Flink;
193  }
194 
195  /* Release the semaphore and reset message id count */
196  Thread->LpcReplyMessageId = 0;
197  KeReleaseSemaphore(&Thread->LpcReplySemaphore, 0, 1, FALSE);
198  }
199  }
200 
201  /* Reinitialize the list head */
202  InitializeListHead(&Port->LpcReplyChainHead);
203 
204  /* Loop queued messages */
205  while ((Port->MsgQueue.ReceiveHead.Flink) &&
206  !(IsListEmpty(&Port->MsgQueue.ReceiveHead)))
207  {
208  /* Get the message */
209  Message = CONTAINING_RECORD(Port->MsgQueue.ReceiveHead.Flink,
210  LPCP_MESSAGE,
211  Entry);
212 
213  /* Free and reinitialize it's list head */
214  RemoveEntryList(&Message->Entry);
215  InitializeListHead(&Message->Entry);
216 
217  /* Remove it from the port zone */
219  }
220 
221  /* Release the lock */
223 
224  /* Dereference the connection port */
225  if (ConnectionPort) ObDereferenceObject(ConnectionPort);
226 
227  /* Check if we have to free the port entirely */
228  if (Destroy)
229  {
230  /* Check if the semaphore exists */
231  if (Port->MsgQueue.Semaphore)
232  {
233  /* Use the semaphore to find the port queue and free it */
234  MessageQueue = CONTAINING_RECORD(Port->MsgQueue.Semaphore,
236  Semaphore);
237  ExFreePoolWithTag(MessageQueue, 'troP');
238  }
239  }
240 }
241 
242 VOID
243 NTAPI
245  IN PVOID Object,
248  IN ULONG SystemHandleCount)
249 {
251 
252  LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p. Flags: %lx\n", Port, Port->Flags);
253 
254  /* Only Server-side Connection Ports need clean up*/
256  {
257  /* Check the handle count */
258  switch (SystemHandleCount)
259  {
260  /* No handles left */
261  case 0:
262 
263  /* Destroy the port queue */
265  break;
266 
267  /* Last handle remaining */
268  case 1:
269 
270  /* Reset the queue only */
272 
273  /* More handles remain, do nothing */
274  default:
275  break;
276  }
277  }
278 }
279 
280 VOID
281 NTAPI
283 {
284  /* Check if this is a client port */
286  {
287  /* Check if security is static */
288  if (!(Port->Flags & LPCP_SECURITY_DYNAMIC))
289  {
290  /* Check if we have a token */
291  if (Port->StaticSecurity.ClientToken)
292  {
293  /* Free security */
294  SeDeleteClientSecurity(&Port->StaticSecurity);
295  }
296  }
297  }
298 }
299 
300 VOID
301 NTAPI
303 {
307  PLPCP_PORT_OBJECT ConnectionPort;
309  PLIST_ENTRY ListHead, NextEntry;
310  HANDLE Pid;
311  CLIENT_DIED_MSG ClientDiedMsg;
312 
313  PAGED_CODE();
314  LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p. Flags: %lx\n", Port, Port->Flags);
315 
316  Timeout.QuadPart = -1000000;
317 
318  /* Check if this is a communication port */
320  {
321  /* Acquire the lock */
323 
324  /* Get the thread */
325  Thread = Port->ClientThread;
326  if (Thread)
327  {
328  /* Clear it */
329  Port->ClientThread = NULL;
330 
331  /* Release the lock and dereference */
334  }
335  else
336  {
337  /* Release the lock */
339  }
340  }
341 
342  /* Check if this is a client-side port */
344  {
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;
351 
352  /* Send it */
353  for (;;)
354  {
355  /* Send the message */
356  if (LpcRequestPort(Port, &ClientDiedMsg.h) != STATUS_NO_MEMORY)
357  break;
358 
359  /* Wait until trying again */
361  }
362  }
363 
364  /* Destroy the port queue */
366 
367  /* Check if we had views */
368  if ((Port->ClientSectionBase) || (Port->ServerSectionBase))
369  {
370  /* Check if we had a client view */
371  if (Port->ClientSectionBase)
372  {
373  /* Unmap it */
374  MmUnmapViewOfSection(Port->MappingProcess,
375  Port->ClientSectionBase);
376  }
377 
378  /* Check for a server view */
379  if (Port->ServerSectionBase)
380  {
381  /* Unmap it */
382  MmUnmapViewOfSection(Port->MappingProcess,
383  Port->ServerSectionBase);
384  }
385 
386  /* Dereference the mapping process */
387  ObDereferenceObject(Port->MappingProcess);
388  Port->MappingProcess = NULL;
389  }
390 
391  /* Acquire the lock */
393 
394  /* Get the connection port */
395  ConnectionPort = Port->ConnectionPort;
396  if (ConnectionPort)
397  {
398  /* Get the PID */
399  Pid = PsGetCurrentProcessId();
400 
401  /* Loop the data lists */
402  ListHead = &ConnectionPort->LpcDataInfoChainHead;
403  NextEntry = ListHead->Flink;
404  while (NextEntry != ListHead)
405  {
406  /* Get the message */
408  NextEntry = NextEntry->Flink;
409 
410  /* Check if this is the connection port */
411  if (Port == ConnectionPort)
412  {
413  /* Free queued messages */
414  RemoveEntryList(&Message->Entry);
415  InitializeListHead(&Message->Entry);
417 
418  /* Restart at the head */
419  NextEntry = ListHead->Flink;
420  }
421  else if ((Message->Request.ClientId.UniqueProcess == Pid) &&
422  ((Message->SenderPort == Port) ||
423  (Message->SenderPort == Port->ConnectedPort) ||
424  (Message->SenderPort == ConnectionPort)))
425  {
426  /* Remove it */
427  RemoveEntryList(&Message->Entry);
428  InitializeListHead(&Message->Entry);
430 
431  /* Restart at the head */
432  NextEntry = ListHead->Flink;
433  }
434  }
435 
436  /* Release the lock */
438 
439  /* Dereference the object unless it's the same port */
440  if (ConnectionPort != Port) ObDereferenceObject(ConnectionPort);
441 
442  /* Check if this is a connection port with a server process */
444  (ConnectionPort->ServerProcess))
445  {
446  /* Dereference the server process */
447  ObDereferenceObject(ConnectionPort->ServerProcess);
448  ConnectionPort->ServerProcess = NULL;
449  }
450  }
451  else
452  {
453  /* Release the lock */
455  }
456 
457  /* Free client security */
459  LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p deleted\n", Port);
460 }
461 
462 /* EOF */
CPPORT Port[4]
Definition: headless.c:34
#define IN
Definition: typedefs.h:38
struct _LPCP_CONNECTION_MESSAGE * PLPCP_CONNECTION_MESSAGE
#define TRUE
Definition: types.h:120
KGUARDED_MUTEX LpcpLock
Definition: port.c:20
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
PAGED_LOOKASIDE_LIST LpcpMessagesLookaside
Definition: port.c:19
VOID FASTCALL KeAcquireGuardedMutex(IN PKGUARDED_MUTEX GuardedMutex)
Definition: gmutex.c:42
LARGE_INTEGER CreateTime
Definition: lpctypes.h:270
_Outptr_ PFLT_PORT * ClientPort
Definition: fltkernel.h:1892
VOID NTAPI ObDereferenceObject(IN PVOID Object)
Definition: obref.c:375
#define LPCP_LOCK_RELEASE
Definition: lpc.h:64
VOID NTAPI LpcpFreePortClientSecurity(IN PLPCP_PORT_OBJECT Port)
Definition: close.c:282
struct _LPCP_PORT_OBJECT * PLPCP_PORT_OBJECT
#define LPCP_PORT_TYPE_MASK
Definition: lpctypes.h:58
PEPROCESS ServerProcess
Definition: lpctypes.h:225
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
#define PAGED_CODE()
Definition: video.h:57
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define LPCP_CONNECTION_PORT
Definition: lpctypes.h:54
#define SeDeleteClientSecurity(C)
Definition: imports.h:320
USHORT Flags
Definition: cportlib.h:31
NTSTATUS NTAPI KeDelayExecutionThread(IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Interval OPTIONAL)
Definition: wait.c:283
#define PsGetCurrentProcess
Definition: psfuncs.h:17
#define LPCP_UNCONNECTED_PORT
Definition: lpctypes.h:55
FORCEINLINE PLPCP_MESSAGE LpcpGetMessageFromThread(IN PETHREAD Thread)
Definition: lpc_x.h:129
unsigned char BOOLEAN
LIST_ENTRY LpcReplyChain
Definition: pstypes.h:1039
smooth NULL
Definition: ftsmooth.c:416
VOID NTAPI LpcpClosePort(IN PEPROCESS Process OPTIONAL, IN PVOID Object, IN ACCESS_MASK GrantedAccess, IN ULONG ProcessHandleCount, IN ULONG SystemHandleCount)
Definition: close.c:244
LIST_ENTRY LpcDataInfoChainHead
Definition: lpctypes.h:222
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
NTSTATUS NTAPI LpcRequestPort(IN PVOID PortObject, IN PPORT_MESSAGE LpcMessage)
Definition: send.c:22
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
NTSTATUS NTAPI MmUnmapViewOfSection(IN PEPROCESS Process, IN PVOID BaseAddress)
Definition: section.c:3053
#define LPC_CLOSE_DEBUG
Definition: lpc.h:18
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
static IUnknown Object
Definition: main.c:512
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
CHAR Message[80]
Definition: alive.c:5
#define LPCP_LOCK_HELD
Definition: lpc.h:63
PORT_MESSAGE h
Definition: lpctypes.h:269
#define LPCP_NAME_DELETED
Definition: lpctypes.h:61
Definition: typedefs.h:117
VOID NTAPI LpcpDestroyPortQueue(IN PLPCP_PORT_OBJECT Port, IN BOOLEAN Destroy)
Definition: close.c:111
PLPCP_PORT_OBJECT ClientPort
Definition: lpctypes.h:257
static ULONG Timeout
Definition: ping.c:61
VOID NTAPI LpcExitThread(IN PETHREAD Thread)
Definition: close.c:19
ULONG LpcExitThreadCalled
Definition: pstypes.h:1146
VOID NTAPI LpcpFreeToPortZone(IN PLPCP_MESSAGE Message, IN ULONG LockFlags)
Definition: close.c:52
LONG NTAPI KeReleaseSemaphore(IN PKSEMAPHORE Semaphore, IN KPRIORITY Increment, IN LONG Adjustment, IN BOOLEAN Wait)
Definition: semphobj.c:54
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
LONG NTAPI KeReadStateSemaphore(IN PKSEMAPHORE Semaphore)
Definition: semphobj.c:41
#define STATUS_NO_MEMORY
Definition: ntstatus.h:246
HANDLE NTAPI PsGetCurrentProcessId(VOID)
Definition: process.c:1123
VOID FASTCALL KeReleaseGuardedMutex(IN OUT PKGUARDED_MUTEX GuardedMutex)
Definition: gmutex.c:53
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:219
#define LPCP_COMMUNICATION_PORT
Definition: lpctypes.h:56
unsigned int ULONG
Definition: retypes.h:1
#define LPCP_SECURITY_DYNAMIC
Definition: lpctypes.h:62
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
_In_ PSECURITY_SUBJECT_CONTEXT _In_ BOOLEAN _In_ ACCESS_MASK _In_ ACCESS_MASK _Outptr_opt_ PPRIVILEGE_SET _In_ PGENERIC_MAPPING _In_ KPROCESSOR_MODE _Out_ PACCESS_MASK GrantedAccess
Definition: sefuncs.h:13
#define LPCTRACE(x, fmt,...)
Definition: lpc.h:49
#define LPCP_CLIENT_PORT
Definition: lpctypes.h:57
ULONG ACCESS_MASK
Definition: nt_native.h:40
base of all file and directory entries
Definition: entries.h:82
VOID NTAPI LpcpDeletePort(IN PVOID ObjectBody)
Definition: close.c:302
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68