7#include <sys/syscall.h>
13static void* inherited_entry(
void* argument) {
15 state->tid = (pid_t)syscall(SYS_gettid);
17 struct sched_param param;
18 return (
void*)(intptr_t)(sc_mask(0, state->cpu) || sc_sample(state->cpu) ||
19 pthread_getschedparam(pthread_self(), &policy, ¶m) ||
20 policy != SCHED_OTHER || param.sched_priority);
22static int check_inherited_thread(
int cpu, pid_t* tid) {
25 if (pthread_create(&thread, NULL, inherited_entry, &state))
28 if (pthread_join(thread, &result) || result)
34static void* creator_entry(
void* argument) {
35 int cpu = *(
int*)argument;
36 if (sc_pin(0, cpu) || check_inherited_thread(cpu, NULL))
40 _exit(sc_mask(0, cpu) || sc_sample(cpu) ? 1 : 0);
41 return (
void*)(intptr_t)(child < 0 || sc_reap(child, 10000));
45 CHECK(sc_pin(0, sc_cpus[0]) == 0);
47 CHECK(check_inherited_thread(sc_cpus[0], &retired) == 0);
48 struct timespec interval;
49 CHECK(sched_rr_get_interval(0, &interval) == 0);
50 CHECK(sc_wait_for_task_retirement(retired, &interval) == 0);
52 struct sched_param param = {.sched_priority = 0};
54 CHECK(sched_getaffinity(retired,
sizeof(mask), &mask) == -1 && errno == ESRCH);
56 CHECK(sc_pin(retired, sc_cpus[0]) == -1 && errno == ESRCH);
58 CHECK(syscall(SYS_sched_getparam, retired, ¶m) == -1 && errno == ESRCH);
60 CHECK(syscall(SYS_sched_getscheduler, retired) == -1 && errno == ESRCH);
62 CHECK(syscall(SYS_sched_setparam, retired, ¶m) == -1 && errno == ESRCH);
64 CHECK(syscall(SYS_sched_setscheduler, retired, SCHED_OTHER, ¶m) == -1 && errno == ESRCH);
66 CHECK(pthread_create(&
creator, NULL, creator_entry, &sc_cpus[sc_count - 1]) == 0);
68 CHECK(pthread_join(
creator, &result) == 0 && result == NULL);
69 CHECK(sc_mask(0, sc_cpus[0]) == 0 && sc_sample(sc_cpus[0]) == 0);
73int sc_exec(
int argc,
char** argv) {
77 int cpu = atoi(argv[2]);
78 CHECK(cpu >= 0 && cpu < CPU_SETSIZE);
79 CHECK(sc_mask(0, cpu) == 0 && sc_sample(cpu) == 0);
80 CHECK((pid_t)syscall(SYS_gettid) == getpid());
81 CHECK(check_inherited_thread(cpu, NULL) == 0);
85static int enter_exec(
int cpu) {
88 execl(
"/applications/scheduling-no-such-image",
"absent", (
char*)NULL);
89 if (errno != ENOENT || sc_mask(0, cpu) || sc_sample(cpu))
92 snprintf(text,
sizeof(text),
"%d", cpu);
93 execl(SC_APP, SC_APP,
"schedule-exec", text, (
char*)NULL);
96static void* exec_entry(
void* argument) {
97 _exit(enter_exec(*(
int*)argument));
99static int exec_child(
int command,
int report,
void* argument) {
102 if (sc_pin(0, sc_cpus[0]))
104 if (!*(
int*)argument)
105 return enter_exec(sc_cpus[sc_count - 1]);
107 if (pthread_create(&
worker, NULL, exec_entry, &sc_cpus[sc_count - 1]))
112static int exec_inheritance(
void) {
114 struct sc_peer peer = SC_PEER_INITIALIZER;
115 for (
int threaded = 0; threaded < 2; ++threaded) {
116 CHECK(sc_spawn(&peer, exec_child, &threaded) == 0);
117 CHECK(sc_join(&peer) == 0);
125 atomic_uint ready, start, stop, sample, sampled;
132 int reverse, exit_race;
134static void* competition_target(
void* argument) {
136 if (sc_pin(0, sc_cpus[0]))
138 state->tid = (pid_t)syscall(SYS_gettid);
139 atomic_store_explicit(&state->ready, 1, memory_order_release);
140 while (!atomic_load_explicit(&state->stop, memory_order_acquire)) {
141 if (atomic_load_explicit(&state->sample, memory_order_acquire) &&
142 !atomic_load_explicit(&state->sampled, memory_order_relaxed)) {
144 state->failed = syscall(SYS_getcpu, &cpu, &node, NULL) || node;
145 state->final_cpu = cpu;
146 atomic_store_explicit(&state->sampled, 1, memory_order_release);
152static void* competition_setter(
void* argument) {
154 if (sc_wait(&
setter->state->start, 1))
156 for (
int i = 0; i < (
setter->exit_race ? 1 : 8); ++i) {
157 int cpu = sc_cpus[(i +
setter->reverse) % 2 ? sc_count - 1 : 0];
158 int result = sc_pin(
setter->state->tid, cpu);
159 if (result && !(
setter->exit_race && errno == ESRCH))
164static int competing_requests(
void) {
165 int failed = 0, target_live = 0, created = 0;
167 pthread_t target, controllers[2];
168 struct setter setters[2] = {{&state, 0, 0}, {&state, 1, 0}};
169 CHECK(pthread_create(&target, NULL, competition_target, &state) == 0);
171 CHECK(sc_wait(&state.ready, 1) == 0);
172 for (
int i = 0; i < 2; ++i) {
173 CHECK(pthread_create(&controllers[i], NULL, competition_setter, &setters[i]) == 0);
176 atomic_store_explicit(&state.start, 1, memory_order_release);
177 for (
int i = 0; i < created; ++i) {
179 if (pthread_join(controllers[i], &result) || result)
184 CHECK(sc_pin(state.tid, sc_cpus[sc_count - 1]) == 0);
185 atomic_store_explicit(&state.sample, 1, memory_order_release);
186 CHECK(sc_wait(&state.sampled, 1) == 0 && !state.failed &&
187 state.final_cpu == (
unsigned)sc_cpus[sc_count - 1]);
189 atomic_store_explicit(&state.start, 1, memory_order_release);
190 for (
int i = 0; i < created; ++i)
191 pthread_join(controllers[i], NULL);
192 atomic_store_explicit(&state.stop, 1, memory_order_release);
195 if (pthread_join(target, &result) || result)
200static int exit_requests(
void) {
202 for (
int i = 0; i < 4; ++i) {
205 pthread_t target, controller;
206 CHECK(pthread_create(&target, NULL, competition_target, &state) == 0);
207 if (sc_wait(&state.ready, 1)) {
208 atomic_store(&state.stop, 1);
209 pthread_join(target, NULL);
212 if (pthread_create(&controller, NULL, competition_setter, &
setter)) {
213 atomic_store(&state.stop, 1);
214 pthread_join(target, NULL);
217 atomic_store_explicit(&state.start, 1, memory_order_release);
218 atomic_store_explicit(&state.stop, 1, memory_order_release);
221 int result = pthread_join(controller, &changed);
222 result |= pthread_join(target, &stopped);
223 CHECK(!result && !changed && !stopped);
225 CHECK(sc_pin(state.tid, sc_cpus[0]) == -1 && errno == ESRCH);
230int sc_lifecycle(
void) {
231 return inheritance() || exec_inheritance() || competing_requests() || exit_requests();