UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
EventLoop.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "CoreTypes.h"
6#include "Algo/ForEach.h"
7#include "Async/Mutex.h"
13#include "HAL/PlatformTime.h"
15#include "Misc/ScopeExit.h"
16#include "Stats/Stats.h"
17#include <limits>
18
19namespace UE::EventLoop {
20
22{
23 static inline uint32 GetCurrentThreadId()
24 {
26 }
27
32
33 static inline bool IsEventLoopThread(uint32 EventLoopThreadId)
34 {
35 return EventLoopThreadId == GetCurrentThreadId();
36 }
37
38 static inline bool IsInitialized(uint32 EventLoopThreadId)
39 {
40 return (EventLoopThreadId != 0);
41 }
42
43 static inline void CheckInitialized(uint32 EventLoopThreadId)
44 {
45 check(IsInitialized(EventLoopThreadId));
46 }
47
48 static inline void CheckNotInitialized(uint32 EventLoopThreadId)
49 {
50 check(!IsInitialized(EventLoopThreadId));
51 }
52
53 static inline void CheckIsEventLoopThread(uint32 EventLoopThreadId)
54 {
55 check(IsEventLoopThread(EventLoopThreadId));
56 }
57
58 static inline bool IsShutdownRequested(bool bShutdownRequested)
59 {
60 return bShutdownRequested;
61 }
62};
63
68
69template <typename IOManagerType, typename Traits = FEventLoopDefaultTraits>
70class TEventLoop final : public IEventLoop
71{
72private:
73 IOManagerType IOManager;
75 TMpscQueue<FAsyncTask> AsyncTasks;
76 TArray<FOnShutdownComplete> ShutdownRequests;
77 FTimespan LoopTime;
78 TAtomic<uint32> EventLoopThreadId;
79 TAtomic<bool> bShutdownRequested;
80 TAtomic<bool> bShutdownCompleted;
81 TAtomic<bool> bNotifyOnInit;
82 UE::FMutex InitMutex;
83 UE::FMutex ShutdownMutex;
84
85public:
86 struct FParams
87 {
88 // Initial IO manager parameters.
89 typename IOManagerType::FParams IOManagerParams;
90 };
91
93 : IOManager(*this, MoveTemp(Params.IOManagerParams))
94 , TimerManager()
95 , AsyncTasks()
96 , LoopTime()
97 , EventLoopThreadId(0)
98 , bShutdownRequested(false)
99 , bShutdownCompleted(false)
100 , bNotifyOnInit(false)
101 {
102 // Make sure request manager type derives from IIOManager.
103 static_assert(std::is_base_of_v<IIOManager, IOManagerType> == true);
104 }
105
106 virtual ~TEventLoop()
107 {
108 }
109
110 typename IOManagerType::FIOAccess& GetIOAccess()
111 {
112 return IOManager.GetIOAccess();
113 }
114
115 virtual bool Init() override
116 {
117 bool bInitSuccessful = false;
118
119 {
120 InitMutex.Lock();
122 {
123 InitMutex.Unlock();
124 };
125
126 Traits::CheckNotInitialized(EventLoopThreadId);
127 LoopTime = Traits::GetCurrentTime();
128 TimerManager.Init();
129 bInitSuccessful = IOManager.Init();
130 EventLoopThreadId = Traits::GetCurrentThreadId();
131 }
132
133 if (bNotifyOnInit)
134 {
135 IOManager.Notify();
136 }
137
138 return bInitSuccessful;
139 }
140
142 {
143 bool bRunLocally = false;
144
145 {
146 ShutdownMutex.Lock();
148 {
149 ShutdownMutex.Unlock();
150 };
151
152 // Check if this call to RequestShutdown is the first call.
153 bool bExpectedValue = false;
154 if (bShutdownRequested.CompareExchange(bExpectedValue, true))
155 {
156 // This is the first call to RequestShutdown. Notify the request manager to wake
157 // it so that the loop will see the request.
158 ShutdownRequests.Add(MoveTemp(OnShutdownComplete));
159 TryNotify();
160 }
161 else if (!bShutdownCompleted)
162 {
163 // Shutdown has been requested, but not yet acknowledged.
164 ShutdownRequests.Add(MoveTemp(OnShutdownComplete));
165 }
166 else
167 {
168 // Loop shutdown has already completed. Run the callback locally outside of the lock.
169 bRunLocally = true;
170 }
171 }
172
173 // Loop shutdown has already completed.
175 {
177 }
178 }
179
181 {
182 FTimerHandle OutHandle = TimerManager.SetTimer(MoveTemp(Callback), InRate, InbRepeat, InFirstDelay);
183 TryNotify();
184 return OutHandle;
185 }
186
188 {
190 TryNotify();
191 }
192
193 virtual void PostAsyncTask(FAsyncTask&& Task) override
194 {
195 AsyncTasks.Enqueue(MoveTemp(Task));
196 TryNotify();
197 }
198
199 virtual void Run() override
200 {
202 Traits::CheckInitialized(EventLoopThreadId);
203
204 while (true)
205 {
206 const FTimespan InfiniteWait(std::numeric_limits<int64>::max());
207 FTimespan WaitTime = InfiniteWait;
208
209 if (!RunOnce(WaitTime))
210 {
211 break;
212 }
213 };
214 }
215
216 virtual bool RunOnce(FTimespan WaitTime) override
217 {
219 Traits::CheckInitialized(EventLoopThreadId);
220
221 if (bShutdownCompleted)
222 {
223 // Terminated.
224 return false;
225 }
226
227 // Check if there are any running timers. The maximum wait time will then be shortened
228 // to the expiration of the next timer.
230 if (TimerManager.GetNextTimeout(TimerExpirationTime))
231 {
232 WaitTime = FMath::Min(WaitTime, TimerExpirationTime);
233 }
234
235 IOManager.Poll(WaitTime);
236
237 // Run timers.
238 FTimespan CurrentTime = Traits::GetCurrentTime();
239 FTimespan ElapsedTime = FMath::Max(CurrentTime - LoopTime, 0.0);
240 LoopTime = CurrentTime;
241 TimerManager.Tick(ElapsedTime);
242
243 // If any timers ran due to the above call to Tick, check whether any repeat timers are
244 // waiting to be rescheduled. Advancing the loop time and ticking the timers again will
245 // allow those timers to reschedule without requiring polling the IO manager again.
246 if (TimerManager.HasPendingRepeatTimer())
247 {
248 CurrentTime = Traits::GetCurrentTime();
249 ElapsedTime = FMath::Max(CurrentTime - LoopTime, 0.0);
250 LoopTime = CurrentTime;
251 TimerManager.Tick(ElapsedTime);
252 }
253
254 RunAsyncTasks();
255
256 if (Traits::IsShutdownRequested(bShutdownRequested))
257 {
258 IOManager.Shutdown();
259
261 {
262 ShutdownMutex.Lock();
264 {
265 ShutdownMutex.Unlock();
266 };
267
268 bShutdownCompleted = true;
269 LocalShutdownRequests = MoveTemp(ShutdownRequests);
270 }
271
272 // Run post-shutdown tasks.
275 {
277 }
278 });
279
280 // Terminated.
281 return false;
282 }
283
284 // Continue running.
285 return true;
286 }
287
288 virtual FTimespan GetLoopTime() const override
289 {
290 Traits::CheckInitialized(EventLoopThreadId);
291 return LoopTime;
292 }
293
294private:
295 void RunAsyncTasks()
296 {
298 while (AsyncTasks.Dequeue(AsyncTask))
299 {
300 AsyncTask();
301 }
302 }
303
304 void TryNotify()
305 {
306 if (Traits::IsInitialized(EventLoopThreadId))
307 {
308 // Init already completed. Notify the IO manager.
309 IOManager.Notify();
310 }
311 else
312 {
313 InitMutex.Lock();
315 {
316 InitMutex.Unlock();
317 };
318
319 if (!Traits::IsInitialized(EventLoopThreadId))
320 {
321 // Init has not yet started. Let it know to notify the IO manager of
322 // pending actions once it has completed.
323 bNotifyOnInit = true;
324 }
325 else
326 {
327 // Init competed before the lock was acquired. Notify the IO manager.
328 IOManager.Notify();
329 }
330 }
331 }
332};
333
334/* UE::EventLoop */ }
#define check(expr)
Definition AssertionMacros.h:314
void AsyncTask(ENamedThreads::Type Thread, TUniqueFunction< void()> Function)
Definition Async.cpp:54
#define QUICK_SCOPE_CYCLE_COUNTER(Stat)
Definition Stats.h:652
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
#define ON_SCOPE_EXIT
Definition ScopeExit.h:73
UE_INTRINSIC_CAST UE_REWRITE constexpr std::remove_reference_t< T > && MoveTemp(T &&Obj) noexcept
Definition UnrealTemplate.h:520
uint32_t uint32
Definition binka_ue_file_header.h:6
Definition Array.h:670
UE_NODEBUG UE_FORCEINLINE_HINT SizeType Add(ElementType &&Item)
Definition Array.h:2696
Definition Atomic.h:538
Definition MpscQueue.h:18
TOptional< ElementType > Dequeue()
Definition MpscQueue.h:58
void Enqueue(ArgTypes &&... Args)
Definition MpscQueue.h:49
Definition IEventLoop.h:26
Definition EventLoop.h:71
virtual void ClearTimer(FTimerHandle &InHandle, FOnTimerCleared &&OnTimerCleared=FOnTimerCleared()) override
Definition EventLoop.h:187
virtual ~TEventLoop()
Definition EventLoop.h:106
virtual FTimespan GetLoopTime() const override
Definition EventLoop.h:288
virtual bool RunOnce(FTimespan WaitTime) override
Definition EventLoop.h:216
virtual FTimerHandle SetTimer(FTimerCallback &&Callback, FTimespan InRate, bool InbRepeat=false, TOptional< FTimespan > InFirstDelay=TOptional< FTimespan >()) override
Definition EventLoop.h:180
virtual bool Init() override
Definition EventLoop.h:115
TEventLoop(FParams &&Params=FParams())
Definition EventLoop.h:92
IOManagerType::FIOAccess & GetIOAccess()
Definition EventLoop.h:110
virtual void Run() override
Definition EventLoop.h:199
virtual void PostAsyncTask(FAsyncTask &&Task) override
Definition EventLoop.h:193
virtual void RequestShutdown(FOnShutdownComplete &&OnShutdownComplete=FOnShutdownComplete()) override
Definition EventLoop.h:141
Definition EventLoopTimer.h:133
void Init()
Definition EventLoopTimer.h:146
bool GetNextTimeout(FTimespan &OutTimeout) const
Definition EventLoopTimer.h:168
FTimerHandle SetTimer(FTimerCallback &&Callback, FTimespan InRate, bool InbRepeat=false, TOptional< FTimespan > InFirstDelay=TOptional< FTimespan >())
Definition EventLoopTimer.h:205
bool HasPendingRepeatTimer() const
Definition EventLoopTimer.h:260
void Tick(FTimespan DeltaTime)
Definition EventLoopTimer.h:311
void ClearTimer(FTimerHandle &InHandle, FOnTimerCleared &&OnTimerCleared=FOnTimerCleared())
Definition EventLoopTimer.h:234
Definition Mutex.h:18
void Lock()
Definition Mutex.h:43
void Unlock()
Definition Mutex.h:53
void ForEach(InT &&Input, CallableT Callable)
Definition ForEach.h:36
constexpr int64 TicksPerSecond
Definition Timespan.h:47
Definition EventLoopLog.cpp:5
TUniqueFunction< void()> FOnShutdownComplete
Definition IEventLoop.h:23
FManagedStorageOnRemoveComplete FOnTimerCleared
Definition EventLoopTimer.h:20
@ false
Definition radaudio_common.h:23
static uint32 GetCurrentThreadId(void)
Definition AndroidPlatformTLS.h:20
static double Seconds()
Definition AndroidPlatformTime.h:20
Definition Timespan.h:76
Definition Optional.h:131
Definition EventLoop.h:22
static void CheckIsEventLoopThread(uint32 EventLoopThreadId)
Definition EventLoop.h:53
static void CheckInitialized(uint32 EventLoopThreadId)
Definition EventLoop.h:43
static bool IsInitialized(uint32 EventLoopThreadId)
Definition EventLoop.h:38
static void CheckNotInitialized(uint32 EventLoopThreadId)
Definition EventLoop.h:48
static uint32 GetCurrentThreadId()
Definition EventLoop.h:23
static bool IsShutdownRequested(bool bShutdownRequested)
Definition EventLoop.h:58
static bool IsEventLoopThread(uint32 EventLoopThreadId)
Definition EventLoop.h:33
static FTimespan GetCurrentTime()
Definition EventLoop.h:28
Definition EventLoopTimer.h:100
Definition EventLoop.h:87
IOManagerType::FParams IOManagerParams
Definition EventLoop.h:89
Definition EventLoopHandle.h:12