Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
DelayExecutor.cpp
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
6#include "DelayExecutor.h"
9
10#include <atomic>
11#include <mutex>
12#include <utility>
13
14namespace
15{
16 bool StoreMax(std::atomic<uint32>& target, uint32 value)
17 {
18 uint32 current = target.load(std::memory_order_relaxed);
19 while (current < value &&
20 !target.compare_exchange_weak(current, value, std::memory_order_relaxed, std::memory_order_relaxed))
21 {
22 }
23
24 return current < value;
25 }
26}
27
29{
31 : activated(false),
32 submitted(0),
33 completed(0),
34 rejected(0),
35 backlog(0),
38 {
39 }
40
42 std::unique_ptr<DelayTask> preSvcHook;
43 std::unique_ptr<DelayTask> postSvcHook;
44 std::mutex stateLock;
46 std::atomic<uint64> submitted;
47 std::atomic<uint64> completed;
48 std::atomic<uint64> rejected;
49 std::atomic<uint32> backlog;
50 std::atomic<uint32> backlogHighWater;
51 std::atomic<uint64> backlogHighWaterEvents;
52};
53
58
61
66
68{
69 {
70 std::lock_guard<std::mutex> guard(impl_->stateLock);
71
72 if (!impl_->activated)
73 return 0;
74
75 impl_->activated = false;
76 impl_->threadGroup.Drain();
77 }
78
79 impl_->threadGroup.Join();
80 impl_->preSvcHook.reset();
81 impl_->postSvcHook.reset();
82
83 return 0;
84}
85
87{
88 if (impl_->preSvcHook)
89 impl_->preSvcHook->call();
90
91 impl_->threadGroup.GetExecutor().Run();
92
93 if (impl_->postSvcHook)
94 impl_->postSvcHook->call();
95
96 return 0;
97}
98
99int DelayExecutor::start(int num_threads, std::unique_ptr<DelayTask> pre_svc_hook, std::unique_ptr<DelayTask> post_svc_hook)
100{
101 if (activated())
102 return -1;
103
104 if (num_threads < 1)
105 return -1;
106
107 impl_->preSvcHook = std::move(pre_svc_hook);
108 impl_->postSvcHook = std::move(post_svc_hook);
109
110 int const started = impl_->threadGroup.Start(static_cast<size_t>(num_threads),
111 [this]
112 {
113 if (impl_->preSvcHook)
114 impl_->preSvcHook->call();
115 },
116 [this]
117 {
118 if (impl_->postSvcHook)
119 impl_->postSvcHook->call();
120 });
121
122 if (started == -1)
123 {
124 impl_->preSvcHook.reset();
125 impl_->postSvcHook.reset();
126 return -1;
127 }
128
129 activated(true);
130
131 return 0;
132}
133
134int DelayExecutor::execute(std::unique_ptr<DelayTask> new_req)
135{
136 auto reject = [this]
137 {
138 impl_->rejected.fetch_add(1, std::memory_order_relaxed);
139 return -1;
140 };
141
142 if (!new_req)
143 return reject();
144
145 {
146 std::lock_guard<std::mutex> guard(impl_->stateLock);
147
148 if (!impl_->activated)
149 return reject();
150 }
151
152 impl_->submitted.fetch_add(1, std::memory_order_relaxed);
153 uint32 const backlog = impl_->backlog.fetch_add(1, std::memory_order_relaxed) + 1;
154 if (StoreMax(impl_->backlogHighWater, backlog))
155 impl_->backlogHighWaterEvents.fetch_add(1, std::memory_order_relaxed);
156
157 impl_->threadGroup.GetExecutor().Post(
158 [this, task = std::move(new_req)]() mutable
159 {
160 task->call();
161 impl_->completed.fetch_add(1, std::memory_order_relaxed);
162 impl_->backlog.fetch_sub(1, std::memory_order_relaxed);
163 });
164
165 return 0;
166}
167
169{
170 std::lock_guard<std::mutex> guard(impl_->stateLock);
171 return impl_->activated;
172}
173
175{
176 std::lock_guard<std::mutex> guard(impl_->stateLock);
177 impl_->activated = s;
178}
179
181{
183 snapshot.Submitted = impl_->submitted.load(std::memory_order_relaxed);
184 snapshot.Completed = impl_->completed.load(std::memory_order_relaxed);
185 snapshot.Rejected = impl_->rejected.load(std::memory_order_relaxed);
186 snapshot.Backlog = impl_->backlog.load(std::memory_order_relaxed);
187 snapshot.BacklogHighWater = impl_->backlogHighWater.load(std::memory_order_relaxed);
188 snapshot.BacklogHighWaterEvents = impl_->backlogHighWaterEvents.load(std::memory_order_relaxed);
189
190 return snapshot;
191}
192
194{
195 uint32 const backlog = impl_->backlog.load(std::memory_order_relaxed);
196
197 impl_->submitted.store(0, std::memory_order_relaxed);
198 impl_->completed.store(0, std::memory_order_relaxed);
199 impl_->rejected.store(0, std::memory_order_relaxed);
200 impl_->backlogHighWater.store(backlog, std::memory_order_relaxed);
201 impl_->backlogHighWaterEvents.store(0, std::memory_order_relaxed);
202}
std::uint32_t uint32
Definition Define.h:77
virtual ~DelayExecutor()
DelayExecutorMetricsSnapshot GetMetricsSnapshot() const
int start(int num_threads=1, std::unique_ptr< DelayTask > pre_svc_hook=std::unique_ptr< DelayTask >(), std::unique_ptr< DelayTask > post_svc_hook=std::unique_ptr< DelayTask >())
int execute(std::unique_ptr< DelayTask > new_req)
static DelayExecutor * instance()
std::unique_ptr< Impl > impl_
static T * instance()
Definition Singleton.h:17
Skyfire::Asio::IoContextThreadGroup threadGroup
std::atomic< uint32 > backlogHighWater
std::atomic< uint64 > backlogHighWaterEvents
std::unique_ptr< DelayTask > preSvcHook
std::atomic< uint64 > submitted
std::atomic< uint64 > rejected
std::atomic< uint32 > backlog
std::atomic< uint64 > completed
std::unique_ptr< DelayTask > postSvcHook