NUMA++ 0.11.0
Loading...
Searching...
No Matches
scheduler.hpp
Go to the documentation of this file.
1/**
2 * @file
3 * @ingroup numapp_sched
4 * @copyright ESO 2024 - European Southern Observatory
5 *
6 * @brief Contains scheduler declarations
7 *
8 * @defgroup numapp_sched Scheduler APIs
9 * @ingroup numapp
10 * @brief NUMA++ scheduler APIs
11 *
12 *
13 * See @ref scheduler-api for an overview.
14 */
15#ifndef NUMAPP_SCHEDULER_HPP_
16#define NUMAPP_SCHEDULER_HPP_
17#include <iosfwd>
18#include <system_error>
19#include <variant>
20
21#include <sched.h>
22
23namespace numapp {
24class IdleScheduler;
26class StaticScheduler;
27class Scheduler;
28
29/**
30 * @name Apply Scheduler to Specified Thread
31 *
32 * Applies scheduler to specified thread.
33 */
34/// @{
35
36/**
37 * Apply idle scheduler to specified thread.
38 *
39 * @param thread thread id.
40 * @param scheduler parameters.
41 * @returns 0 on success.
42 * @returns on-zero on failure.
43 *
44 * @relatesalso ::numapp::IdleScheduler
45 * @ingroup numapp_sched
46 * @headerfile <> <numapp/scheduler.hpp>
47 */
48[[nodiscard]] std::error_code Apply(pid_t thread, IdleScheduler const& scheduler) noexcept;
49
50/**
51 * Apply dynamic scheduler to specified thread.
52 *
53 * @param thread thread id.
54 * @param scheduler scheduler parameters.
55 * @returns 0 on success.
56 * @returns on-zero on failure.
57 *
58 * @relatesalso DynamicScheduler
59 * @ingroup numapp_sched
60 * @headerfile <> <numapp/scheduler.hpp>
61 */
62[[nodiscard]] std::error_code Apply(pid_t thread, DynamicScheduler const& scheduler) noexcept;
63
64/**
65 * Apply static scheduler to specified thread.
66 *
67 * @param thread thread id.
68 * @param scheduler scheduler parameters.
69 * @returns 0 on success.
70 * @returns on-zero on failure.
71 *
72 * @relatesalso StaticScheduler
73 * @ingroup numapp_sched
74 * @headerfile <> <numapp/scheduler.hpp>
75 */
76[[nodiscard]] std::error_code Apply(pid_t thread, StaticScheduler const& scheduler) noexcept;
77
78/**
79 * Apply variadic scheduler to specified thread.
80 *
81 * @param thread thread id.
82 * @param scheduler parameters.
83 * @returns 0 on success.
84 * @returns on-zero on failure.
85 *
86 * @relatesalso Scheduler
87 * @ingroup numapp_sched
88 * @headerfile <> <numapp/scheduler.hpp>
89 */
90[[nodiscard]] std::error_code Apply(pid_t thread, Scheduler const& scheduler) noexcept;
91/// @}
92
93namespace thisThread {
94
95/**
96 * @name Apply Scheduler to Current Thread
97 *
98 * Applies specified scheduler to current thread.
99 * @ingroup numapp_sched
100 */
101/// @{
102/**
103 * Apply idle scheduler to @a this thread.
104 *
105 * @param scheduler parameters.
106 * @returns 0 on success.
107 * @returns on-zero on failure.
108 *
109 * @relatesalso numapp::IdleScheduler
110 * @ingroup numapp_sched
111 * @headerfile <> <numapp/scheduler.hpp>
112 */
113[[nodiscard]] std::error_code Apply(IdleScheduler const& scheduler) noexcept;
114
115/**
116 * Apply dynamic scheduler to @a this thread.
117 *
118 * @param scheduler parameters.
119 * @returns 0 on success.
120 * @returns on-zero on failure.
121 *
122 * @relatesalso ::numapp::DynamicScheduler
123 * @ingroup numapp_sched
124 * @headerfile <> <numapp/scheduler.hpp>
125 */
126[[nodiscard]] std::error_code Apply(DynamicScheduler const& scheduler) noexcept;
127
128/**
129 * Apply static scheduler to @a this thread.
130 *
131 * @param scheduler parameters.
132 * @returns 0 on success.
133 * @returns on-zero on failure.
134 *
135 * @relatesalso ::numapp::StaticScheduler
136 * @ingroup numapp_sched
137 * @headerfile <> <numapp/scheduler.hpp>
138 */
139[[nodiscard]] std::error_code Apply(StaticScheduler const& scheduler) noexcept;
140
141/**
142 * Apply variadic scheduler to @a this thread.
143 *
144 * @param scheduler parameters.
145 * @returns 0 on success.
146 * @returns on-zero on failure.
147 *
148 * @relatesalso ::numapp::Scheduler
149 * @ingroup numapp_sched
150 * @headerfile <> <numapp/scheduler.hpp>
151 */
152[[nodiscard]] std::error_code Apply(Scheduler const& scheduler) noexcept;
153/// @}
154}
155
156/**
157 * Represents @c SCHED_IDLE scheduler policy.
158 *
159 * It does not use either dynamic or static priority and is only scheduled to execute if no
160 * other task is ready to run.
161
162 * @manpages
163 * @manpage{sched,7}
164 * @ingroup numapp_sched
165 * @headerfile <> <numapp/scheduler.hpp>
166 */
167class IdleScheduler {
168public:
169 IdleScheduler() noexcept = default;
170 explicit constexpr IdleScheduler(IdleScheduler&&) noexcept = default;
171 explicit constexpr IdleScheduler(IdleScheduler const&) noexcept = default;
172 constexpr IdleScheduler& operator=(IdleScheduler&&) noexcept = default;
173 constexpr IdleScheduler& operator=(IdleScheduler const&) noexcept = default;
174
175 [[nodiscard]] constexpr bool operator==(IdleScheduler const& rhs) const {
176 return true;
177 }
178 [[nodiscard]] bool operator!=(IdleScheduler const& rhs) const {
179 return false;
180 }
181
182 /**
183 * Apply policy to calling thread
184 */
185 [[nodiscard]] std::error_code Apply() const noexcept;
186};
187
188/**
189 * Formats @a scheduler and inserts it to @a os.
190 *
191 * @param os output stream to insert into.
192 * @param scheduler IdleScheduler to format.
193 * @returns @a os
194 *
195 * @relates IdleScheduler
196 */
197std::ostream& operator<<(std::ostream& os, IdleScheduler const& scheduler);
198
199/**
200 * Static priority scheduler (real-time).
201 *
202 * Get and set scheduler for the calling thread.
203 *
204 * The implementation use the pthread API to query and apply policy.
205 *
206 * @par Permissions
207 *
208 * Real-time priority scheduler may require additional permissions provided by `CAP_SYS_NICE` unless
209 * allowed by resource limits (`RLIMIT_RTPRIO`). See also @ref permissions.
210 *
211 * @manpages
212 * @manpage{sched,7}
213 * @ingroup numapp_sched
214 * @headerfile <> <numapp/scheduler.hpp>
215 */
217public:
218 /**
219 * Scheduler policy.
220 */
221 enum class Policy : int {
222 /**
223 * A first-in, first-out "real-time" policy.
224 */
225 Fifo = SCHED_FIFO,
226 /**
227 * A roound-robin, "real-time" policy.
228 */
229 Rr = SCHED_RR
230 };
231
232 /**
233 * Create with provided policy and priority.
234 *
235 * @param policy Scheduler policy.
236 * @param priority Static priority with a valid range of 1 (low) to 99 (high).
237 *
238 * @throw std::system_error containing std::errc::invalid_argument if any argument is invalid.
239 */
240 explicit StaticScheduler(Policy policy, int priority);
241
242 constexpr StaticScheduler(StaticScheduler&&) noexcept = default;
243 constexpr StaticScheduler(StaticScheduler const&) noexcept = default;
244 StaticScheduler& operator=(StaticScheduler&&) noexcept = default;
245 StaticScheduler& operator=(StaticScheduler const&) noexcept = default;
246
247 [[nodiscard]] bool operator==(StaticScheduler const& rhs) const noexcept {
248 return m_policy == rhs.m_policy && m_prio == rhs.m_prio;
249 }
250 [[nodiscard]] bool operator!=(StaticScheduler const& rhs) const noexcept {
251 return !(*this == rhs);
252 }
253
254 /**
255 * Set static priority 0 - 99.
256 * @param priority The priority to use. Valid range is 0 - 99.
257 *
258 * @return std::errc::invalid_argument if @c priority is invalid.
259 */
260 std::error_code SetPriority(int priority);
261
262 /**
263 * Set policy.
264 *
265 * @return std::errc::invalid_argument if policy is invalid.
266 */
267 std::error_code SetPolicy(Policy policy) noexcept;
268
269 /**
270 * Get static priority.
271 */
272 constexpr int GetPriority() const noexcept {
273 return m_prio;
274 }
275
276 /**
277 * @returns policy.
278 */
279 constexpr Policy GetPolicy() const noexcept {
280 return m_policy;
281 }
282
283private:
284 Policy m_policy;
285 int m_prio;
286};
287
288/**
289 * Formats @a scheduler and inserts it to @a os.
290 *
291 * @param os output stream to insert into.
292 * @param scheduler StaticScheduler to format.
293 * @returns @a os
294 *
295 * @relates StaticScheduler
296 */
297std::ostream& operator<<(std::ostream& os, StaticScheduler const& scheduler);
298
299/**
300 * Formats @a policy and inserts it to @a os.
301 *
302 * @param os output stream to insert into.
303 * @param policy Policy to format.
304 * @returns @a os
305 *
306 * @ingroup StaticScheduler
307 * @headerfile <> <numapp/scheduler.hpp>
308 */
309std::ostream& operator<<(std::ostream& os, StaticScheduler::Policy const& policy);
310
311/**
312 * Normal non-realtime scheduler that use dynamic priority (nice value).
313 *
314 * @note The "nice" value is a type of inverse dynamic scheduling priority where lower values (less
315 * nice) have higher priority.
316 *
317 * To apply a lower value requires CAP_SYS_NICE privilege.
318 *
319 * @manpages
320 * @manpage{sched,7}
321 * @manpage{setpriority,2}
322 *
323 * @ingroup numapp_sched
324 * @headerfile <> <numapp/scheduler.hpp>
325 */
327public:
328 /**
329 * Sheduler policy.
330 */
331 enum class Policy : int {
332 /**
333 * The standard round-robin time-sharing policy.
334 *
335 * This is referred to as @c SCHED_NORMAL in the kernel.
336 */
337 Other = SCHED_OTHER,
338 /**
339 * For "batch" style execution of processes.
340 */
341 Batch = SCHED_BATCH,
342 };
343
344 /**
345 * @param policy Scheduling policy.
346 * @param nice Niceness value with range [-20 - 19], where -20 is the highest priority and 19
347 * lowest priority.
348 *
349 * @throws std::system_error with std::errc::invalid_argument on error.
350 */
351 explicit DynamicScheduler(Policy policy = Policy::Other, int nice = 0);
352 constexpr DynamicScheduler(DynamicScheduler const&) noexcept = default;
353 DynamicScheduler& operator=(DynamicScheduler const&) noexcept = default;
354
355 [[nodiscard]] bool operator==(DynamicScheduler rhs) const {
356 return m_policy == rhs.m_policy && m_priority == rhs.m_priority;
357 }
358
359 [[nodiscard]] bool operator!=(DynamicScheduler rhs) const {
360 return !(*this == rhs);
361 }
362
363 /**
364 * Set dynamic nice value (dynamic priority) of thread.
365 *
366 * Higher value means "more" nice and correspondingly lower scheduling priority.
367 *
368 * @param value the dynamic priority. Valid range is [-20 - 19].
369 *
370 * @return std::errc::invalid_argument if value is out of range.
371 */
372 std::error_code SetNice(int value) noexcept;
373
374 /**
375 * Set policy.
376 *
377 * @return std::errc::invalid_argument if policy is invalid.
378 */
379 std::error_code SetPolicy(Policy policy) noexcept;
380
381 /**
382 * Get dynamic nice value.
383 */
384 int GetNice() const noexcept;
385
386 /**
387 * @returns policy.
388 */
389 constexpr Policy GetPolicy() const noexcept {
390 return m_policy;
391 }
392
393private:
394 Policy m_policy;
395 int m_priority;
396};
397
398/**
399 * Formats @a scheduler and inserts it to @a os.
400 *
401 * @param os output stream to insert into.
402 * @param scheduler DynamicScheduler to format.
403 * @returns @a os
404 *
405 * @relates DynamicScheduler
406 */
407std::ostream& operator<<(std::ostream& os, DynamicScheduler const& scheduler);
408
409/**
410 * Formats @a policy and inserts it to @a os.
411 *
412 * @param os output stream to insert into.
413 * @param policy Policy to format.
414 * @returns @a os
415 *
416 * @relates DynamicScheduler
417 */
418std::ostream& operator<<(std::ostream& os, DynamicScheduler const& policy);
419
420/**
421 * Variant of possible schedulers.
422 *
423 * @ingroup numapp_sched
424 * @headerfile <> <numapp/scheduler.hpp>
425 */
426using SchedulerVariant = std::variant<DynamicScheduler, StaticScheduler, IdleScheduler>;
427
428/**
429 * Formats @a scheduler and inserts it to @a os.
430 *
431 * @param os output stream to insert into.
432 * @param scheduler Scheduler to format.
433 * @returns @a os
434 *
435 * @ingroup numapp_sched
436 * @headerfile <> <numapp/scheduler.hpp>
437 */
438std::ostream& operator<<(std::ostream& os, SchedulerVariant const& scheduler);
439
440/**
441 * A sum-type of all supported schedulers.
442 *
443 * @manpages
444 * @manpage{sched,7}
445 *
446 * @ingroup numapp_sched
447 * @headerfile <> <numapp/scheduler.hpp>
448 */
449class Scheduler {
450public:
451 explicit Scheduler(SchedulerVariant const& sched);
452 Scheduler(IdleScheduler sched) noexcept;
453 Scheduler(StaticScheduler sched) noexcept;
454 Scheduler(DynamicScheduler sched) noexcept;
455
456 explicit Scheduler(SchedulerVariant&& sched) noexcept;
457 Scheduler(Scheduler&&) noexcept = default;
458 Scheduler(Scheduler const&) = default;
459
460 Scheduler& operator=(Scheduler&& rhs) noexcept = default;
461 Scheduler& operator=(Scheduler const&) noexcept = default;
462
463 [[nodiscard]] bool operator==(Scheduler const& rhs) const noexcept {
464 return m_scheduler == rhs.m_scheduler;
465 }
466 [[nodiscard]] bool operator!=(Scheduler const& rhs) const noexcept {
467 return !(*this == rhs);
468 }
469
470 /**
471 * Query the held scheduler.
472 *
473 * if (scheduler.HoldsScheduler<IdleScheduler>()) {
474 * // ...
475 * }
476 */
477 template <class T>
478 [[nodiscard]] constexpr bool HoldsScheduler() const noexcept {
479 return std::holds_alternative<T>(m_scheduler);
480 }
481
482 /**
483 * Get the held scheduler.
484 *
485 * idle_scheduler = scheduler.GetScheduler<IdleScheduler>(); // may throw
486 *
487 * @throw std::bad_variant_access if @c T does not match held scheduler.
488 */
489 template <class T>
490 [[nodiscard]] constexpr T GetScheduler() const {
491 return std::get<T>(m_scheduler);
492 }
493
494 /**
495 * Return active scheduler policy for this thread.
496 *
497 * @throws std::system_error with std::errc::not_supported error if unknown policy is found..
498 */
499 [[nodiscard]] static Scheduler MakeFromActive();
500
501 /**
502 * Return active scheduler policy for thread with @a pid.
503 *
504 * @throws std::system_error with std::errc::not_supported error if unknown policy is found..
505 */
506 [[nodiscard]] static Scheduler MakeFromActive(pid_t pid);
507
508 /**
509 * Get the underlying scheduler.
510 */
511 SchedulerVariant const& Get() const noexcept {
512 return m_scheduler;
513 }
514
515 /**
516 * Enable implicit conversion to underlying SchedulerVariant.
517 */
518 operator SchedulerVariant() const noexcept;
519
520private:
521 SchedulerVariant m_scheduler;
522};
523
524/**
525 * Formats @a scheduler and inserts it to @a os.
526 *
527 * @param os output stream to insert into.
528 * @param scheduler Scheduler to format.
529 * @returns @a os
530 *
531 * @relates Scheduler
532 */
533std::ostream& operator<<(std::ostream& os, Scheduler const& scheduler);
534
535} // namespace numapp
536#endif //#ifndef NUMAPP_SCHEDULER_HPP_
Normal non-realtime scheduler that use dynamic priority (nice value).
Policy
Sheduler policy.
@ Batch
For "batch" style execution of processes.
@ Other
The standard round-robin time-sharing policy.
constexpr Policy GetPolicy() const noexcept
DynamicScheduler(Policy policy=Policy::Other, int nice=0)
std::error_code SetNice(int value) noexcept
Set dynamic nice value (dynamic priority) of thread.
std::error_code SetPolicy(Policy policy) noexcept
Set policy.
int GetNice() const noexcept
Get dynamic nice value.
std::ostream & operator<<(std::ostream &os, DynamicScheduler const &scheduler)
Formats scheduler and inserts it to os.
std::ostream & operator<<(std::ostream &os, DynamicScheduler const &policy)
Formats policy and inserts it to os.
Represents SCHED_IDLE scheduler policy.
std::error_code Apply() const noexcept
Apply policy to calling thread.
std::ostream & operator<<(std::ostream &os, IdleScheduler const &scheduler)
Formats scheduler and inserts it to os.
A sum-type of all supported schedulers.
SchedulerVariant const & Get() const noexcept
Get the underlying scheduler.
static Scheduler MakeFromActive()
Return active scheduler policy for this thread.
constexpr T GetScheduler() const
Get the held scheduler.
constexpr bool HoldsScheduler() const noexcept
Query the held scheduler.
static Scheduler MakeFromActive(pid_t pid)
Return active scheduler policy for thread with pid.
Static priority scheduler (real-time).
std::ostream & operator<<(std::ostream &os, StaticScheduler const &scheduler)
Formats scheduler and inserts it to os.
constexpr int GetPriority() const noexcept
Get static priority.
StaticScheduler(Policy policy, int priority)
Create with provided policy and priority.
Policy
Scheduler policy.
@ Fifo
A first-in, first-out "real-time" policy.
@ Rr
A roound-robin, "real-time" policy.
std::error_code SetPriority(int priority)
Set static priority 0 - 99.
constexpr Policy GetPolicy() const noexcept
std::error_code SetPolicy(Policy policy) noexcept
Set policy.
std::error_code Apply(pid_t thread, IdleScheduler const &scheduler) noexcept
Apply idle scheduler to specified thread.
std::variant< DynamicScheduler, StaticScheduler, IdleScheduler > SchedulerVariant
Variant of possible schedulers.
std::error_code Apply(StaticScheduler const &scheduler) noexcept
Apply static scheduler to this thread.
std::error_code Apply(pid_t thread, DynamicScheduler const &scheduler) noexcept
Apply dynamic scheduler to specified thread.
std::error_code Apply(Scheduler const &scheduler) noexcept
Apply variadic scheduler to this thread.
std::error_code Apply(DynamicScheduler const &scheduler) noexcept
Apply dynamic scheduler to this thread.
std::error_code Apply(IdleScheduler const &scheduler) noexcept
Apply idle scheduler to this thread.
std::error_code Apply(pid_t thread, Scheduler const &scheduler) noexcept
Apply variadic scheduler to specified thread.
std::error_code Apply(pid_t thread, StaticScheduler const &scheduler) noexcept
Apply static scheduler to specified thread.