UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
AutoRTFM.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
11// HEADER_UNIT_SKIP - unused warnings
12
13#include "AutoRTFMConstants.h"
14#include "AutoRTFMDefines.h" // IWYU pragma: export
15
16#ifdef __cplusplus
17#include "AutoRTFMTask.h"
18
19#include <algorithm>
20#include <cstdarg>
21#include <tuple>
22#include <type_traits>
23#include <utility>
24#endif // __cplusplus
25
26#include <memory.h>
27#include <stdlib.h>
28
29#ifdef __cplusplus
30extern "C"
31{
32#endif
33
34// The C API exists for a few reasons:
35//
36// - It makes linking easy. AutoRTFM has to deal with a weird kind of linking
37// where the compiler directly emits calls to functions with a given name.
38// It's easiest to do that in llvm if the functions have C linkage and C ABI.
39// - It makes testing easy. Even seemingly simple C++ code introduces pitfalls
40// for AutoRTFM. So very focused tests work best when written in C.
41// - It makes compiler optimizations much easier as there is no mangling to
42// consider when looking for functions in the runtime we can optimize.
43//
44// We use snake_case for C API surface area to make it easy to distinguish.
45//
46// The C API should not be used directly - it is here purely as an
47// implementation detail.
48
49// This must match AutoRTFM::ETransactionResult.
59
60// This must match AutoRTFM::EContextStatus.
74
75// AutoRTFM logging severity.
84
85// An opaque unique identifier for a transaction.
87
88// Function pointers used by AutoRTFM for heap allocations, etc.
89typedef struct
90{
91 // The function used to allocate memory from the heap.
92 // Must not be null.
93 void* (*Allocate)(size_t Size, size_t Alignment);
94
95 // The function used to reallocate memory from the heap.
96 // Must not be null.
97 void* (*Reallocate)(void* Pointer, size_t Size, size_t Alignment);
98
99 // The function used to allocate zeroed memory from the heap.
100 // Must not be null.
101 void* (*AllocateZeroed)(size_t Size, size_t Alignment);
102
103 // The function used to free memory allocated by Allocate() and AllocateZeroed().
104 // Must not be null.
105 void (*Free)(void* Pointer);
106
107 // Function used to log messages using a printf-style format string and va_list arguments.
108 // Strings use UTF-8 encoding.
109 // Must not be null.
110 void (*Log)(const char* File, int Line, void* ProgramCounter, autortfm_log_severity Severity, const char* Format, va_list Args);
111
112 // Function used to log messages with a callstack using a printf-style format string and va_list arguments.
113 // Strings use UTF-8 encoding.
114 // Must not be null.
115 void (*LogWithCallstack)(void* ProgramCounter, autortfm_log_severity Severity, const char* Format, va_list Args);
116
117 // Function used to report an ensure failure using a printf-style format string and va_list arguments.
118 // Strings use UTF-8 encoding.
119 // Must not be null.
120 void (*EnsureFailure)(const char* File, int Line, void* ProgramCounter, const char* Condition, const char* Format, va_list Args);
121
122 // Function used to query whether a log severity is active.
123 // Must not be null.
124 bool (*IsLogActive)(autortfm_log_severity Severity);
125
126 // Optional callback to be informed when the value returned by
127 // ForTheRuntime::IsAutoRTFMRuntimeEnabled() changes.
128 // Can be null.
129 void (*OnRuntimeEnabledChanged)();
130
131 // Optional callback to be informed when the value returned by
132 // ForTheRuntime::GetRetryTransaction() changes.
133 // Can be null.
134 void (*OnRetryTransactionsChanged)();
135
136 // Optional callback to be informed when the value returned by
137 // ForTheRuntime::GetMemoryValidationLevel() changes.
138 // Can be null.
139 void (*OnMemoryValidationLevelChanged)();
140
141 // Optional callback to be informed when the value returned by
142 // ForTheRuntime::GetMemoryValidationThrottlingEnabled() changes.
143 // Can be null.
144 void (*OnMemoryValidationThrottlingChanged)();
145
146 // Optional callback to be informed when the value returned by
147 // ForTheRuntime::GetMemoryValidationStatisticsEnabled() changes.
148 // Can be null.
149 void (*OnMemoryValidationStatisticsChanged)();
150
152
153#if UE_AUTORTFM_ENABLED
154// Initialize the AutoRTFM library.
155// Parameters:
156// ExternAPI - Function pointers used by AutoRTFM for heap allocations, etc.
157// Must be non-null.
159#else
164#endif
165
166#if UE_AUTORTFM_ENABLED
167// Note: There is no implementation of this function.
168// The AutoRTFM compiler will replace all calls to this function with a constant boolean value.
170#else
175#endif
176
177#if UE_AUTORTFM_ENABLED
179#else
184#endif
185
186#if UE_AUTORTFM_ENABLED
188#else
193#endif
194
195#if UE_AUTORTFM_ENABLED
197#else
202#endif
203
204#if UE_AUTORTFM_ENABLED
206#else
211#endif
212
213#if UE_AUTORTFM_ENABLED
215#else
222#endif
223
224#if UE_AUTORTFM_ENABLED
226#else
233#endif
234
235#if UE_AUTORTFM_ENABLED
236UE_AUTORTFM_API void autortfm_commit(void (*UninstrumentedWork)(void*), void (*InstrumentedWork)(void*), void* Arg);
237#else
243#endif
244
245#if UE_AUTORTFM_ENABLED
247#else
249#endif
250
251#if UE_AUTORTFM_ENABLED
253#else
255#endif
256
257#if UE_AUTORTFM_ENABLED
259#else
261#endif
262
263#if UE_AUTORTFM_ENABLED
264UE_AUTORTFM_FORCENOINLINE UE_AUTORTFM_API void autortfm_open(void (*work)(void* arg), void* arg, const void* return_address);
265#else
266UE_AUTORTFM_CRITICAL_INLINE void autortfm_open(void (*work)(void* arg), void* arg, const void* /* return_address */) { work(arg); }
267#endif
268
269#if UE_AUTORTFM_ENABLED
271#else
272UE_AUTORTFM_CRITICAL_INLINE void autortfm_open_explicit_validation(autortfm_memory_validation_level, void (*work)(void* arg), void* arg, const void* /* return_address */) { work(arg); }
273#endif
274
275#if UE_AUTORTFM_ENABLED
277#else
288#endif
289
290#if UE_AUTORTFM_ENABLED
292#else
298#endif
299
300#if UE_AUTORTFM_ENABLED
302#else
308#endif
309
310// autortfm_open_to_closed_mapping maps an open function to its closed variant.
316
317// autortfm_open_to_closed_table holds a pointer to a null-terminated list of
318// autortfm_open_to_closed_mapping, and an intrusive linked-list pointer to the
319// previous and next registered autortfm_open_to_closed_table.
321{
322 // Null-terminated open function to closed function mapping table.
324 // An intrusive linked-list pointer to the previous autortfm_open_to_closed_table.
325 // Used by autortfm_register_open_to_closed_functions().
327 // An intrusive linked-list pointer to the next autortfm_open_to_closed_table.
328 // Used by autortfm_register_open_to_closed_functions().
330};
331
332#if UE_AUTORTFM_ENABLED
335#else
344#endif
345
346#if UE_AUTORTFM_ENABLED
348#else
354#endif
355
356#if UE_AUTORTFM_ENABLED
357UE_AUTORTFM_API void autortfm_on_commit(void (*work)(void* arg), void* arg);
358#else
360{
361 work(arg);
362}
363#endif
364
365#if UE_AUTORTFM_ENABLED
367#else
373#endif
374
375#if UE_AUTORTFM_ENABLED
377#else
383#endif
384
385#if UE_AUTORTFM_ENABLED
386UE_AUTORTFM_API void autortfm_push_on_abort_handler(const void* key, void (*work)(void* arg), void* arg) AUTORTFM_NOEXCEPT;
388#else
395
400#endif
401
402#if UE_AUTORTFM_ENABLED
403UE_AUTORTFM_API void* autortfm_did_allocate(void* ptr, size_t size) AUTORTFM_NOEXCEPT;
404#else
406{
407 UE_AUTORTFM_UNUSED(size);
408 return ptr;
409}
410#endif
411
412#if UE_AUTORTFM_ENABLED
414#else
419#endif
420
421// If running with AutoRTFM enabled, then perform an ABI check between the
422// AutoRTFM compiler and the AutoRTFM runtime, to ensure that memory is being
423// laid out in an identical manner between the AutoRTFM runtime and the AutoRTFM
424// compiler pass. Should not be called manually by the user, a call to this will
425// be injected by the compiler into a global constructor in the AutoRTFM compiled
426// code.
427#if UE_AUTORTFM_ENABLED
428UE_AUTORTFM_API void autortfm_check_abi(void* ptr, size_t size) AUTORTFM_NOEXCEPT;
429#else
435#endif
436
437#if UE_AUTORTFM_ENABLED
438// Called when execution unexpectedly reaches a code path that was considered unreachable.
439// Either aborts execution of the program or aborts the current transaction, depending on the
440// current 'InternalAbortAction' state.
442#else
447#endif
448
449#ifdef __cplusplus
450}
451
452namespace AutoRTFM
453{
454
455// The transaction result provides information on how a transaction completed. This is either Committed,
456// or one of the various AbortedBy* variants to show why an abort occurred.
457enum class ETransactionResult
458{
459 // The transaction aborted because of an explicit call to AbortTransaction or RollbackTransaction.
461
462 // The transaction aborted because of unhandled constructs in the code (atomics, unhandled function calls, etc).
464
465 // The transaction committed successfully. For a nested transaction this does not mean that the transaction effects
466 // cannot be undone later if the parent transaction is aborted for any reason.
468
469 // The transaction aborted because a new transaction nest was attempted (via OnCommit or OnComplete) while the
470 // current transaction was being committed.
472
473 // The transaction aborted because a new transaction nest was attempted (via OnAbort or OnComplete) while the
474 // current transaction was being aborted.
476
477 // The transaction aborted because of an explicit call to CascadingAbortTransaction.
479};
480
481// The context status shows what state the AutoRTFM context is currently in.
482enum class EContextStatus : uint8_t
483{
484 // An Idle status means we are not in transactional code.
486
487 // An OnTrack status means we are in transactional code.
489
490 // Reserved for a full STM future.
492
493 // An AbortedByLanguage status means that we found some unhandled constructs in the code
494 // (atomics, unhandled function calls, etc) and are currently aborting because of it.
496
497 // An AbortedByRequest status means that a call to AbortTransaction or RollbackTransaction occurred,
498 // and we are currently aborting because of it.
500
501 // A Committing status means we are currently attempting to commit a transaction.
503
504 // An AbortedByCascadingAbort status means that a call to CascadingAbortTransaction or
505 // CascadingRollbackTransaction occurred, and we are currently aborting because of it.
507
508 // An AbortedByCascadingRetry status means that a call to CascadingRetryTransaction occurred,
509 // and we are currently aborting because of it.
511
512 // Means we are in a static local initializer which always run in the open.
513 // `IsTransactional()` will return `false` when in this state.
515};
516
517// Returns true if Status represents one of the "aborting" states.
518inline bool IsStatusAborting(EContextStatus Status)
519{
520 switch (Status)
521 {
522 case EContextStatus::AbortedByFailedLockAcquisition:
523 case EContextStatus::AbortedByLanguage:
524 case EContextStatus::AbortedByRequest:
525 case EContextStatus::AbortedByCascadingAbort:
526 case EContextStatus::AbortedByCascadingRetry:
527 return true;
528 case EContextStatus::Idle:
529 case EContextStatus::OnTrack:
530 case EContextStatus::Committing:
531 case EContextStatus::InStaticLocalInitializer:
532 return false;
533 }
534}
535
536// An opaque unique identifier for a transaction.
538
539// An enumerator of transactional memory validation levels.
540// Memory validation is used to detect modification by open-code to memory that was written by a
541// transaction. In this situation, aborting the transaction can corrupt memory as the undo will
542// overwrite the writes made in the open-code.
544{
545 // The default memory validation level.
547
548 // Disable memory validation.
550
551 // Memory validation enabled as warnings.
553
554 // Memory validation enabled as errors.
556};
557
558#if UE_AUTORTFM
559namespace ForTheRuntime
560{
565 UE_AUTORTFM_API void OnCommitInternal(TTask<void()>&& Work);
566 UE_AUTORTFM_API void OnPreAbortInternal(TTask<void()>&& Work);
567 UE_AUTORTFM_API void OnAbortInternal(TTask<void()>&& Work);
568 UE_AUTORTFM_API void OnCompleteInternal(TTask<void()>&& Work);
569 UE_AUTORTFM_API void PushOnCommitHandlerInternal(const void* Key, TTask<void()>&& Work);
570 UE_AUTORTFM_API void PopOnCommitHandlerInternal(const void* Key);
572 UE_AUTORTFM_API void PushOnAbortHandlerInternal(const void* Key, TTask<void()>&& Work);
573 UE_AUTORTFM_API void PopOnAbortHandlerInternal(const void* Key);
575 UE_AUTORTFM_API void RegisterOnCommitFromTheOpen(TTask<void()>&& Work);
576 UE_AUTORTFM_API void RegisterOnAbortFromTheOpen(TTask<void()>&& Work);
579} // namespace ForTheRuntime
580#endif
581
582template<typename FunctorType>
583void AutoRTFMFunctorInvoker(void* Arg) { (*static_cast<const FunctorType*>(Arg))(); }
584
585#if UE_AUTORTFM
587
588template<typename FunctorType>
589auto AutoRTFMLookupInstrumentedFunctorInvoker(const FunctorType& Functor) -> void(*)(void*)
590{
591 // keep this as a single expression to help ensure that even Debug builds optimize this.
592 // if we put intermediate results in local variables then the compiler emits loads
593 // and stores to the stack which confuse our custom pass that tries to strip away
594 // the actual call to autortfm_lookup_function
595 void (*Result)(void*) = reinterpret_cast<void(*)(void*)>(autortfm_lookup_function(reinterpret_cast<void*>(&AutoRTFMFunctorInvoker<FunctorType>), "AutoRTFMLookupInstrumentedFunctorInvoker"));
596 return Result;
597}
598#else
599template<typename FunctorType>
600auto AutoRTFMLookupInstrumentedFunctorInvoker(const FunctorType& Functor) -> void(*)(void*)
601{
602 return nullptr;
603}
604#endif
605
606// Tells if we are currently running in a transaction. This will return true in an open nest
607// (see `Open`). This function is handled specially in the compiler and will be constant folded
608// as true in closed code, or preserved as a function call in open code.
609UE_AUTORTFM_CRITICAL_INLINE_ALWAYS bool IsTransactional() { return autortfm_is_transactional(); }
610
611// Tells if we are currently running in the closed nest of a transaction. By default,
612// transactional code is in a closed nest; the only way to be in an open nest is to request it
613// via `Open`. This function is handled specially in the compiler and will be constant folded
614// as true in closed code, and false in open code.
615UE_AUTORTFM_CRITICAL_INLINE_ALWAYS bool IsClosed() { return autortfm_is_closed(); }
616
617// Tells us if we are currently committing a transaction. This will return true
618// when inside an on-commit handler.
620
621// Tells us if we are currently committing or aborting a transaction. This will return true
622// when inside an on-abort, on-commit or on-complete handler.
624
625// Tells us if we are currently retrying a transaction. This will return true when inside an
626// on-abort or on-complete handler that was triggered by CascadingRetryTransaction.
628
629// Returns true if the passed-in pointer is on the stack of the currently-executing transaction.
630// This is occasionally necessary when writing OnAbort handlers for objects on the stack, since
631// we don't want to scribble on stack memory that might have been reused.
633{
635}
636
637// Returns an opaque identifier for the current transaction.
639{
641}
642
643// Run the functor in a transaction. Memory writes and other side effects get instrumented
644// and will be reversed if the transaction aborts.
645//
646// If this begins a nested transaction, the instrumented effects are logged onto the root
647// transaction, so the effects can be reversed later if the root transaction aborts, even
648// if this nested transaction succeeds.
649//
650// If AutoRTFM is disabled, the code will be ran non-transactionally.
651template<typename FunctorType>
652UE_AUTORTFM_CRITICAL_INLINE ETransactionResult Transact(const FunctorType& Functor)
653{
655 static_cast<ETransactionResult>(
659 const_cast<void*>(static_cast<const void*>(&Functor))));
660
661 return Result;
662}
663
664// This is just like calling Transact([&] { Open([&] { Functor(); }); });
665// The reason we expose it is that it allows the caller's module to not
666// be compiled with the AutoRTFM instrumentation of functions if the only
667// thing that's being invoked is a function in the open.
668template<typename FunctorType>
670{
672 static_cast<ETransactionResult>(
676 const_cast<void*>(static_cast<const void*>(&Functor))));
677
678 return Result;
679}
680
681// Run the callback in a transaction like Transact, but abort program
682// execution if the result is anything other than autortfm_committed.
683// Useful for testing.
684template<typename FunctorType>
685UE_AUTORTFM_CRITICAL_INLINE void Commit(const FunctorType& Functor)
686{
690 const_cast<void*>(static_cast<const void*>(&Functor)));
691}
692
693// Ends a transaction while in the closed, discarding all effects.
694// Sends control to the end of the transaction immediately.
696{
698}
699
700// End a transaction nest in the closed, discarding all effects. This cascades,
701// meaning an abort of a nested transaction will cause all transactions in the
702// nest to abort. Once the transaction has aborted, on-complete callbacks will
703// be invoked. Finally, control will be returned to the end of the outermost
704// Transact.
705#if UE_AUTORTFM
707{
708 ForTheRuntime::CascadingAbortTransactionInternal();
709}
710#else
712#endif
713
714namespace Detail
715{
716template<typename T, typename = void>
717struct THasAssignFromOpenToClosedMethod : std::false_type {};
718template<typename T>
719struct THasAssignFromOpenToClosedMethod<T, std::void_t<decltype(T::AutoRTFMAssignFromOpenToClosed(std::declval<T&>(), std::declval<T>()))>> : std::true_type {};
720}
721
722// Evaluates to true if the type T has a static method with the signature:
723// static void AutoRTFMAssignFromOpenToClosed(T& Closed, U Open)
724// Where `U` is `T`, `const T&` or `T&&`. Supports both copy assignment and move assignment.
725template<typename T>
726static constexpr bool HasAssignFromOpenToClosedMethod = Detail::THasAssignFromOpenToClosedMethod<T>::value;
727
728// Template class used to declare a method for safely copying or moving an
729// object of type T from open to closed transactions.
730// Specializations of TAssignFromOpenToClosed must have at least one static
731// method with the signature:
732// static void Assign(T& Closed, U Open);
733// Where `U` is `T`, `const T&` or `T&&`. Supports both copy assignment and move assignment.
734//
735// TAssignFromOpenToClosed has pre-declared specializations for basic primitive
736// types, and can be extended with user-declared template specializations.
737//
738// TAssignFromOpenToClosed has a pre-declared specialization that detects and
739// calls a static method on T with the signature:
740// static void AutoRTFMAssignFromOpenToClosed(T& Closed, U Open)
741// Where `U` is `T`, `const T&` or `T&&`. Supports both copy assignment and move assignment.
742template<typename T, typename = void>
744
745namespace Detail
746{
747template<typename T, typename = void>
748struct THasAssignFromOpenToClosedTrait : std::false_type {};
749template<typename T>
750struct THasAssignFromOpenToClosedTrait<T, std::void_t<decltype(TAssignFromOpenToClosed<T>::Assign(std::declval<T&>(), std::declval<T>()))>> : std::true_type {};
751}
752
753// Evaluates to true if the type T supports assigning from open to closed transactions.
754template<typename T>
755static constexpr bool HasAssignFromOpenToClosedTrait = Detail::THasAssignFromOpenToClosedTrait<T>::value;
756
757// Specialization of TAssignFromOpenToClosed for fundamental types.
758template<typename T>
759struct TAssignFromOpenToClosed<T, std::enable_if_t<std::is_fundamental_v<T>>>
760{
761 UE_AUTORTFM_FORCEINLINE static void Assign(T& Closed, T Open) { Closed = Open; }
762};
763
764// Specialization of TAssignFromOpenToClosed for raw pointer types.
765template<typename T>
766struct TAssignFromOpenToClosed<T*, void>
767{
768 UE_AUTORTFM_FORCEINLINE static void Assign(T*& Closed, T* Open) { Closed = Open; }
769};
770
771// Specialization of TAssignFromOpenToClosed for std::tuple.
772template<typename ... TYPES>
773struct TAssignFromOpenToClosed<std::tuple<TYPES...>, std::enable_if_t<(HasAssignFromOpenToClosedTrait<TYPES> && ...)>>
774{
775 template<size_t I = 0, typename SRC = void>
776 UE_AUTORTFM_FORCEINLINE static void AssignElements(std::tuple<TYPES...>& Closed, SRC&& Open)
777 {
778 if constexpr(I < sizeof...(TYPES))
779 {
780 using E = std::tuple_element_t<I, std::tuple<TYPES...>>;
781 TAssignFromOpenToClosed<E>::Assign(std::get<I>(Closed), std::get<I>(std::forward<SRC>(Open)));
782 AssignElements<I+1>(Closed, std::forward<SRC>(Open));
783 }
784 }
785
786 template<typename SRC>
787 UE_AUTORTFM_FORCEINLINE static void Assign(std::tuple<TYPES...>& Closed, SRC&& Open)
788 {
789 AssignElements(Closed, std::forward<SRC>(Open));
790 }
791};
792
793// Specialization of TAssignFromOpenToClosed for types that have a static method
794// with the signature:
795// static void AutoRTFMAssignFromOpenToClosed(T& Closed, U Open)
796// Where `U` is `T`, `const T&` or `T&&`. Supports both copy assignment and move assignment.
797template<typename T>
798struct TAssignFromOpenToClosed<T, std::enable_if_t<HasAssignFromOpenToClosedMethod<T>>>
799{
800 template<typename OPEN>
802 {
803 Closed.AutoRTFMAssignFromOpenToClosed(Closed, std::forward<OPEN>(Open));
804 }
805};
806
807// Specialization of TAssignFromOpenToClosed for `void` (used to make IsSafeToReturnFromOpen<void> work).
808template<>
810
811// Evaluates to true if the type T is safe to return from Open().
812template<typename T>
813static constexpr bool IsSafeToReturnFromOpen = HasAssignFromOpenToClosedTrait<T> || std::is_same_v<T, void>;
814
815// Executes the given code non-transactionally regardless of whether we are in
816// a transaction or not. Returns the value returned by Functor.
817// ReturnType must be void or a type that can be safely copied from the open to a closed transaction.
818// TAssignFromOpenToClosed must have a specialization for the type that is being returned.
819template
820<
821 EMemoryValidationLevel VALIDATION_LEVEL = EMemoryValidationLevel::Default,
822 typename FunctorType = void,
823 typename ReturnType = decltype(std::declval<FunctorType>()())
824>
825UE_AUTORTFM_CRITICAL_INLINE ReturnType Open(const FunctorType& Functor)
826{
828 "function return type is not safe to return from Open()");
829#if UE_AUTORTFM
830 if (!autortfm_is_closed())
831 {
832 return Functor();
833 }
834
836 {
837 if constexpr (std::is_same_v<void, ReturnType>)
838 {
839 struct FCallHelper
840 {
841 AUTORTFM_DISABLE static void Call(void* Arg)
842 {
843 const FunctorType& Fn = *reinterpret_cast<FunctorType*>(Arg);
845 }
846 };
847
848 if constexpr (VALIDATION_LEVEL == EMemoryValidationLevel::Default)
849 {
850 autortfm_open(&FCallHelper::Call, const_cast<void*>(reinterpret_cast<const void*>(&Functor)), __builtin_return_address(0));
851 }
852 else
853 {
856 &FCallHelper::Call,
857 const_cast<void*>(static_cast<const void*>(&Functor)),
859 }
860 }
861 else
862 {
863 struct FCallHelper
864 {
865 AUTORTFM_DISABLE static void Call(void* Arg)
866 {
867 FCallHelper& Self = *reinterpret_cast<FCallHelper*>(Arg);
869 TAssignFromOpenToClosed<ReturnType>::Assign(Self.ReturnValue, std::move(Self.Functor()));
870 }
871 const FunctorType& Functor;
872 ReturnType ReturnValue{};
873 };
874 FCallHelper Helper{Functor};
875 if constexpr (VALIDATION_LEVEL == EMemoryValidationLevel::Default)
876 {
877 autortfm_open(&FCallHelper::Call, reinterpret_cast<void*>(&Helper), __builtin_return_address(0));
878 }
879 else
880 {
883 &FCallHelper::Call,
884 reinterpret_cast<void*>(&Helper),
886 }
887 return Helper.ReturnValue;
888 }
889 }
890#else // UE_AUTORTFM
891 return Functor();
892#endif // UE_AUTORTFM
893}
894
895// Always executes the given code transactionally when called from a transaction nest
896// (whether we are in open or closed code).
897//
898// Will crash if called outside of a transaction nest.
899//
900// If Close() returns an aborting status (see IsStatusAborting()), then
901// attempting to use the transaction is undefined behaviour. The caller should
902// return to the closed as quickly as possible to avoid the risk of the
903// transaction being used in its rolled-back state.
904template<typename FunctorType> [[nodiscard]] UE_AUTORTFM_CRITICAL_INLINE EContextStatus Close(const FunctorType& Functor)
905{
906 return static_cast<EContextStatus>(
910 const_cast<void*>(static_cast<const void*>(&Functor))));
911}
912
913// Force a transaction nest to be retried. Once the transaction has aborted,
914// all on-complete handlers will be called before retrying the transaction.
915// This is an expensive operation and should thus be used with extreme caution.
916// If this is called outside of a transaction, the call is ignored.
917#if UE_AUTORTFM
919{
920 if (autortfm_is_closed())
921 {
922 ForTheRuntime::CascadingRetryTransactionInternal();
923 }
924}
925#else
927{
928}
929#endif
930
931#if UE_AUTORTFM
932// Have some work happen when this transaction commits.
933// In a nested transaction, the work is deferred until the outermost nest is committed;
934// at that point, the worklist is run in FIFO order.
935// If this is called outside a transaction or from an open nest, then the work
936// happens immediately.
937template<typename FunctorType> UE_AUTORTFM_CRITICAL_INLINE void OnCommit(FunctorType&& Work)
938{
939 if (autortfm_is_closed())
940 {
941 ForTheRuntime::OnCommitInternal(std::forward<FunctorType>(Work));
942 }
943 else
944 {
946 }
947}
948#else
949template<typename FunctorType> UE_AUTORTFM_CRITICAL_INLINE void OnCommit(FunctorType&& Work) { Work(); }
950#endif
951
952#if UE_AUTORTFM
953// Have some work happen when this transaction aborts (before memory rollback).
954// If an abort occurs, the work list is run in LIFO order.
955// If this is called outside a transaction or from an open nest then the work is ignored.
956template<typename FunctorType> UE_AUTORTFM_CRITICAL_INLINE void OnPreAbort(FunctorType&& Work)
957{
958 if (autortfm_is_closed())
959 {
960 ForTheRuntime::OnPreAbortInternal(std::forward<FunctorType>(Work));
961 }
962}
963#else
964template<typename FunctorType> UE_AUTORTFM_CRITICAL_INLINE void OnPreAbort(FunctorType&&) {}
965#endif
966
967#if UE_AUTORTFM
968// Have some work happen when this transaction aborts (after memory rollback).
969// If an abort occurs, the work list is run in LIFO order.
970// If this is called outside a transaction or from an open nest then the work is ignored.
971template<typename FunctorType> UE_AUTORTFM_CRITICAL_INLINE void OnAbort(FunctorType&& Work)
972{
973 if (autortfm_is_closed())
974 {
975 ForTheRuntime::OnAbortInternal(std::forward<FunctorType>(Work));
976 }
977}
978#else
979template<typename FunctorType> UE_AUTORTFM_CRITICAL_INLINE void OnAbort(FunctorType&&) {}
980#endif
981
982#if UE_AUTORTFM
983// Have some work happen when the transaction completes, whether that transaction is committed or aborted.
984// In a nested transaction, the work is deferred until the very end of the outermost nest, right before
985// the end of the transaction.
986// The worklist is run in FIFO order, after the OnCommit or OnAbort worklist has finished.
987// If this is called outside a transaction or from an open nest, then the work is ignored.
988template<typename FunctorType> UE_AUTORTFM_CRITICAL_INLINE void OnComplete(FunctorType&& Work)
989{
990 if (autortfm_is_closed())
991 {
992 ForTheRuntime::OnCompleteInternal(std::forward<FunctorType>(Work));
993 }
994}
995#else
996template<typename FunctorType> UE_AUTORTFM_CRITICAL_INLINE void OnComplete(FunctorType&&) {}
997#endif
998
999#if UE_AUTORTFM
1000// Register a handler for transaction commit. Takes a key parameter so that
1001// the handler can be unregistered (see `PopOnCommitHandler`). This is useful
1002// for scoped mutations that need an abort handler present unless execution
1003// reaches the end of the relevant scope.
1004template<typename FunctorType> UE_AUTORTFM_CRITICAL_INLINE void PushOnCommitHandler(const void* Key, FunctorType&& Work)
1005{
1006 if (autortfm_is_closed())
1007 {
1008 ForTheRuntime::PushOnCommitHandlerInternal(Key, std::forward<FunctorType>(Work));
1009 }
1010}
1011#else
1012// Register a handler for transaction commit. Takes a key parameter so that
1013// the handler can be unregistered (see `PopOnCommitHandler`). This is useful
1014// for scoped mutations that need an abort handler present unless execution
1015// reaches the end of the relevant scope.
1016template<typename FunctorType> UE_AUTORTFM_CRITICAL_INLINE void PushOnCommitHandler(const void*, FunctorType&&) {}
1017#endif
1018
1019#if UE_AUTORTFM
1020// Unregister the most recently pushed handler (via `PushOnCommitHandler`) for the given key.
1022{
1023 if (autortfm_is_closed())
1024 {
1025 ForTheRuntime::PopOnCommitHandlerInternal(Key);
1026 }
1027}
1028#else
1029// Unregister the most recently pushed handler (via `PushOnCommitHandler`) for the given key.
1031#endif
1032
1033#if UE_AUTORTFM
1034// Unregister all pushed handlers (via `PushOnCommitHandler`) for the given key.
1036{
1037 if (autortfm_is_closed())
1038 {
1039 ForTheRuntime::PopAllOnCommitHandlersInternal(Key);
1040 }
1041}
1042#else
1043// Unregister all pushed handlers (via `PushOnCommitHandler`) for the given key.
1045#endif
1046
1047#if UE_AUTORTFM
1048// Register a handler for transaction abort. Takes a key parameter so that
1049// the handler can be unregistered (see `PopOnAbortHandler`). This is useful
1050// for scoped mutations that need an abort handler present unless execution
1051// reaches the end of the relevant scope.
1052template<typename FunctorType> UE_AUTORTFM_CRITICAL_INLINE void PushOnAbortHandler(const void* Key, FunctorType&& Work)
1053{
1054 if (autortfm_is_closed())
1055 {
1056 ForTheRuntime::PushOnAbortHandlerInternal(Key, std::forward<FunctorType>(Work));
1057 }
1058}
1059#else
1060// Register a handler for transaction abort. Takes a key parameter so that
1061// the handler can be unregistered (see `PopOnAbortHandler`). This is useful
1062// for scoped mutations that need an abort handler present unless execution
1063// reaches the end of the relevant scope.
1064template<typename FunctorType> UE_AUTORTFM_CRITICAL_INLINE void PushOnAbortHandler(const void* Key, FunctorType&&) {}
1065#endif
1066
1067#if UE_AUTORTFM
1068// Unregister the most recently pushed handler (via `PushOnAbortHandler`) for the given key.
1070{
1071 if (autortfm_is_closed())
1072 {
1073 ForTheRuntime::PopOnAbortHandlerInternal(Key);
1074 }
1075}
1076#else
1077// Unregister the most recently pushed handler (via `PushOnAbortHandler`) for the given key.
1079{
1080 UE_AUTORTFM_UNUSED(Key);
1081}
1082#endif
1083
1084#if UE_AUTORTFM
1085// Unregister all pushed handlers (via `PushOnAbortHandler`) for the given key.
1087{
1088 if (autortfm_is_closed())
1089 {
1090 ForTheRuntime::PopAllOnAbortHandlersInternal(Key);
1091 }
1092}
1093#else
1094// Unregister all pushed handlers (via `PushOnAbortHandler`) for the given key.
1096{
1097 UE_AUTORTFM_UNUSED(Key);
1098}
1099#endif
1100
1102{
1105 void (*RedirectedStore)(uint64_t DestAddress, uint64_t Size, const void* SourcePointer);
1106};
1107
1108#if UE_AUTORTFM
1110#else
1112{
1113}
1114#endif
1115
1116// Inform the runtime that we have performed a new object allocation. It's only
1117// necessary to call this inside of custom malloc implementations. As an
1118// optimization, you can choose to then only have your malloc return the pointer
1119// returned by this function. It's guaranteed to be equal to the pointer you
1120// passed, but it's blessed specially from the compiler's perspective, leading
1121// to some nice optimizations. This does nothing when called from open code.
1122UE_AUTORTFM_CRITICAL_INLINE void* DidAllocate(void* Ptr, size_t Size)
1123{
1124 return autortfm_did_allocate(Ptr, Size);
1125}
1126
1127// Inform the runtime that we have free'd a given memory location.
1129{
1130 autortfm_did_free(Ptr);
1131}
1132
1133// Informs the runtime that a block of memory is about to be overwritten in the open.
1134// During a transaction, this allows the runtime to copy the data in preparation for
1135// a possible abort. Normally, tracking memory overwrites should be automatically
1136// handled by AutoRTFM, but manual overwrite tracking may be required for third-party
1137// libraries or outside compilers (such as ISPC).
1138UE_AUTORTFM_CRITICAL_INLINE void RecordOpenWrite(void* Ptr, size_t Size)
1139{
1141}
1142
1143// Informs the runtime that a block of memory is about to be overwritten in the open.
1144// During a transaction, this allows the runtime to copy the data in preparation for
1145// a possible abort. Normally, tracking memory overwrites should be automatically
1146// handled by AutoRTFM, but manual overwrite tracking may be required for third-party
1147// libraries or outside compilers (such as ISPC).
1148template<typename Type> UE_AUTORTFM_CRITICAL_INLINE void RecordOpenWrite(Type* Ptr)
1149{
1150 autortfm_record_open_write(Ptr, sizeof(Type));
1151}
1152
1153// Same as RecordOpenWrite() but marks the write as ignorable by the memory validator.
1155{
1157}
1158
1159// Same as RecordOpenWrite() but marks the write as ignorable by the memory validator.
1160template<typename Type> UE_AUTORTFM_CRITICAL_INLINE void RecordOpenWriteNoMemoryValidation(Type* Ptr)
1161{
1163}
1164
1165// Report that a unreachable codepath is being hit. Used to manually ban certain codepaths
1166// from being transactionally safe.
1167#if UE_AUTORTFM_ENABLED
1168[[noreturn]] UE_AUTORTFM_CRITICAL_INLINE_ALWAYS void Unreachable(const char* Message = nullptr)
1169{
1170 autortfm_unreachable(Message);
1171}
1172#else
1173UE_AUTORTFM_CRITICAL_INLINE void Unreachable(const char* Message = nullptr)
1174{
1175 UE_AUTORTFM_UNUSED(Message);
1176}
1177#endif
1178
1179// If we are running within a transaction, call `AutoRTFM::Unreachable`.
1180UE_AUTORTFM_CRITICAL_INLINE_ALWAYS void UnreachableIfTransactional(const char* Message = nullptr)
1181{
1182 if (AutoRTFM::IsTransactional())
1183 {
1184 AutoRTFM::Unreachable(Message);
1185 }
1186}
1187
1188// If we are running within a closed transaction, call `AutoRTFM::Unreachable`.
1189UE_AUTORTFM_CRITICAL_INLINE_ALWAYS void UnreachableIfClosed(const char* Message = nullptr)
1190{
1191 if (AutoRTFM::IsClosed())
1192 {
1193 AutoRTFM::Unreachable(Message);
1194 }
1195}
1196
1197// Evaluates to true if a call to the function with type FuncType with arguments
1198// of the given types resolves to a function overload that is AutoRTFM-disabled.
1199// Warning: This is an experimental API and may be removed in the future.
1200template <typename FuncType, typename ... ArgTypes>
1201static constexpr bool CallIsDisabled = AUTORTFM_CALL_IS_DISABLED(std::declval<FuncType>()(std::declval<ArgTypes>()...));
1202
1203// Evaluates to true if the destructor of type Type is AutoRTFM-disabled.
1204// Warning: This is an experimental API and may be removed in the future.
1205template <typename Type>
1206static constexpr bool DestructorIsDisabled = AUTORTFM_CALL_IS_DISABLED(std::declval<Type>().~Type());
1207
1208// Evaluates to true if the constructor of Type with the given arguments is AutoRTFM-disabled.
1209// Warning: This is an experimental API and may be removed in the future.
1210template <typename Type, typename ... ArgTypes>
1211static constexpr bool ConstructorIsDisabled = AUTORTFM_CALL_IS_DISABLED(::new Type(std::declval<ArgTypes>()...));
1212
1213// A collection of power-user functions that are reserved for use by the AutoRTFM runtime only.
1214namespace ForTheRuntime
1215{
1216 // An enum to represent the various ways we want to enable/disable the AutoRTFM runtime.
1217 // This enum has effective groups of functionality such that if a higher priority group
1218 // has enabled or disabled the runtime, a lower priority group cannot then override that.
1219 //
1220 // We have from higher to lower priority:
1221 // - Forced Enabled/Disabled - used by CVars when force enabling/disabling AutoRTFM.
1222 // - Override Enabled/Disabled - override any setting of enabled/disabled as was set by a CVar.
1223 // - Enabled/Disabled - used by CVars when enabling/disabling AutoRTFM.
1224 // - Default Enabled/Disabled - whether we should be enabled or disabled by default (used for different backend executables).
1225 //
1226 // For example the following would be valid:
1227 // - At compile time the state is compiled in as default disabled.
1228 // - The CVar is set to enabled, so we switch the state to enabled.
1229 // - At runtime we detect a mode where we want AutoRTFM and try to switch the default to enabled, but the CVar already enabled it so this is ignored.
1230 // - Then for a given codepath we override AutoRTFM to disabled so we switch the state to disabled.
1232 {
1233 // Disable AutoRTFM.
1235
1236 // Enable AutoRTFM.
1238
1239 // Force disable AutoRTFM.
1241
1242 // Force enable AutoRTFM.
1244
1245 // Whether our default is to be disabled.
1247
1248 // Whether our default is to be enabled.
1250
1251 // Whether we've overridden and AutoRTFM is disabled.
1253
1254 // Whether we've overridden and AutoRTFM is enabled.
1256 };
1257
1258 // An enum to represent whether we should abort and retry transactions (for testing purposes).
1260 {
1261 // Do not abort and retry transactions (the default).
1262 NoRetry = 0,
1263
1264 // Abort and retry non-nested transactions (EG. only abort the parent transactional nest).
1266
1267 // Abort and retry nested-transactions too. Will be slower as each nested-transaction will
1268 // be aborted and retried at least *twice* (once when the non-nested transaction runs the
1269 // first time, and a second time when the non-nested transaction is doing its retry after
1270 // aborting).
1272 };
1273
1275 {
1276 // Crash the process if we hit an internal AutoRTFM abort.
1277 Crash = 0,
1278
1279 // Just do a normal transaction abort and let the runtime recover (used to test aborting codepaths).
1280 Abort,
1281 };
1282
1283 // Set whether the AutoRTFM runtime is enabled or disabled. Returns true when the state was changed
1284 // successfully.
1286
1288
1289 // Query whether the AutoRTFM runtime is enabled.
1291 {
1292 // If we are already in the closed nest of a transaction, we must have our runtime enabled!
1293 if (AutoRTFM::IsClosed())
1294 {
1295 return true;
1296 }
1297
1299 }
1300
1301 // Set the percentage [0..100] chance that a call to `CoinTossDisable` will end up disabling AutoRTFM.
1302 // 100% means never disable via coin-toss, 0% means always disable. So passing `0.1` means disable
1303 // all but 1/1000's calls via `CoinTossDisable`.
1305
1306 // Get the enabled probability set via `SetAutoRTFMEnabledProbability`.
1308
1309 // Call to randomly disable AutoRTFM with a probability set with `SetAutoRTFMEnabledProbability`.
1310 // Returns true if AutoRTFM was disabled by this call.
1312
1314
1316
1318 UE_AUTORTFM_API void SetEnsureOnInternalAbort(bool bEnabled);
1319
1320 // Set whether we should trigger an ensure on an abort-by-language.
1321 [[deprecated("Use `SetEnsureOnInternalAbort` instead!")]]
1322 inline void SetEnsureOnAbortByLanguage(bool bEnabled)
1323 {
1324 SetEnsureOnInternalAbort(bEnabled);
1325 }
1326
1327 // Returns whether the runtime will trigger an ensure on an abort-by-language, or not.
1328 [[deprecated("Use `GetEnsureOnInternalAbort` instead!")]]
1330 {
1331 return GetEnsureOnInternalAbort();
1332 }
1333
1334 // Returns whether we want to assert or ensure on a Language Error
1335 [[deprecated("Use `GetInternalAbortAction` instead!")]]
1336 inline bool IsAutoRTFMAssertOnError()
1337 {
1338 return EAutoRTFMInternalAbortActionState::Crash == GetInternalAbortAction();
1339 }
1340
1341 // Set whether we should retry transactions.
1343
1344 // Returns whether we should retry transactions.
1346
1347 // Returns true if we should retry non-nested transactions.
1349
1350 // Returns true if we should also retry nested transactions.
1352
1353 // Returns the memory validation level currently enabled.
1355
1356 // Sets the memory validation level. See IsWriteValidationEnabled().
1358
1359 // Returns true if the memory validation throttling is enabled.
1361
1362 // Sets the memory validation throttling mode.
1364
1365 // Returns true if the memory validation statistics are enabled.
1367
1368 // Sets whether memory validation statistics are logged or not.
1370
1371 // A debug helper that will break to the debugger if the hash of the memory
1372 // write locations no longer matches the hash recorded when the transaction
1373 // was opened. Useful for isolating where the open write happened.
1374 // Requires the memory validation to be enabled to be called.
1376
1377 // Manually create a new transaction from open code and push it as a transaction nest.
1378 // Can only be called within an already active parent transaction (EG. this cannot start
1379 // a transaction nest itself).
1381
1382 // Manually commit the top transaction nest, popping it from the execution scope.
1383 // Can only be called within an already active parent transaction (EG. this cannot end
1384 // a transaction nest itself).
1386
1387 // Manually clear the status of a user abort from the top transaction in a nest.
1389
1390 // Returns the current transaction status.
1392
1393 // RollbackTransaction() aborts the current transaction.
1394 // If the transaction is scoped, then this is kept on the transaction stack
1395 // until we return to the closed. Attempting to use this transaction before
1396 // transitioning to the closed is undefined behaviour.
1397 // If the transaction is unscoped, then this is popped immediately.
1398 // RollbackTransaction() sets the transaction status to AbortedByRequest.
1400
1401 // CascadingAbortRollbackTransaction() rolls back the current scoped
1402 // transaction, which must be a scoped transaction (i.e. created by
1403 // AutoRTFM::Transact() and not by StartTransaction()).
1404 // CascadingAbortRollbackTransaction() sets the transaction status to
1405 // AbortedByCascadingAbort, which will cause the next open -> closed
1406 // transition point to abort all transactions on the transaction nest.
1407 // Attempting to use any transactions in the open while unwinding is
1408 // undefined behaviour.
1410
1411 // CascadingRetryRollbackTransaction() rolls back the current scoped
1412 // transaction, which must be a scoped transaction (i.e. created by
1413 // AutoRTFM::Transact() and not by StartTransaction()).
1414 // CascadingRetryRollbackTransaction() sets the transaction status to
1415 // AbortedByCascadingRetry, which will cause the next open -> closed
1416 // transition point to abort all transactions on the transaction nest,
1417 // and then retry the outermost transaction.
1418 // Attempting to use any transactions in the open while unwinding is
1419 // undefined behaviour.
1421
1422 // Reserved for future.
1423 UE_AUTORTFM_CRITICAL_INLINE void RecordOpenRead(void const*, size_t) {}
1424
1425 // Reserved for future.
1426 template<typename Type> UE_AUTORTFM_CRITICAL_INLINE void RecordOpenRead(Type*) {}
1427
1428} // namespace ForTheRuntime
1429
1430} // namespace AutoRTFM
1431
1432// Macro-based variants so we completely compile away when not in use, even in debug builds
1433#if UE_AUTORTFM
1434
1435namespace AutoRTFM::Private
1436{
1437 struct FOpenHelper
1438 {
1439 template<typename FunctorType>
1440 UE_AUTORTFM_FORCEINLINE void operator+(FunctorType&& F)
1441 {
1442 AutoRTFM::Open(std::forward<FunctorType>(F));
1443 }
1444 };
1446 {
1447 template<typename FunctorType>
1448 UE_AUTORTFM_FORCEINLINE void operator+(FunctorType&& F)
1449 {
1450 AutoRTFM::Open<EMemoryValidationLevel::Disabled>(std::forward<FunctorType>(F));
1451 }
1452 };
1453 struct FCloseHelper
1454 {
1455 template<typename FunctorType>
1456 [[nodiscard]] EContextStatus operator+(FunctorType F)
1457 {
1458 return AutoRTFM::Close(std::move(F));
1459 }
1460 };
1461 struct FOnPreAbortHelper
1462 {
1463 template<typename FunctorType>
1464 UE_AUTORTFM_FORCEINLINE void operator+(FunctorType&& F)
1465 {
1466 AutoRTFM::OnPreAbort(std::forward<FunctorType>(F));
1467 }
1468 };
1469 struct FOnAbortHelper
1470 {
1471 template<typename FunctorType>
1472 UE_AUTORTFM_FORCEINLINE void operator+(FunctorType&& F)
1473 {
1474 AutoRTFM::OnAbort(std::forward<FunctorType>(F));
1475 }
1476 };
1477 struct FOnCommitHelper
1478 {
1479 template<typename FunctorType>
1480 UE_AUTORTFM_FORCEINLINE void operator+(FunctorType&& F)
1481 {
1482 AutoRTFM::OnCommit(std::forward<FunctorType>(F));
1483 }
1484 };
1485 struct FTransactHelper
1486 {
1487 template<typename FunctorType>
1488 UE_AUTORTFM_FORCEINLINE void operator+(FunctorType&& F)
1489 {
1490 AutoRTFM::Transact(std::forward<FunctorType>(F));
1491 }
1492 };
1493 namespace /* must have internal linkage */
1494 {
1495 struct FThreadLocalHelper
1496 {
1497 template <typename Type, int Unique>
1499 {
1500 thread_local Type Data;
1501 return Data;
1502 }
1503 };
1504 }
1505} // namespace AutoRTFM::Private
1506
1507#define UE_AUTORTFM_DECLARE_THREAD_LOCAL_VAR_IMPL(Type, Name) Type& Name = ::AutoRTFM::Private::FThreadLocalHelper::Get<Type, __COUNTER__>()
1508
1509#define UE_AUTORTFM_OPEN_IMPL ::AutoRTFM::Private::FOpenHelper{} + [&]()
1510#define UE_AUTORTFM_OPEN_NO_VALIDATION_IMPL ::AutoRTFM::Private::FOpenNoMemoryValidationHelper{} + [&]()
1511#define UE_AUTORTFM_CLOSE_IMPL ::AutoRTFM::Private::FCloseHelper{} + [&]()
1512#define UE_AUTORTFM_ONPREABORT_IMPL(...) ::AutoRTFM::Private::FOnPreAbortHelper{} + [__VA_ARGS__]() mutable
1513#define UE_AUTORTFM_ONABORT_IMPL(...) ::AutoRTFM::Private::FOnAbortHelper{} + [__VA_ARGS__]() mutable
1514#define UE_AUTORTFM_ONCOMMIT_IMPL(...) ::AutoRTFM::Private::FOnCommitHelper{} + [__VA_ARGS__]() mutable
1515#define UE_AUTORTFM_TRANSACT_IMPL ::AutoRTFM::Private::FTransactHelper{} + [&]()
1516#else
1517
1518// Do nothing, these should be followed by blocks that should be either executed or not executed
1519#define UE_AUTORTFM_DECLARE_THREAD_LOCAL_VAR_IMPL(Type, Name) thread_local Type Name
1520#define UE_AUTORTFM_OPEN_IMPL
1521#define UE_AUTORTFM_OPEN_NO_VALIDATION_IMPL
1522#define UE_AUTORTFM_CLOSE_IMPL
1523#define UE_AUTORTFM_ONPREABORT_IMPL(...) while (false)
1524#define UE_AUTORTFM_ONABORT_IMPL(...) while (false)
1525#define UE_AUTORTFM_ONCOMMIT_IMPL(...)
1526#define UE_AUTORTFM_TRANSACT_IMPL
1527#endif
1528
1529// Declares an AutoRTFM-aware thread local variable. `thread_local` variables are not yet natively supported (#jira SOL-7684)
1530// Calls should be written like this:
1531// UE_AUTORTFM_DECLARE_THREAD_LOCAL_VAR(FString, MyThreadLocalString);
1532// MyThreadLocalString = "Hello";
1533#define UE_AUTORTFM_DECLARE_THREAD_LOCAL_VAR(Type, Name) UE_AUTORTFM_DECLARE_THREAD_LOCAL_VAR_IMPL(Type, Name)
1534
1535// Runs a block of code in the open, non-transactionally. Anything performed in the open will not be undone if a transaction fails.
1536// Calls should be written like this: UE_AUTORTFM_OPEN { ... code ... };
1537#define UE_AUTORTFM_OPEN UE_AUTORTFM_OPEN_IMPL
1538
1539#define UE_AUTORTFM_OPEN_NO_VALIDATION UE_AUTORTFM_OPEN_NO_VALIDATION_IMPL
1540
1541// Runs a block of code in the closed, transactionally. Anything performed in the closed will be undone if a transaction fails.
1542// Calls should be written like this: UE_AUTORTFM_CLOSE { ... code ... };
1543#define UE_AUTORTFM_CLOSE UE_AUTORTFM_CLOSE_IMPL
1544
1545// Runs a block of code if a transaction aborts (before memory rollback).
1546// In non-transactional code paths the block of code will not be executed at all.
1547// The macro arguments are the capture specification for the lambda.
1548// Calls should be written like this: UE_AUTORTFM_ONPREABORT(=) { ... code ... };
1549#define UE_AUTORTFM_ONPREABORT(...) UE_AUTORTFM_ONPREABORT_IMPL(__VA_ARGS__)
1550
1551// Runs a block of code if a transaction aborts (after memory rollback).
1552// In non-transactional code paths the block of code will not be executed at all.
1553// The macro arguments are the capture specification for the lambda.
1554// Calls should be written like this: UE_AUTORTFM_ONABORT(=) { ... code ... };
1555#define UE_AUTORTFM_ONABORT(...) UE_AUTORTFM_ONABORT_IMPL(__VA_ARGS__)
1556
1557// Runs a block of code if a transaction commits successfully.
1558// In non-transactional code paths the block of code will be executed immediately.
1559// The macro arguments are the capture specification for the lambda.
1560// Calls should be written like this: UE_AUTORTFM_ONCOMMIT(=) { ... code ... };
1561#define UE_AUTORTFM_ONCOMMIT(...) UE_AUTORTFM_ONCOMMIT_IMPL(__VA_ARGS__)
1562
1563// Runs a block of code in the closed, transactionally, within a new transaction.
1564// Calls should be written like this: UE_AUTORTFM_TRANSACT { ... code ... };
1565#define UE_AUTORTFM_TRANSACT UE_AUTORTFM_TRANSACT_IMPL
1566
1567#if UE_AUTORTFM
1568#define UE_AUTORTFM_REGISTER_OPEN_TO_CLOSED_FUNCTIONS(...) \
1569 static const ::AutoRTFM::ForTheRuntime::TAutoRegisterOpenToClosedFunctions<__VA_ARGS__> UE_AUTORTFM_CONCAT(AutoRTFMFunctionRegistration, __COUNTER__)
1570#else
1571#define UE_AUTORTFM_REGISTER_OPEN_TO_CLOSED_FUNCTIONS(...)
1572#endif
1573
1574#endif // __cplusplus
OODEFFUNC typedef void(OODLE_CALLBACK t_fp_OodleCore_Plugin_Free)(void *ptr)
autortfm_memory_validation_level
Definition AutoRTFMConstants.h:19
@ autortfm_memory_validation_level_warn
Definition AutoRTFMConstants.h:27
@ autortfm_memory_validation_level_error
Definition AutoRTFMConstants.h:30
@ autortfm_memory_validation_level_default
Definition AutoRTFMConstants.h:21
@ autortfm_memory_validation_level_disabled
Definition AutoRTFMConstants.h:24
#define UE_AUTORTFM_CRITICAL_INLINE
Definition AutoRTFMDefines.h:202
#define UE_AUTORTFM_FORCENOINLINE
Definition AutoRTFMDefines.h:173
#define UE_AUTORTFM_CALLSITE_FORCEINLINE
Definition AutoRTFMDefines.h:126
#define AUTORTFM_EXCEPT
Definition AutoRTFMDefines.h:135
#define UE_AUTORTFM_UNUSED(UNUSEDVAR)
Definition AutoRTFMDefines.h:197
#define AUTORTFM_CALL_IS_DISABLED(EXPR_OR_TYPE)
Definition AutoRTFMDefines.h:125
#define AUTORTFM_DISABLE
Definition AutoRTFMDefines.h:116
#define UE_AUTORTFM_FORCEINLINE
Definition AutoRTFMDefines.h:171
#define AUTORTFM_DISABLE_UNREACHABLE_CODE_WARNINGS
Definition AutoRTFMDefines.h:193
#define UE_AUTORTFM_API
Definition AutoRTFMDefines.h:156
#define UE_AUTORTFM_CRITICAL_INLINE_ALWAYS
Definition AutoRTFMDefines.h:203
#define AUTORTFM_OPEN
Definition AutoRTFMDefines.h:122
#define AUTORTFM_RESTORE_UNREACHABLE_CODE_WARNINGS
Definition AutoRTFMDefines.h:194
#define UE_AUTORTFM_ALWAYS_OPEN
Definition AutoRTFMDefines.h:114
#define AUTORTFM_NOEXCEPT
Definition AutoRTFMDefines.h:134
uint64_t autortfm_transaction_id
Definition AutoRTFM.h:86
UE_AUTORTFM_CRITICAL_INLINE void autortfm_commit(void(*UninstrumentedWork)(void *), void(*InstrumentedWork)(void *), void *Arg)
Definition AutoRTFM.h:238
UE_AUTORTFM_CRITICAL_INLINE autortfm_result autortfm_commit_transaction() AUTORTFM_NOEXCEPT
Definition AutoRTFM.h:260
UE_AUTORTFM_CRITICAL_INLINE void autortfm_did_free(void *ptr) AUTORTFM_NOEXCEPT
Definition AutoRTFM.h:415
UE_AUTORTFM_CRITICAL_INLINE bool autortfm_is_transactional(void) AUTORTFM_NOEXCEPT
Definition AutoRTFM.h:180
UE_AUTORTFM_CRITICAL_INLINE autortfm_transaction_id autortfm_current_transaction_id() AUTORTFM_NOEXCEPT
Definition AutoRTFM.h:254
UE_AUTORTFM_CRITICAL_INLINE void autortfm_record_open_write_no_memory_validation(void *Ptr, size_t Size) AUTORTFM_NOEXCEPT
Definition AutoRTFM.h:303
UE_AUTORTFM_CRITICAL_INLINE void autortfm_abort_transaction() AUTORTFM_NOEXCEPT
Definition AutoRTFM.h:248
UE_AUTORTFM_CRITICAL_INLINE void autortfm_check_abi(void *ptr, size_t size) AUTORTFM_NOEXCEPT
Definition AutoRTFM.h:430
UE_AUTORTFM_CRITICAL_INLINE void autortfm_on_commit(void(*work)(void *arg), void *arg)
Definition AutoRTFM.h:359
UE_AUTORTFM_CRITICAL_INLINE void autortfm_unreachable(const char *Message) AUTORTFM_NOEXCEPT
Definition AutoRTFM.h:443
UE_AUTORTFM_CRITICAL_INLINE void autortfm_on_pre_abort(void(*work)(void *arg), void *arg) AUTORTFM_NOEXCEPT
Definition AutoRTFM.h:368
UE_AUTORTFM_CRITICAL_INLINE void autortfm_register_open_to_closed_functions(autortfm_open_to_closed_table *Table) AUTORTFM_NOEXCEPT
Definition AutoRTFM.h:336
UE_AUTORTFM_CRITICAL_INLINE void autortfm_open(void(*work)(void *arg), void *arg, const void *)
Definition AutoRTFM.h:266
autortfm_log_severity
Definition AutoRTFM.h:77
@ autortfm_log_error
Definition AutoRTFM.h:81
@ autortfm_log_verbose
Definition AutoRTFM.h:78
@ autortfm_log_fatal
Definition AutoRTFM.h:82
@ autortfm_log_info
Definition AutoRTFM.h:79
@ autortfm_log_warn
Definition AutoRTFM.h:80
UE_AUTORTFM_CRITICAL_INLINE bool autortfm_is_retrying(void) AUTORTFM_NOEXCEPT
Definition AutoRTFM.h:207
UE_AUTORTFM_CRITICAL_INLINE void autortfm_on_abort(void(*work)(void *arg), void *arg) AUTORTFM_NOEXCEPT
Definition AutoRTFM.h:378
AUTORTFM_RESTORE_UNREACHABLE_CODE_WARNINGS UE_AUTORTFM_CRITICAL_INLINE void autortfm_record_open_write(void *Ptr, size_t Size) AUTORTFM_NOEXCEPT
Definition AutoRTFM.h:293
UE_AUTORTFM_CRITICAL_INLINE void * autortfm_did_allocate(void *ptr, size_t size) AUTORTFM_NOEXCEPT
Definition AutoRTFM.h:405
AUTORTFM_DISABLE_UNREACHABLE_CODE_WARNINGS UE_AUTORTFM_CRITICAL_INLINE autortfm_status autortfm_close(void(*UninstrumentedWork)(void *), void(*InstrumentedWork)(void *), void *Arg)
Definition AutoRTFM.h:279
UE_AUTORTFM_CRITICAL_INLINE void autortfm_pop_on_abort_handler(const void *key) AUTORTFM_NOEXCEPT
Definition AutoRTFM.h:396
UE_AUTORTFM_CRITICAL_INLINE void autortfm_unregister_open_to_closed_functions(autortfm_open_to_closed_table *Table) AUTORTFM_NOEXCEPT
Definition AutoRTFM.h:340
UE_AUTORTFM_CRITICAL_INLINE autortfm_result autortfm_transact(void(*UninstrumentedWork)(void *), void(*InstrumentedWork)(void *), void *Arg) AUTORTFM_EXCEPT
Definition AutoRTFM.h:216
autortfm_status
Definition AutoRTFM.h:62
@ autortfm_status_aborted_by_failed_lock_aquisition
Definition AutoRTFM.h:65
@ autortfm_status_aborted_by_cascading_abort
Definition AutoRTFM.h:69
@ autortfm_status_idle
Definition AutoRTFM.h:63
@ autortfm_status_ontrack
Definition AutoRTFM.h:64
@ autortfm_status_in_static_local_initializer
Definition AutoRTFM.h:71
@ autortfm_status_aborted_by_request
Definition AutoRTFM.h:67
@ autortfm_status_in_post_abort
Definition AutoRTFM.h:72
@ autortfm_status_committing
Definition AutoRTFM.h:68
@ autortfm_status_aborted_by_language
Definition AutoRTFM.h:66
@ autortfm_status_aborted_by_cascading_retry
Definition AutoRTFM.h:70
UE_AUTORTFM_CRITICAL_INLINE bool autortfm_is_committing_or_aborting(void) AUTORTFM_NOEXCEPT
Definition AutoRTFM.h:198
UE_AUTORTFM_CRITICAL_INLINE bool autortfm_is_closed(void) AUTORTFM_NOEXCEPT
Definition AutoRTFM.h:171
UE_AUTORTFM_CRITICAL_INLINE void autortfm_open_explicit_validation(autortfm_memory_validation_level, void(*work)(void *arg), void *arg, const void *)
Definition AutoRTFM.h:272
UE_AUTORTFM_CRITICAL_INLINE autortfm_result autortfm_transact_then_open(void(*UninstrumentedWork)(void *), void(*InstrumentedWork)(void *), void *Arg)
Definition AutoRTFM.h:227
autortfm_result
Definition AutoRTFM.h:51
@ autortfm_aborted_by_request
Definition AutoRTFM.h:52
@ autortfm_aborted_by_transact_during_abort
Definition AutoRTFM.h:56
@ autortfm_committed
Definition AutoRTFM.h:54
@ autortfm_aborted_by_transact_during_commit
Definition AutoRTFM.h:55
@ autortfm_aborted_by_language
Definition AutoRTFM.h:53
@ autortfm_aborted_by_cascade
Definition AutoRTFM.h:57
UE_AUTORTFM_CRITICAL_INLINE bool autortfm_is_on_current_transaction_stack(void *Ptr) AUTORTFM_NOEXCEPT
Definition AutoRTFM.h:349
UE_AUTORTFM_CRITICAL_INLINE bool autortfm_is_committing(void) AUTORTFM_NOEXCEPT
Definition AutoRTFM.h:189
UE_AUTORTFM_CRITICAL_INLINE void autortfm_push_on_abort_handler(const void *key, void(*work)(void *arg), void *arg) AUTORTFM_NOEXCEPT
Definition AutoRTFM.h:389
UE_AUTORTFM_CRITICAL_INLINE void autortfm_initialize(const autortfm_extern_api *ExternAPI) AUTORTFM_NOEXCEPT
Definition AutoRTFM.h:160
return Self
Definition CocoaThread.cpp:337
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
OnComplete(MoveTemp(Response))
JsonWriter Close()
s expects dereferenced FString s expects ANSICHAR *or UTF8CHAR s expects ANSICHAR *or UTF8CHAR *but got TCHAR *use ls S expects dereferenced FAnsiString or FUtf8String S expects character pointer but got S expects ANSICHAR *or UTF8CHAR S expects ANSICHAR *or UTF8CHAR *but got TCHAR *use s hs expects dereferenced FAnsiString or FUtf8String hs expects ANSICHAR *or UTF8CHAR hs expects ANSICHAR *or UTF8CHAR *but got TCHAR *use s ls expects character pointer but got ls expects TCHAR ls expects TCHAR *but got ANSICHAR *or UTF8CHAR *use hs c expects ANSICHAR or UTF8CHAR p expects a pointer unsupported format not enough arguments provided to format string d expects integral arg(eg. `char`, `int`, `long`, etc.)") X(ZNeedsIntegerArg
constexpr EIOSEventType operator+(EIOSEventType type, int Index)
Definition IOSInputInterface.cpp:138
const bool
Definition NetworkReplayStreaming.h:178
@ Unreachable
Object is not reachable on the object graph.
uint32 Size
Definition VulkanMemory.cpp:4034
bool CoinTossDisable()
Definition API.cpp:201
void SetInternalAbortAction(EAutoRTFMInternalAbortActionState State)
Definition API.cpp:229
bool GetMemoryValidationThrottlingEnabled()
Definition API.cpp:350
void SetEnsureOnInternalAbort(bool bEnabled)
Definition API.cpp:256
UE_AUTORTFM_ALWAYS_OPEN void DebugBreakIfMemoryValidationFails()
Definition API.cpp:400
EAutoRTFMRetryTransactionState GetRetryTransaction()
Definition API.cpp:281
void SetMemoryValidationStatisticsEnabled(bool bEnabled)
Definition API.cpp:384
void SetRetryTransaction(EAutoRTFMRetryTransactionState State)
Definition API.cpp:265
bool IsAutoRTFMRuntimeEnabledInternal()
Definition API.cpp:163
void SetAutoRTFMEnabledProbability(float Chance)
Definition API.cpp:182
bool GetMemoryValidationStatisticsEnabled()
Definition API.cpp:375
void SetMemoryValidationLevel(EMemoryValidationLevel Level)
Definition API.cpp:330
EMemoryValidationLevel GetMemoryValidationLevel()
Definition API.cpp:321
void SetMemoryValidationThrottlingEnabled(bool bEnabled)
Definition API.cpp:359
bool ShouldRetryNonNestedTransactions()
Definition API.cpp:290
bool SetAutoRTFMRuntime(EAutoRTFMEnabledState State)
Definition API.cpp:85
bool GetEnsureOnInternalAbort()
Definition API.cpp:247
EAutoRTFMInternalAbortActionState GetInternalAbortAction()
Definition API.cpp:238
bool ShouldRetryNestedTransactionsToo()
Definition API.cpp:306
float GetAutoRTFMEnabledProbability()
Definition API.cpp:192
Definition API.cpp:57
GeometryCollection::Facades::FMuscleActivationData Data
Definition MuscleActivationConstraints.h:15
Type
Definition PawnAction_Move.h:11
@ Committed
Definition MemPro.h:149
FORCEINLINE T * Get(const FObjectPtr &ObjectPtr)
Definition ObjectPtr.h:426
@ deprecated
This class is deprecated and objects of this class won't be saved when serializing....
Definition ObjectMacros.h:847
UE_STRING_CLASS Result(Forward< LhsType >(Lhs), RhsLen)
Definition String.cpp.inl:732
Definition AutoRTFM.h:90
Definition AutoRTFM.h:312
void * Open
Definition AutoRTFM.h:313
void * Closed
Definition AutoRTFM.h:314
Definition AutoRTFM.h:321
const struct autortfm_open_to_closed_mapping * Mappings
Definition AutoRTFM.h:323
struct autortfm_open_to_closed_table * Prev
Definition AutoRTFM.h:326
struct autortfm_open_to_closed_table * Next
Definition AutoRTFM.h:329