Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553/*++
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
FxTransactionedList.cpp
Abstract:
This module implements a simple transactioned list which allows the caller to lock the list and then iterate over it without worrying about deletes and adds.
Author:
Environment:
Both kernel and user mode
Revision History:
--*/
#include "fxsupportpch.hpp"
FxTransactionedList::FxTransactionedList(){ m_ListLockedRecursionCount = 0; m_DeleteOnRemove = FALSE; m_Deleting = FALSE; m_Retries = 0; m_DeletingDoneEvent = NULL;
InitializeListHead(&m_ListHead); InitializeListHead(&m_TransactionHead);}
FxTransactionedList::~FxTransactionedList(){ FxTransactionedEntry* pEntry; PLIST_ENTRY ple;
// // If m_DeleteOnRemove is FALSE, there is no need to iterate over any of the // lists to free anything. // if (m_DeleteOnRemove == FALSE) { ASSERT(IsListEmpty(&m_ListHead)); ASSERT(IsListEmpty(&m_TransactionHead)); return; }
ASSERT(m_ListLockedRecursionCount == 0);
while (!IsListEmpty(&m_ListHead)) { ple = RemoveHeadList(&m_ListHead); InitializeListHead(ple);
pEntry = FxTransactionedEntry::_FromEntry(ple);
switch (pEntry->m_Transaction) { case FxTransactionActionNothing: // // Nothing to do, no pending transaction // break;
case FxTransactionActionAdd: // // Should not have an add transaction and be on the main list at the // same time! // ASSERT(FALSE); break;
case FxTransactionActionRemove: // // Make sure it is not on the transaction list // RemoveEntryList(&pEntry->m_TransactionLink); InitializeListHead(&pEntry->m_TransactionLink);
// // When inserted as a remove transaction, we add this reference in // RemoveLocked // pEntry->GetTransactionedObject()->RELEASE(pEntry); break;
}
pEntry->GetTransactionedObject()->DeleteObject(); }
while (!IsListEmpty(&m_TransactionHead)) { ple = RemoveHeadList(&m_TransactionHead); InitializeListHead(ple);
pEntry = CONTAINING_RECORD(ple, FxTransactionedEntry, m_TransactionLink);
// // We yanked out all of the removes in the previous loop // ASSERT(pEntry->m_Transaction == FxTransactionActionAdd);
// // Delete the object since this list owns it. // pEntry->GetTransactionedObject()->DeleteObject(); }}
VOIDFxTransactionedList::LockForEnum( __in PFX_DRIVER_GLOBALS FxDriverGlobals ){ KIRQL irql;
AcquireLock(FxDriverGlobals, &irql); m_ListLockedRecursionCount++; ReleaseLock(FxDriverGlobals, irql);}
VOIDFxTransactionedList::UnlockFromEnum( __in PFX_DRIVER_GLOBALS FxDriverGlobals ){ LIST_ENTRY releaseHead; KIRQL irql; MxEvent* event;
InitializeListHead(&releaseHead); event = NULL; AcquireLock(FxDriverGlobals, &irql); m_ListLockedRecursionCount--; ProcessTransactionList(&releaseHead);
if (m_ListLockedRecursionCount == 0 && m_Deleting) { event = m_DeletingDoneEvent; m_DeletingDoneEvent = NULL; } ReleaseLock(FxDriverGlobals, irql);
ProcessObjectsToRelease(&releaseHead);
if (event != NULL) { event->Set(); }}
VOIDFxTransactionedList::ProcessTransactionList( __in PLIST_ENTRY ReleaseHead ){ LIST_ENTRY *ple; FxTransactionedEntry* pEntry;
// // If there are other iterators, do not process transactions until they are // done. // if (m_ListLockedRecursionCount != 0) { return; }
while (!IsListEmpty(&m_TransactionHead)) { ple = RemoveHeadList(&m_TransactionHead); InitializeListHead(ple);
pEntry = CONTAINING_RECORD(ple, FxTransactionedEntry, m_TransactionLink);
ASSERT(pEntry->m_Transaction != FxTransactionActionNothing);
if (pEntry->m_Transaction == FxTransactionActionAdd) { // // Add to the main list // InsertTailList(&m_ListHead, &pEntry->m_ListLink);
// // Virtual notification of addition // EntryAdded(pEntry); } else if (pEntry->m_Transaction == FxTransactionActionRemove) { // // Remove it from the main list and move it to a free list // RemoveEntryList(&pEntry->m_ListLink); InsertTailList(ReleaseHead, &pEntry->m_TransactionLink);
// // Virtual notification of removal // EntryRemoved(pEntry); }
pEntry->m_Transaction = FxTransactionActionNothing; }}
VOIDFxTransactionedList::ProcessObjectsToRelease( __in PLIST_ENTRY ReleaseHead ){ LIST_ENTRY *ple; FxTransactionedEntry* pEntry;
while (!IsListEmpty(ReleaseHead)) { ple = RemoveHeadList(ReleaseHead); InitializeListHead(ple);
pEntry = CONTAINING_RECORD(ple, FxTransactionedEntry, m_TransactionLink);
// // We always release our reference we took when we post the change // to the list // pEntry->GetTransactionedObject()->RELEASE(pEntry);
// // 2ndary release if the list is set to do this // if (m_DeleteOnRemove) { pEntry->GetTransactionedObject()->DeleteObject(); } }}
BOOLEANFxTransactionedList::Deleting( __in PFX_DRIVER_GLOBALS FxDriverGlobals, __in_opt MxEvent* DeleteDoneEvent ){ KIRQL irql; BOOLEAN result;
result = TRUE;
AcquireLock(FxDriverGlobals, &irql); m_Deleting = TRUE;
if (m_ListLockedRecursionCount != 0) { m_DeletingDoneEvent = DeleteDoneEvent; result = FALSE; }
ReleaseLock(FxDriverGlobals, irql);
return result;}
_Must_inspect_result_NTSTATUSFxTransactionedList::Add( __in PFX_DRIVER_GLOBALS FxDriverGlobals, __in FxTransactionedEntry* Entry ){ NTSTATUS status; KIRQL irql;
AcquireLock(FxDriverGlobals, &irql);
if (m_Deleting) { status = STATUS_INVALID_DEVICE_STATE; } else { status = ProcessAdd(Entry); }
if (NT_SUCCESS(status)) { if (m_ListLockedRecursionCount == 0) { // // We can insert the entry now, do so // InsertTailList(&m_ListHead, &Entry->m_ListLink);
EntryAdded(Entry); } else { // // List is locked, queue a transaction // Entry->m_Transaction = FxTransactionActionAdd; InsertTailList(&m_TransactionHead, &Entry->m_TransactionLink); } }
ReleaseLock(FxDriverGlobals, irql);
return status;}
VOIDFxTransactionedList::SearchForAndRemove( __in PFX_DRIVER_GLOBALS FxDriverGlobals, __in PVOID EntryData ){ KIRQL irql; FxTransactionedEntry* pEntry; PLIST_ENTRY ple; BOOLEAN removed;
removed = FALSE;
AcquireLock(FxDriverGlobals, &irql);
for (ple = m_TransactionHead.Flink; ple != &m_TransactionHead; ple = ple->Flink) {
pEntry = CONTAINING_RECORD(ple, FxTransactionedEntry, m_TransactionLink);
if (Compare(pEntry, EntryData)) { if (pEntry->GetTransactionAction() == FxTransactionActionAdd) { RemoveEntryList(&pEntry->m_TransactionLink); InitializeListHead(&pEntry->m_TransactionLink);
removed = TRUE; } else { // // Already being removed, just return // ASSERT(pEntry->GetTransactionAction() == FxTransactionActionRemove); }
goto Done; } }
// // Walk the committed list // pEntry = NULL;
while ((pEntry = GetNextEntryLocked(pEntry)) != NULL) { if (Compare(pEntry, EntryData)) { removed = RemoveLocked(pEntry); break; } }
Done: ReleaseLock(FxDriverGlobals, irql);
if (removed && m_DeleteOnRemove) { pEntry->GetTransactionedObject()->DeleteObject(); }}
VOIDFxTransactionedList::Remove( __in PFX_DRIVER_GLOBALS FxDriverGlobals, __in FxTransactionedEntry* Entry ){ BOOLEAN removed; KIRQL irql;
AcquireLock(FxDriverGlobals, &irql); removed = RemoveLocked(Entry); ReleaseLock(FxDriverGlobals,irql);
if (removed && m_DeleteOnRemove) { Entry->GetTransactionedObject()->DeleteObject(); }}
BOOLEANFxTransactionedList::RemoveLocked( __in FxTransactionedEntry* Entry ){ BOOLEAN removed;
removed = FALSE;
if (Entry->m_Transaction == FxTransactionActionAdd) { // // Not yet added to the list proper, remove it from the transaction list // removed = TRUE; RemoveEntryList(&Entry->m_TransactionLink); InitializeListHead(&Entry->m_TransactionLink);
Entry->m_Transaction = FxTransactionActionNothing; } else { ASSERT(!IsListEmpty(&Entry->m_ListLink));
if (m_ListLockedRecursionCount == 0) { // // List is not locked, remove it now // RemoveEntryList(&Entry->m_ListLink); InitializeListHead(&Entry->m_ListLink);
// // Virtual notification // EntryRemoved(Entry);
removed = TRUE; } else { // // List is locked for enumeration, queue a transaction // Entry->m_Transaction = FxTransactionActionRemove; InsertTailList(&m_TransactionHead, &Entry->m_TransactionLink); Entry->GetTransactionedObject()->ADDREF(Entry); } }
return removed;}
_Must_inspect_result_FxTransactionedEntry*FxTransactionedList::GetNextEntry( __in_opt FxTransactionedEntry* Entry )/*++
Routine Description: Gets the next entry. Assumes the caller has called LockedForEnum
Arguments: Entry the current entry in the iteratation, NULL for the first
Return Value: next entry in the iteration, NULL if there are no more entries
--*/{ // // The caller should have locked the list for enumeration // ASSERT(m_ListLockedRecursionCount > 0 || m_Deleting);
return GetNextEntryLocked(Entry);}
_Must_inspect_result_FxTransactionedEntry*FxTransactionedList::GetNextEntryLocked( __in_opt FxTransactionedEntry* Entry )/*++
Routine Description: Returns the next entry. Assumes that the caller has the list locked through a call to AcquireLock() or through LockForEnum()
Arguments: Entry the current entry in the iteratation, NULL for the first
Return Value: next entry in the iteration, NULL if there are no more entries
--*/{ PLIST_ENTRY ple;
if (Entry == NULL) { ple = m_ListHead.Flink; } else { ple = Entry->m_ListLink.Flink; }
// // Find the next entry which does not have a pending transaction on it // for ( ; ple != &m_ListHead; ple = ple->Flink) { FxTransactionedEntry* pNext;
pNext = FxTransactionedEntry::_FromEntry(ple); if (pNext->m_Transaction == FxTransactionActionNothing) { return pNext; } }
// // Reached the end of the list // return NULL;}
FxSpinLockTransactionedList::FxSpinLockTransactionedList() : FxTransactionedList(){}
__drv_raisesIRQL(DISPATCH_LEVEL)__drv_maxIRQL(DISPATCH_LEVEL)VOIDFxSpinLockTransactionedList::AcquireLock( __in PFX_DRIVER_GLOBALS FxDriverGlobals, __out PKIRQL Irql ){ UNREFERENCED_PARAMETER(FxDriverGlobals); m_ListLock.Acquire(Irql);}
__drv_requiresIRQL(DISPATCH_LEVEL)VOIDFxSpinLockTransactionedList::ReleaseLock( __in PFX_DRIVER_GLOBALS FxDriverGlobals, __in __drv_restoresIRQL KIRQL Irql ){ UNREFERENCED_PARAMETER(FxDriverGlobals); m_ListLock.Release(Irql);}
_Acquires_lock_(_Global_critical_region_)VOIDFxWaitLockTransactionedList::AcquireLock( __in PFX_DRIVER_GLOBALS FxDriverGlobals, __out PKIRQL Irql ){ UNREFERENCED_PARAMETER(Irql); m_StateChangeListLock.AcquireLock(FxDriverGlobals);}
_Releases_lock_(_Global_critical_region_)VOIDFxWaitLockTransactionedList::ReleaseLock( __in PFX_DRIVER_GLOBALS FxDriverGlobals, __in KIRQL Irql ){ UNREFERENCED_PARAMETER(Irql); m_StateChangeListLock.ReleaseLock(FxDriverGlobals);}