Files
ben clayton f23ab35448 [AutoRTFM] Make UAIPerceptionSystem::UnregisterSource() transaction-safe
Add and use FRWTransactionallySafeAccessDetector, a transaction-safe version of FRWAccessDetector.
Use a FTransactionallySafeCriticalSection for UObjectDeleteListenersCritical.

#rb neil.henning

[CL 35622505 by ben clayton in ue5-main branch]
2024-08-19 07:24:22 -04:00

451 lines
12 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Catch2Includes.h"
#include "Misc/MTTransactionallySafeAccessDetector.h"
#include <AutoRTFM/AutoRTFM.h>
#if ENABLE_MT_DETECTOR
TEST_CASE("MTTransactionallySafeAccessDetector")
{
FRWTransactionallySafeAccessDetector Detector;
SECTION("AcquireWriteAccess, ReleaseWriteAccess")
{
Detector.AcquireWriteAccess();
Detector.ReleaseWriteAccess();
}
SECTION("AcquireReadAccess, ReleaseReadAccess")
{
Detector.AcquireReadAccess();
Detector.ReleaseReadAccess();
}
SECTION("AcquireReadAccess, AcquireReadAccess, ReleaseReadAccess, ReleaseReadAccess")
{
Detector.AcquireReadAccess();
Detector.AcquireReadAccess();
Detector.ReleaseReadAccess();
Detector.ReleaseReadAccess();
}
SECTION("Transact(AcquireWriteAccess, ReleaseWriteAccess)")
{
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
Detector.AcquireWriteAccess();
Detector.ReleaseWriteAccess();
});
REQUIRE(AutoRTFM::ETransactionResult::Committed == Result);
}
SECTION("Transact(AcquireWriteAccess, ReleaseWriteAccess, Abort)")
{
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
Detector.AcquireWriteAccess();
Detector.ReleaseWriteAccess();
AutoRTFM::AbortTransaction();
});
REQUIRE(AutoRTFM::ETransactionResult::AbortedByRequest == Result);
}
SECTION("Transact(AcquireWriteAccess), ReleaseWriteAccess")
{
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
Detector.AcquireWriteAccess();
});
REQUIRE(AutoRTFM::ETransactionResult::Committed == Result);
Detector.ReleaseWriteAccess();
}
SECTION("Transact(AcquireWriteAccess, Abort)")
{
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
Detector.AcquireWriteAccess();
AutoRTFM::AbortTransaction();
});
REQUIRE(AutoRTFM::ETransactionResult::AbortedByRequest == Result);
}
SECTION("Transact(AcquireReadAccess, Abort)")
{
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
Detector.AcquireReadAccess();
AutoRTFM::AbortTransaction();
});
REQUIRE(AutoRTFM::ETransactionResult::AbortedByRequest == Result);
}
SECTION("AcquireReadAccess, Transact(AcquireReadAccess, Abort), ReleaseReadAccess")
{
Detector.AcquireReadAccess();
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
Detector.AcquireReadAccess();
AutoRTFM::AbortTransaction();
});
REQUIRE(AutoRTFM::ETransactionResult::AbortedByRequest == Result);
Detector.ReleaseReadAccess();
}
SECTION("AcquireWriteAccess, Transact(ReleaseWriteAccess)")
{
Detector.AcquireWriteAccess();
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
Detector.ReleaseWriteAccess();
});
REQUIRE(AutoRTFM::ETransactionResult::Committed == Result);
}
SECTION("AcquireReadAccess, Transact(ReleaseReadAccess)")
{
Detector.AcquireReadAccess();
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
Detector.ReleaseReadAccess();
});
REQUIRE(AutoRTFM::ETransactionResult::Committed == Result);
}
SECTION("AcquireWriteAccess, Transact(ReleaseWriteAccess, Abort), ReleaseWriteAccess")
{
Detector.AcquireWriteAccess();
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
Detector.ReleaseWriteAccess();
AutoRTFM::AbortTransaction();
});
REQUIRE(AutoRTFM::ETransactionResult::AbortedByRequest == Result);
Detector.ReleaseWriteAccess();
}
SECTION("Transact(AcquireReadAccess, AcquireReadAccess, ReleaseReadAccess, ReleaseReadAccess)")
{
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
Detector.AcquireReadAccess();
Detector.AcquireReadAccess();
Detector.ReleaseReadAccess();
Detector.ReleaseReadAccess();
});
REQUIRE(AutoRTFM::ETransactionResult::Committed == Result);
}
SECTION("Transact(AcquireReadAccess, AcquireReadAccess, ReleaseReadAccess, ReleaseReadAccess, Abort)")
{
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
Detector.AcquireReadAccess();
Detector.AcquireReadAccess();
Detector.ReleaseReadAccess();
Detector.ReleaseReadAccess();
AutoRTFM::AbortTransaction();
});
REQUIRE(AutoRTFM::ETransactionResult::AbortedByRequest == Result);
}
SECTION("Transact(AcquireWriteAccess, ReleaseWriteAccess, AcquireReadAccess)")
{
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
Detector.AcquireWriteAccess();
Detector.ReleaseWriteAccess();
Detector.AcquireReadAccess();
});
REQUIRE(AutoRTFM::ETransactionResult::Committed == Result);
Detector.ReleaseReadAccess();
}
SECTION("Transact(AcquireWriteAccess, ReleaseWriteAccess, AcquireReadAccess, Abort)")
{
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
Detector.AcquireWriteAccess();
Detector.ReleaseWriteAccess();
Detector.AcquireReadAccess();
AutoRTFM::AbortTransaction();
});
REQUIRE(AutoRTFM::ETransactionResult::AbortedByRequest == Result);
}
SECTION("Transact(AcquireWriteAccess, ReleaseWriteAccess, AcquireReadAccess, ReleaseReadAccess)")
{
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
Detector.AcquireWriteAccess();
Detector.ReleaseWriteAccess();
Detector.AcquireReadAccess();
Detector.ReleaseReadAccess();
});
REQUIRE(AutoRTFM::ETransactionResult::Committed == Result);
}
SECTION("Transact(AcquireWriteAccess, ReleaseWriteAccess, AcquireReadAccess, ReleaseReadAccess, Abort)")
{
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
Detector.AcquireWriteAccess();
Detector.ReleaseWriteAccess();
Detector.AcquireReadAccess();
Detector.ReleaseReadAccess();
AutoRTFM::AbortTransaction();
});
REQUIRE(AutoRTFM::ETransactionResult::AbortedByRequest == Result);
}
SECTION("AcquireReadAccess, Transact(ReleaseReadAccess, AcquireWriteAccess), ReleaseWriteAccess")
{
Detector.AcquireReadAccess();
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
Detector.ReleaseReadAccess();
Detector.AcquireWriteAccess();
});
REQUIRE(AutoRTFM::ETransactionResult::Committed == Result);
Detector.ReleaseWriteAccess();
}
SECTION("AcquireReadAccess, Transact(ReleaseReadAccess, AcquireWriteAccess, Abort), ReleaseReadAccess")
{
Detector.AcquireReadAccess();
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
Detector.ReleaseReadAccess();
Detector.AcquireWriteAccess();
AutoRTFM::AbortTransaction();
});
REQUIRE(AutoRTFM::ETransactionResult::AbortedByRequest == Result);
Detector.ReleaseReadAccess();
}
SECTION("AcquireReadAccess, Transact(ReleaseReadAccess, AcquireWriteAccess, ReleaseWriteAccess)")
{
Detector.AcquireReadAccess();
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
Detector.ReleaseReadAccess();
Detector.AcquireWriteAccess();
Detector.ReleaseWriteAccess();
});
REQUIRE(AutoRTFM::ETransactionResult::Committed == Result);
}
SECTION("AcquireReadAccess, Transact(ReleaseReadAccess, AcquireWriteAccess, ReleaseWriteAccess, Abort), ReleaseReadAccess")
{
Detector.AcquireReadAccess();
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
Detector.ReleaseReadAccess();
Detector.AcquireWriteAccess();
Detector.ReleaseWriteAccess();
AutoRTFM::AbortTransaction();
});
REQUIRE(AutoRTFM::ETransactionResult::AbortedByRequest == Result);
Detector.ReleaseReadAccess();
}
{
// These tests use AutoRTFM::Open() blocks to acquire / release locks.
// Transaction retries will cause the lock counts to go out of sync, so
// we can only test these with retries disabled retries.
struct DisableRetriesScope
{
DisableRetriesScope() : OldState(AutoRTFM::ForTheRuntime::GetRetryTransaction())
{
AutoRTFM::ForTheRuntime::SetRetryTransaction(AutoRTFM::ForTheRuntime::NoRetry);
}
~DisableRetriesScope()
{
AutoRTFM::ForTheRuntime::SetRetryTransaction(OldState);
}
AutoRTFM::ForTheRuntime::EAutoRTFMRetryTransactionState OldState;
};
DisableRetriesScope DisableRetries;
SECTION("Transact(AcquireReadAccess, Open(AcquireReadAccess, ReleaseReadAccess), ReleaseReadAccess)")
{
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
Detector.AcquireReadAccess();
AutoRTFM::Open([&]
{
Detector.AcquireReadAccess();
Detector.ReleaseReadAccess();
});
Detector.ReleaseReadAccess();
});
REQUIRE(AutoRTFM::ETransactionResult::Committed == Result);
}
SECTION("Transact(AcquireReadAccess, Open(AcquireReadAccess, ReleaseReadAccess), ReleaseReadAccess, Abort)")
{
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
Detector.AcquireReadAccess();
AutoRTFM::Open([&]
{
Detector.AcquireReadAccess();
Detector.ReleaseReadAccess();
});
Detector.ReleaseReadAccess();
AutoRTFM::AbortTransaction();
});
REQUIRE(AutoRTFM::ETransactionResult::AbortedByRequest == Result);
}
SECTION("Transact(AcquireReadAccess, Open(AcquireReadAccess)), ReleaseReadAccess, ReleaseReadAccess")
{
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
Detector.AcquireReadAccess();
AutoRTFM::Open([&]
{
Detector.AcquireReadAccess();
});
});
REQUIRE(AutoRTFM::ETransactionResult::Committed == Result);
Detector.ReleaseReadAccess();
Detector.ReleaseReadAccess();
}
SECTION("Transact(Open(AcquireReadAccess), ReleaseReadAccess, AcquireWriteAccess, Abort), ReleaseReadAccess")
{
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
AutoRTFM::Open([&]
{
Detector.AcquireReadAccess();
});
Detector.ReleaseReadAccess();
Detector.AcquireWriteAccess();
AutoRTFM::AbortTransaction();
});
REQUIRE(AutoRTFM::ETransactionResult::AbortedByRequest == Result);
Detector.ReleaseReadAccess();
}
SECTION("Transact(AcquireReadAccess, Open(AcquireReadAccess), Abort), ReleaseReadAccess")
{
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
Detector.AcquireReadAccess();
AutoRTFM::Open([&]
{
Detector.AcquireReadAccess();
});
AutoRTFM::AbortTransaction();
});
REQUIRE(AutoRTFM::ETransactionResult::AbortedByRequest == Result);
Detector.ReleaseReadAccess();
}
SECTION("AcquireReadAccess, Transact(AcquireReadAccess, Open(ReleaseReadAccess), Abort)")
{
Detector.AcquireReadAccess();
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
Detector.AcquireReadAccess();
AutoRTFM::Open([&]
{
Detector.ReleaseReadAccess();
});
AutoRTFM::AbortTransaction();
});
REQUIRE(AutoRTFM::ETransactionResult::AbortedByRequest == Result);
}
SECTION("AcquireWriteAccess, Transact(Open(ReleaseWriteAccess), AcquireReadAccess, ReleaseReadAccess)")
{
Detector.AcquireWriteAccess();
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
AutoRTFM::Open([&]
{
Detector.ReleaseWriteAccess();
});
Detector.AcquireReadAccess();
});
REQUIRE(AutoRTFM::ETransactionResult::Committed == Result);
Detector.ReleaseReadAccess();
}
SECTION("AcquireWriteAccess, Transact(Open(ReleaseWriteAccess), AcquireReadAccess, Abort)")
{
Detector.AcquireWriteAccess();
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
AutoRTFM::Open([&]
{
Detector.ReleaseWriteAccess();
});
Detector.AcquireReadAccess();
AutoRTFM::AbortTransaction();
});
REQUIRE(AutoRTFM::ETransactionResult::AbortedByRequest == Result);
}
SECTION("AcquireReadAccess, Transact(Open(ReleaseReadAccess), AcquireWriteAccess), ReleaseWriteAccess")
{
Detector.AcquireReadAccess();
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
AutoRTFM::Open([&]
{
Detector.ReleaseReadAccess();
});
Detector.AcquireWriteAccess();
});
REQUIRE(AutoRTFM::ETransactionResult::Committed == Result);
Detector.ReleaseWriteAccess();
}
SECTION("AcquireReadAccess, Transact(Open(ReleaseReadAccess), AcquireWriteAccess, Abort)")
{
Detector.AcquireReadAccess();
AutoRTFM::ETransactionResult Result = AutoRTFM::Transact([&]
{
AutoRTFM::Open([&]
{
Detector.ReleaseReadAccess();
});
Detector.AcquireWriteAccess();
AutoRTFM::AbortTransaction();
});
REQUIRE(AutoRTFM::ETransactionResult::AbortedByRequest == Result);
}
}
}
#endif // ENABLE_MT_DETECTOR