ReactOS  0.4.15-dev-2155-g06f57e1
fxtransactionedlist.cpp
Go to the documentation of this file.
1 /*++
2 
3 Copyright (c) Microsoft Corporation. All rights reserved.
4 
5 Module Name:
6 
7  FxTransactionedList.cpp
8 
9 Abstract:
10 
11  This module implements a simple transactioned list which allows the caller
12  to lock the list and then iterate over it without worrying about deletes
13  and adds.
14 
15 Author:
16 
17 
18 
19 Environment:
20 
21  Both kernel and user mode
22 
23 Revision History:
24 
25 --*/
26 
27 #include "fxsupportpch.hpp"
28 
30 {
33  m_Deleting = FALSE;
34  m_Retries = 0;
36 
39 }
40 
42 {
45 
46  //
47  // If m_DeleteOnRemove is FALSE, there is no need to iterate over any of the
48  // lists to free anything.
49  //
50  if (m_DeleteOnRemove == FALSE) {
53  return;
54  }
55 
57 
58  while (!IsListEmpty(&m_ListHead)) {
61 
63 
64  switch (pEntry->m_Transaction) {
66  //
67  // Nothing to do, no pending transaction
68  //
69  break;
70 
72  //
73  // Should not have an add transaction and be on the main list at the
74  // same time!
75  //
76  ASSERT(FALSE);
77  break;
78 
80  //
81  // Make sure it is not on the transaction list
82  //
83  RemoveEntryList(&pEntry->m_TransactionLink);
84  InitializeListHead(&pEntry->m_TransactionLink);
85 
86  //
87  // When inserted as a remove transaction, we add this reference in
88  // RemoveLocked
89  //
90  pEntry->GetTransactionedObject()->RELEASE(pEntry);
91  break;
92 
93  }
94 
95  pEntry->GetTransactionedObject()->DeleteObject();
96  }
97 
98  while (!IsListEmpty(&m_TransactionHead)) {
101 
102  pEntry = CONTAINING_RECORD(ple, FxTransactionedEntry, m_TransactionLink);
103 
104  //
105  // We yanked out all of the removes in the previous loop
106  //
107  ASSERT(pEntry->m_Transaction == FxTransactionActionAdd);
108 
109  //
110  // Delete the object since this list owns it.
111  //
112  pEntry->GetTransactionedObject()->DeleteObject();
113  }
114 }
115 
116 VOID
118  __in PFX_DRIVER_GLOBALS FxDriverGlobals
119  )
120 {
121  KIRQL irql;
122 
123  AcquireLock(FxDriverGlobals, &irql);
125  ReleaseLock(FxDriverGlobals, irql);
126 }
127 
128 VOID
130  __in PFX_DRIVER_GLOBALS FxDriverGlobals
131  )
132 {
133  LIST_ENTRY releaseHead;
134  KIRQL irql;
135  MxEvent* event;
136 
137  InitializeListHead(&releaseHead);
138  event = NULL;
139  AcquireLock(FxDriverGlobals, &irql);
141  ProcessTransactionList(&releaseHead);
142 
144  event = m_DeletingDoneEvent;
146  }
147  ReleaseLock(FxDriverGlobals, irql);
148 
149  ProcessObjectsToRelease(&releaseHead);
150 
151  if (event != NULL) {
152  event->Set();
153  }
154 }
155 
156 VOID
158  __in PLIST_ENTRY ReleaseHead
159  )
160 {
161  LIST_ENTRY *ple;
163 
164  //
165  // If there are other iterators, do not process transactions until they are
166  // done.
167  //
168  if (m_ListLockedRecursionCount != 0) {
169  return;
170  }
171 
172  while (!IsListEmpty(&m_TransactionHead)) {
175 
176  pEntry = CONTAINING_RECORD(ple, FxTransactionedEntry, m_TransactionLink);
177 
178  ASSERT(pEntry->m_Transaction != FxTransactionActionNothing);
179 
180  if (pEntry->m_Transaction == FxTransactionActionAdd) {
181  //
182  // Add to the main list
183  //
184  InsertTailList(&m_ListHead, &pEntry->m_ListLink);
185 
186  //
187  // Virtual notification of addition
188  //
190  }
191  else if (pEntry->m_Transaction == FxTransactionActionRemove) {
192  //
193  // Remove it from the main list and move it to a free list
194  //
195  RemoveEntryList(&pEntry->m_ListLink);
196  InsertTailList(ReleaseHead, &pEntry->m_TransactionLink);
197 
198  //
199  // Virtual notification of removal
200  //
202  }
203 
204  pEntry->m_Transaction = FxTransactionActionNothing;
205  }
206 }
207 
208 VOID
210  __in PLIST_ENTRY ReleaseHead
211  )
212 {
213  LIST_ENTRY *ple;
215 
216  while (!IsListEmpty(ReleaseHead)) {
217  ple = RemoveHeadList(ReleaseHead);
219 
220  pEntry = CONTAINING_RECORD(ple, FxTransactionedEntry, m_TransactionLink);
221 
222  //
223  // We always release our reference we took when we post the change
224  // to the list
225  //
226  pEntry->GetTransactionedObject()->RELEASE(pEntry);
227 
228  //
229  // 2ndary release if the list is set to do this
230  //
231  if (m_DeleteOnRemove) {
232  pEntry->GetTransactionedObject()->DeleteObject();
233  }
234  }
235 }
236 
237 BOOLEAN
239  __in PFX_DRIVER_GLOBALS FxDriverGlobals,
240  __in_opt MxEvent* DeleteDoneEvent
241  )
242 {
243  KIRQL irql;
244  BOOLEAN result;
245 
246  result = TRUE;
247 
248  AcquireLock(FxDriverGlobals, &irql);
249  m_Deleting = TRUE;
250 
251  if (m_ListLockedRecursionCount != 0) {
252  m_DeletingDoneEvent = DeleteDoneEvent;
253  result = FALSE;
254  }
255 
256  ReleaseLock(FxDriverGlobals, irql);
257 
258  return result;
259 }
260 
262 NTSTATUS
264  __in PFX_DRIVER_GLOBALS FxDriverGlobals,
266  )
267 {
269  KIRQL irql;
270 
271  AcquireLock(FxDriverGlobals, &irql);
272 
273  if (m_Deleting) {
275  }
276  else {
278  }
279 
280  if (NT_SUCCESS(status)) {
281  if (m_ListLockedRecursionCount == 0) {
282  //
283  // We can insert the entry now, do so
284  //
285  InsertTailList(&m_ListHead, &Entry->m_ListLink);
286 
287  EntryAdded(Entry);
288  }
289  else {
290  //
291  // List is locked, queue a transaction
292  //
293  Entry->m_Transaction = FxTransactionActionAdd;
294  InsertTailList(&m_TransactionHead, &Entry->m_TransactionLink);
295  }
296  }
297 
298  ReleaseLock(FxDriverGlobals, irql);
299 
300  return status;
301 }
302 
303 VOID
305  __in PFX_DRIVER_GLOBALS FxDriverGlobals,
306  __in PVOID EntryData
307  )
308 {
309  KIRQL irql;
312  BOOLEAN removed;
313 
314  removed = FALSE;
315 
316  AcquireLock(FxDriverGlobals, &irql);
317 
318  for (ple = m_TransactionHead.Flink;
320  ple = ple->Flink) {
321 
322  pEntry = CONTAINING_RECORD(ple, FxTransactionedEntry, m_TransactionLink);
323 
324  if (Compare(pEntry, EntryData)) {
325  if (pEntry->GetTransactionAction() == FxTransactionActionAdd) {
326  RemoveEntryList(&pEntry->m_TransactionLink);
327  InitializeListHead(&pEntry->m_TransactionLink);
328 
329  removed = TRUE;
330  }
331  else {
332  //
333  // Already being removed, just return
334  //
335  ASSERT(pEntry->GetTransactionAction() ==
337  }
338 
339  goto Done;
340  }
341  }
342 
343  //
344  // Walk the committed list
345  //
346  pEntry = NULL;
347 
348  while ((pEntry = GetNextEntryLocked(pEntry)) != NULL) {
349  if (Compare(pEntry, EntryData)) {
350  removed = RemoveLocked(pEntry);
351  break;
352  }
353  }
354 
355 Done:
356  ReleaseLock(FxDriverGlobals, irql);
357 
358  if (removed && m_DeleteOnRemove) {
359  pEntry->GetTransactionedObject()->DeleteObject();
360  }
361 }
362 
363 VOID
365  __in PFX_DRIVER_GLOBALS FxDriverGlobals,
367  )
368 {
369  BOOLEAN removed;
370  KIRQL irql;
371 
372  AcquireLock(FxDriverGlobals, &irql);
373  removed = RemoveLocked(Entry);
374  ReleaseLock(FxDriverGlobals,irql);
375 
376  if (removed && m_DeleteOnRemove) {
377  Entry->GetTransactionedObject()->DeleteObject();
378  }
379 }
380 
381 BOOLEAN
384  )
385 {
386  BOOLEAN removed;
387 
388  removed = FALSE;
389 
390  if (Entry->m_Transaction == FxTransactionActionAdd) {
391  //
392  // Not yet added to the list proper, remove it from the transaction list
393  //
394  removed = TRUE;
395  RemoveEntryList(&Entry->m_TransactionLink);
396  InitializeListHead(&Entry->m_TransactionLink);
397 
398  Entry->m_Transaction = FxTransactionActionNothing;
399  }
400  else {
401  ASSERT(!IsListEmpty(&Entry->m_ListLink));
402 
403  if (m_ListLockedRecursionCount == 0) {
404  //
405  // List is not locked, remove it now
406  //
407  RemoveEntryList(&Entry->m_ListLink);
408  InitializeListHead(&Entry->m_ListLink);
409 
410  //
411  // Virtual notification
412  //
414 
415  removed = TRUE;
416  }
417  else {
418  //
419  // List is locked for enumeration, queue a transaction
420  //
421  Entry->m_Transaction = FxTransactionActionRemove;
422  InsertTailList(&m_TransactionHead, &Entry->m_TransactionLink);
423  Entry->GetTransactionedObject()->ADDREF(Entry);
424  }
425  }
426 
427  return removed;
428 }
429 
434  )
435 /*++
436 
437 Routine Description:
438  Gets the next entry. Assumes the caller has called LockedForEnum
439 
440 Arguments:
441  Entry the current entry in the iteratation, NULL for the first
442 
443 Return Value:
444  next entry in the iteration, NULL if there are no more entries
445 
446  --*/
447 {
448  //
449  // The caller should have locked the list for enumeration
450  //
452 
453  return GetNextEntryLocked(Entry);
454 }
455 
460  )
461 /*++
462 
463 Routine Description:
464  Returns the next entry. Assumes that the caller has the list locked through
465  a call to AcquireLock() or through LockForEnum()
466 
467 Arguments:
468  Entry the current entry in the iteratation, NULL for the first
469 
470 Return Value:
471  next entry in the iteration, NULL if there are no more entries
472 
473  --*/
474 {
476 
477  if (Entry == NULL) {
478  ple = m_ListHead.Flink;
479  }
480  else {
481  ple = Entry->m_ListLink.Flink;
482  }
483 
484  //
485  // Find the next entry which does not have a pending transaction on it
486  //
487  for ( ; ple != &m_ListHead; ple = ple->Flink) {
488  FxTransactionedEntry* pNext;
489 
492  return pNext;
493  }
494  }
495 
496  //
497  // Reached the end of the list
498  //
499  return NULL;
500 }
501 
504 {
505 }
506 
509 VOID
511  __in PFX_DRIVER_GLOBALS FxDriverGlobals,
513  )
514 {
515  UNREFERENCED_PARAMETER(FxDriverGlobals);
516  m_ListLock.Acquire(Irql);
517 }
518 
520 VOID
522  __in PFX_DRIVER_GLOBALS FxDriverGlobals,
524  )
525 {
526  UNREFERENCED_PARAMETER(FxDriverGlobals);
527  m_ListLock.Release(Irql);
528 }
529 
530 _Acquires_lock_(_Global_critical_region_)
531 VOID
533  __in PFX_DRIVER_GLOBALS FxDriverGlobals,
535  )
536 {
538  m_StateChangeListLock.AcquireLock(FxDriverGlobals);
539 }
540 
541 _Releases_lock_(_Global_critical_region_)
542 VOID
544  __in PFX_DRIVER_GLOBALS FxDriverGlobals,
545  __in KIRQL Irql
546  )
547 {
549  m_StateChangeListLock.ReleaseLock(FxDriverGlobals);
550 }
551 
552 
_Acquires_lock_(_Global_critical_region_) VOID FxWaitLockTransactionedList
#define _Must_inspect_result_
Definition: no_sal2.h:62
VOID Remove(__in PFX_DRIVER_GLOBALS FxDriverGlobals, __in FxTransactionedEntry *Entry)
GLuint64EXT * result
Definition: glext.h:11304
FxWaitLockInternal m_StateChangeListLock
#define __in_opt
Definition: dbghelp.h:38
#define TRUE
Definition: types.h:120
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
BOOLEAN Deleting(__in PFX_DRIVER_GLOBALS FxDriverGlobals, __in_opt MxEvent *DeleteDoneEvent)
#define __drv_restoresIRQL
Definition: driverspecs.h:304
LONG NTSTATUS
Definition: precomp.h:26
VOID SearchForAndRemove(__in PFX_DRIVER_GLOBALS FxDriverGlobals, __in PVOID EntryData)
#define __drv_maxIRQL(irql)
Definition: driverspecs.h:273
NTSTATUS Add(__in PFX_DRIVER_GLOBALS FxDriverGlobals, __in FxTransactionedEntry *Entry)
KIRQL irql
Definition: wave.h:1
#define InsertTailList(ListHead, Entry)
_Out_ PKIRQL Irql
Definition: csq.h:179
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
_Must_inspect_result_ FxTransactionedEntry * GetNextEntryLocked(__in_opt FxTransactionedEntry *Entry)
PSINGLE_LIST_ENTRY ple
#define STATUS_INVALID_DEVICE_STATE
Definition: udferr_usr.h:178
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
VOID UnlockFromEnum(__in PFX_DRIVER_GLOBALS FxDriverGlobals)
UCHAR KIRQL
Definition: env_spec_w32.h:591
virtual VOID EntryRemoved(__in FxTransactionedEntry *Entry)
#define FALSE
Definition: types.h:117
virtual _Must_inspect_result_ NTSTATUS ProcessAdd(__in FxTransactionedEntry *Entry)
_Releases_lock_(_Global_critical_region_) VOID FxWaitLockTransactionedList
#define __out
Definition: dbghelp.h:62
virtual VOID EntryAdded(__in FxTransactionedEntry *Entry)
unsigned char BOOLEAN
FORCEINLINE PLIST_ENTRY RemoveHeadList(_Inout_ PLIST_ENTRY ListHead)
Definition: rtlfuncs.h:128
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
VOID LockForEnum(__in PFX_DRIVER_GLOBALS FxDriverGlobals)
__drv_requiresIRQL(DISPATCH_LEVEL) VOID FxSpinLockTransactionedList
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
#define ASSERT(a)
Definition: mode.c:45
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
virtual VOID AcquireLock(__in PFX_DRIVER_GLOBALS FxDriverGlobals, __out PKIRQL Irql)=0
_Must_inspect_result_ FxTransactionedEntry * GetNextEntry(__in_opt FxTransactionedEntry *Entry)
KIRQL * PKIRQL
Definition: env_spec_w32.h:592
Definition: typedefs.h:119
VOID ProcessTransactionList(__in PLIST_ENTRY ReleaseHead)
struct _cl_event * event
Definition: glext.h:7739
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define NULL
Definition: types.h:112
VOID ProcessObjectsToRelease(__in PLIST_ENTRY ReleaseHead)
virtual VOID ReleaseLock(__in PFX_DRIVER_GLOBALS FxDriverGlobals, __in KIRQL Irql)=0
static FxTransactionedEntry * _FromEntry(__in PLIST_ENTRY Entry)
virtual BOOLEAN Compare(__in FxTransactionedEntry *Entry, __in PVOID Data)
__drv_raisesIRQL(DISPATCH_LEVEL) __drv_maxIRQL(DISPATCH_LEVEL) VOID FxSpinLockTransactionedList
BOOLEAN RemoveLocked(__in FxTransactionedEntry *Entry)
PLIST_ENTRY pEntry
Definition: fxioqueue.cpp:4484
FxListTransactionAction m_Transaction
#define __in
Definition: dbghelp.h:35
static SERVICE_STATUS status
Definition: service.c:31
base of all file and directory entries
Definition: entries.h:82
Definition: ps.c:97