6#include "HAL/PlatformTLS.h"
7#include "HAL/PreprocessorHelpers.h"
8#include "Misc/AssertionMacros.h"
17extern bool GIsAutomationTesting;
20
21
22
23
24struct FRWAccessDetector
34 checkf(AtomicValue.load(std::memory_order_relaxed) == 0, TEXT(
"Detector cannot be destroyed while other threads access it"))
37 FRWAccessDetector(FRWAccessDetector&& Other)
39 checkf(Other.AtomicValue.load(std::memory_order_relaxed) == 0, TEXT(
"Detector cannot be \"moved out\" while other threads access it"));
42 FRWAccessDetector& operator=(FRWAccessDetector&& Other)
44 checkf(AtomicValue.load(std::memory_order_relaxed) == 0, TEXT(
"Detector cannot be modified while other threads access it"));
45 checkf(Other.AtomicValue.load(std::memory_order_relaxed) == 0, TEXT(
"Detector cannot be \"moved out\" while other threads access it"));
49 FRWAccessDetector(
const FRWAccessDetector& Other)
51 checkf(Other.AtomicValue.load(std::memory_order_relaxed) == 0, TEXT(
"Detector cannot be copied while other threads access it"));
54 FRWAccessDetector& operator=(
const FRWAccessDetector& Other)
56 checkf(AtomicValue.load(std::memory_order_relaxed) == 0, TEXT(
"Detector cannot be modified while other threads access it"));
57 checkf(Other.AtomicValue.load(std::memory_order_relaxed) == 0, TEXT(
"Detector cannot be copied while other threads access it"));
62
63
64
65 FORCEINLINE
bool AcquireReadAccess()
const
67 const bool ErrorDetected = (AtomicValue.fetch_add(1, std::memory_order_relaxed) & WriterBits) != 0;
68 checkf(!ErrorDetected || GIsAutomationTesting, TEXT(
"Aquiring a read access while there is already a write access"));
69 return !ErrorDetected;
73
74
75
76 FORCEINLINE
bool ReleaseReadAccess()
const
78 const bool ErrorDetected = (AtomicValue.fetch_sub(1, std::memory_order_relaxed) & WriterBits) != 0;
79 checkf(!ErrorDetected || GIsAutomationTesting, TEXT(
"Another thread asked to have a write access during this read access"));
80 return !ErrorDetected;
84
85
86
87 FORCEINLINE
bool AcquireWriteAccess()
const
89 const bool ErrorDetected = AtomicValue.fetch_add(WriterIncrementValue, std::memory_order_relaxed) != 0;
90 checkf(!ErrorDetected || GIsAutomationTesting, TEXT(
"Acquiring a write access while there are ongoing read or write access"));
91 return !ErrorDetected;
95
96
97
98 FORCEINLINE
bool ReleaseWriteAccess()
const
100 const bool ErrorDetected = AtomicValue.fetch_sub(WriterIncrementValue, std::memory_order_relaxed) != WriterIncrementValue;
101 checkf(!ErrorDetected || GIsAutomationTesting, TEXT(
"Another thread asked to have a read or write access during this write access"));
102 return !ErrorDetected;
109 static constexpr uint32 WriterBits = 0xfff00000;
110 static constexpr uint32 WriterIncrementValue = 0x100000;
112 mutable std::atomic<uint32> AtomicValue;
116
117
118
119struct FRWRecursiveAccessDetector :
public FRWAccessDetector
123
124
125
126 FORCEINLINE
bool AcquireWriteAccess()
const
128 uint32 CurThreadID = FPlatformTLS::GetCurrentThreadId();
130 if (WriterThreadID == CurThreadID)
135 else if (FRWAccessDetector::AcquireWriteAccess())
137 check(RecursiveDepth == 0);
138 WriterThreadID = CurThreadID;
146
147
148
149 FORCEINLINE
bool ReleaseWriteAccess()
const
151 uint32 CurThreadID = FPlatformTLS::GetCurrentThreadId();
152 if (WriterThreadID == CurThreadID)
154 check(RecursiveDepth > 0);
157 if (RecursiveDepth == 0)
159 WriterThreadID = (uint32)-1;
160 return FRWAccessDetector::ReleaseWriteAccess();
168 return FRWAccessDetector::ReleaseWriteAccess();
173 mutable uint32 WriterThreadID = (uint32)-1;
174 mutable int32 RecursiveDepth = 0;
178
179
180struct FRWFullyRecursiveAccessDetector :
public FRWRecursiveAccessDetector
184
185
186
187 FORCEINLINE
bool AcquireReadAccess()
const
189 uint32 CurThreadID = FPlatformTLS::GetCurrentThreadId();
190 if (WriterThreadID == CurThreadID)
194 return FRWAccessDetector::AcquireReadAccess();
198
199
200
201 FORCEINLINE
bool ReleaseReadAccess()
const
203 uint32 CurThreadID = FPlatformTLS::GetCurrentThreadId();
204 if (WriterThreadID == CurThreadID)
208 return FRWAccessDetector::ReleaseReadAccess();
212struct FBaseScopedAccessDetector
216template<
typename RWAccessDetector>
217struct TScopedReaderAccessDetector :
public FBaseScopedAccessDetector
221 FORCEINLINE TScopedReaderAccessDetector(
const RWAccessDetector& InAccessDetector)
222 : AccessDetector(InAccessDetector)
224 AccessDetector.AcquireReadAccess();
227 FORCEINLINE ~TScopedReaderAccessDetector()
229 AccessDetector.ReleaseReadAccess();
232 const RWAccessDetector& AccessDetector;
235template<
typename RWAccessDetector>
236FORCEINLINE TScopedReaderAccessDetector<RWAccessDetector> MakeScopedReaderAccessDetector(RWAccessDetector& InAccessDetector)
238 return TScopedReaderAccessDetector<RWAccessDetector>(InAccessDetector);
241template<
typename RWAccessDetector>
242struct TScopedWriterDetector :
public FBaseScopedAccessDetector
246 FORCEINLINE TScopedWriterDetector(
const RWAccessDetector& InAccessDetector)
247 : AccessDetector(InAccessDetector)
249 AccessDetector.AcquireWriteAccess();
252 FORCEINLINE ~TScopedWriterDetector()
254 AccessDetector.ReleaseWriteAccess();
257 const RWAccessDetector& AccessDetector;
260template<
typename RWAccessDetector>
261FORCEINLINE TScopedWriterDetector<RWAccessDetector> MakeScopedWriterAccessDetector(RWAccessDetector& InAccessDetector)
263 return TScopedWriterDetector<RWAccessDetector>(InAccessDetector);
266#define UE_MT_DECLARE_RW_ACCESS_DETECTOR(AccessDetector) FRWAccessDetector AccessDetector;
267#define UE_MT_DECLARE_RW_RECURSIVE_ACCESS_DETECTOR(AccessDetector) FRWRecursiveAccessDetector AccessDetector;
268#define UE_MT_DECLARE_RW_FULLY_RECURSIVE_ACCESS_DETECTOR(AccessDetector) FRWFullyRecursiveAccessDetector AccessDetector;
270#define UE_MT_SCOPED_READ_ACCESS(AccessDetector) const FBaseScopedAccessDetector& PREPROCESSOR_JOIN(ScopedMTAccessDetector_,__LINE__) = MakeScopedReaderAccessDetector(AccessDetector);
271#define UE_MT_SCOPED_WRITE_ACCESS(AccessDetector) const FBaseScopedAccessDetector& PREPROCESSOR_JOIN(ScopedMTAccessDetector_,__LINE__) = MakeScopedWriterAccessDetector(AccessDetector);
273#define UE_MT_ACQUIRE_READ_ACCESS(AccessDetector) (AccessDetector).AcquireReadAccess();
274#define UE_MT_RELEASE_READ_ACCESS(AccessDetector) (AccessDetector).ReleaseReadAccess();
275#define UE_MT_ACQUIRE_WRITE_ACCESS(AccessDetector) (AccessDetector).AcquireWriteAccess();
276#define UE_MT_RELEASE_WRITE_ACCESS(AccessDetector) (AccessDetector).ReleaseWriteAccess();
280#define UE_MT_DECLARE_RW_ACCESS_DETECTOR(AccessDetector)
281#define UE_MT_DECLARE_RW_RECURSIVE_ACCESS_DETECTOR(AccessDetector)
282#define UE_MT_DECLARE_RW_FULLY_RECURSIVE_ACCESS_DETECTOR(AccessDetector)
284#define UE_MT_SCOPED_READ_ACCESS(AccessDetector)
285#define UE_MT_SCOPED_WRITE_ACCESS(AccessDetector)
287#define UE_MT_ACQUIRE_READ_ACCESS(AccessDetector)
288#define UE_MT_RELEASE_READ_ACCESS(AccessDetector)
289#define UE_MT_ACQUIRE_WRITE_ACCESS(AccessDetector)
290#define UE_MT_RELEASE_WRITE_ACCESS(AccessDetector)
#define ENABLE_MT_DETECTOR