Loop Timing Witness
Native controller and runtime interfaces; hardware qualification pending
Toggle main menu visibility
Loading...
Searching...
No Matches
run_policy.h
Go to the documentation of this file.
1
// SPDX-License-Identifier: AGPL-3.0-or-later
2
// Commercial license available
3
// © Concepts 1996–2026 Miroslav Šotek. All rights reserved.
4
// © Code 2020–2026 Miroslav Šotek. All rights reserved.
5
// ORCID: 0009-0009-3560-0851
6
// Contact: www.anulum.li | protoscience@anulum.li
7
// Loop Timing Witness — actual Linux run scheduling policy
8
12
13
#ifndef WITNESS_LINUX_RUN_POLICY_H
14
#define WITNESS_LINUX_RUN_POLICY_H
15
#include "
../run_options.h
"
16
#include "
../refusal.h
"
17
#include <sched.h>
18
#include <sys/resource.h>
19
#include <cerrno>
20
#include <cstdio>
21
#include <cstdlib>
22
#include <memory>
23
#include <string>
24
#include <vector>
25
26
namespace
witness {
28
struct
HostPolicy
{
29
int
scheduler
;
30
int
priority
;
31
int
observed_cpu
;
32
int
nice
;
33
std::vector<int>
cpus
;
34
};
35
37
struct
FreeCpuMask
{
39
void
operator()
(cpu_set_t *mask)
const
noexcept
{ CPU_FREE(mask); }
40
};
41
43
inline
HostPolicy
read_host_policy
() {
44
HostPolicy
result{};
45
result.
scheduler
= sched_getscheduler(0);
46
sched_param parameter{};
47
if
(result.
scheduler
< 0 || sched_getparam(0, ¶meter) != 0)
48
throw
witness::RuntimeRefused
(
"cannot read Linux scheduler policy"
);
49
result.
priority
= parameter.sched_priority;
50
errno = 0;
51
result.
nice
= getpriority(PRIO_PROCESS, 0);
52
if
(errno)
53
throw
witness::RuntimeRefused
(
"cannot read Linux nice value"
);
54
result.
observed_cpu
= sched_getcpu();
55
if
(result.
observed_cpu
< 0)
56
throw
witness::RuntimeRefused
(
"cannot read current Linux CPU"
);
57
for
(
int
capacity = CPU_SETSIZE; capacity <= (1 << 20); capacity *= 2) {
58
const
auto
count =
static_cast<
std::size_t
>
(capacity);
59
const
auto
size = CPU_ALLOC_SIZE(count);
60
std::unique_ptr<cpu_set_t, FreeCpuMask> mask(CPU_ALLOC(count));
61
if
(!mask)
62
throw
witness::RuntimeRefused
(
"cannot allocate Linux CPU affinity mask"
);
63
CPU_ZERO_S(size, mask.get());
64
if
(sched_getaffinity(0, size, mask.get()) == 0) {
65
for
(
int
cpu = 0; cpu < capacity; ++cpu)
66
if
(CPU_ISSET_S(
static_cast<
std::size_t
>
(cpu), size, mask.get()))
67
result.
cpus
.push_back(cpu);
68
return
result;
69
}
70
if
(errno != EINVAL)
71
throw
witness::RuntimeRefused
(
"cannot read Linux CPU affinity"
);
72
}
73
throw
witness::RuntimeRefused
(
"Linux CPU affinity exceeds supported mask size"
);
74
}
75
77
inline
HostPolicy
apply_host_policy
(
const
RunOptions
&options) {
78
validate_run_options
(options);
79
const
auto
inherited =
read_host_policy
();
80
if
(options.
cpu
>= 0) {
81
bool
allowed =
false
;
82
for
(
int
cpu : inherited.cpus)
83
if
(cpu == options.
cpu
)
84
allowed =
true
;
85
if
(!allowed)
86
throw
witness::RuntimeRefused
(
"requested CPU is outside inherited affinity"
);
87
}
88
if
(options.
scheduler
== 1 && (options.
priority
< sched_get_priority_min(SCHED_FIFO) ||
89
options.
priority
> sched_get_priority_max(SCHED_FIFO)))
90
throw
witness::RuntimeRefused
(
"FIFO priority is outside Linux scheduler bounds"
);
91
if
(options.
cpu
>= 0) {
92
const
auto
count =
static_cast<
std::size_t
>
(options.
cpu
) + 1;
93
const
auto
size = CPU_ALLOC_SIZE(count);
94
std::unique_ptr<cpu_set_t, FreeCpuMask> mask(CPU_ALLOC(count));
95
if
(!mask)
96
throw
witness::RuntimeRefused
(
"cannot allocate requested Linux CPU mask"
);
97
CPU_ZERO_S(size, mask.get());
98
CPU_SET_S(
static_cast<
std::size_t
>
(options.
cpu
), size, mask.get());
99
if
(sched_setaffinity(0, size, mask.get()) != 0)
100
throw
witness::RuntimeRefused
(
"cannot set Linux CPU affinity (errno "
+
101
std::to_string(errno) +
")"
);
102
}
103
if
(options.
scheduler
>= 0) {
104
sched_param parameter{};
105
parameter.sched_priority = options.
scheduler
== 1 ? options.
priority
: 0;
106
if
(sched_setscheduler(0, options.
scheduler
== 1 ? SCHED_FIFO : SCHED_OTHER, ¶meter) !=
107
0)
108
throw
witness::RuntimeRefused
(
"cannot set Linux scheduler (errno "
+
109
std::to_string(errno) +
")"
);
110
}
111
const
auto
actual =
read_host_policy
();
112
if
((options.
cpu
>= 0 && (actual.cpus.size() != 1 || actual.cpus[0] != options.
cpu
)) ||
113
(options.
scheduler
>= 0 &&
114
actual.scheduler != (options.
scheduler
== 1 ? SCHED_FIFO : SCHED_OTHER)) ||
115
(options.
scheduler
>= 0 &&
116
actual.priority != (options.
scheduler
== 1 ? options.
priority
: 0)))
117
throw
witness::RuntimeRefused
(
"Linux scheduler/affinity readback differs from request"
);
118
return
actual;
119
}
120
122
inline
bool
write_host_policy
(std::FILE *file,
const
RunOptions
&options,
123
const
HostPolicy
&actual) {
124
bool
failed =
125
std::fprintf(file,
126
" \"host_policy\": {\"requested_cpu\": %d, \"requested_scheduler\": %d, "
127
"\"requested_priority\": %d, \"scheduler\": %d, \"priority\": %d, "
128
"\"observed_cpu\": %d, \"nice\": %d, \"affinity_cpus\": ["
,
129
options.
cpu
, options.
scheduler
, options.
priority
, actual.
scheduler
,
130
actual.
priority
, actual.
observed_cpu
, actual.
nice
) < 0;
131
for
(std::size_t index = 0; index < actual.
cpus
.size(); ++index)
132
if
(std::fprintf(file,
"%s%d"
, index ?
", "
:
""
, actual.
cpus
[index]) < 0)
133
failed =
true
;
134
return
std::fprintf(file,
"]}\n"
) < 0 || failed;
135
}
136
}
// namespace witness
152
153
#endif
witness::RuntimeRefused
Definition
refusal.h:19
refusal.h
run_options.h
witness::validate_run_options
void validate_run_options(const RunOptions &options)
Definition
run_options.h:32
witness::write_host_policy
bool write_host_policy(std::FILE *file, const RunOptions &options, const HostPolicy &actual)
Definition
run_policy.h:122
witness::apply_host_policy
HostPolicy apply_host_policy(const RunOptions &options)
Definition
run_policy.h:77
witness::read_host_policy
HostPolicy read_host_policy()
Definition
run_policy.h:43
witness::FreeCpuMask
Definition
run_policy.h:37
witness::FreeCpuMask::operator()
void operator()(cpu_set_t *mask) const noexcept
Definition
run_policy.h:39
witness::HostPolicy
Definition
run_policy.h:28
witness::HostPolicy::observed_cpu
int observed_cpu
Definition
run_policy.h:31
witness::HostPolicy::priority
int priority
Definition
run_policy.h:30
witness::HostPolicy::scheduler
int scheduler
Definition
run_policy.h:29
witness::HostPolicy::cpus
std::vector< int > cpus
Definition
run_policy.h:33
witness::HostPolicy::nice
int nice
Definition
run_policy.h:32
witness::RunOptions
Definition
run_options.h:22
witness::RunOptions::scheduler
int scheduler
Definition
run_options.h:27
witness::RunOptions::priority
int priority
Definition
run_options.h:28
witness::RunOptions::cpu
int cpu
Definition
run_options.h:26
runtime
linux
run_policy.h
Generated by
1.18.0