1#include "internal.h"
2
3#include <nightmare/record.h>
4#include <sch/sched.h>
5#include <thread/thread.h>
6
7#ifdef TEST_NIGHTMARE_ENABLED
8void nightmare_publish_stop(enum test_stop reason) {
9 test_conc_publish_stop(c: &nightmare_runtime.conc, reason);
10}
11
12bool nightmare_must_stop(void) {
13 return test_conc_must_stop(c: &nightmare_runtime.conc);
14}
15
16void nightmare_stop_after_finding(void) {
17 nightmare_publish_stop(reason: TEST_STOP_FINDING);
18}
19
20bool nightmare_must_park(void) {
21 return test_conc_must_park(c: &nightmare_runtime.conc);
22}
23
24void nightmare_park(struct test_conc_worker *worker) {
25 test_conc_park(c: &nightmare_runtime.conc, w: worker);
26}
27
28static void nightmare_perturb_finding(const char *kind, const char *msg) {
29 nightmare_finding_at(
30 site: &(const struct nightmare_finding_site){.kind = kind,
31 .tier = NIGHTMARE_TIER_AMBIGUOUS,
32 .file = __RELFILE__,
33 .line = __LINE__},
34 discriminator: 0, fmt: "%s", msg);
35}
36
37void nightmare_thread_main(void *arg) {
38 struct test_conc_worker *worker = arg;
39 event_wait(e: &nightmare_runtime.conc.start, type: THREAD_WAIT_UNINTERRUPTIBLE,
40 reason: THREAD_BLOCK_REASON_MANUAL);
41
42 if (!nightmare_must_stop()) {
43 if (worker->index < nightmare_runtime.ctx.worker_count) {
44 if (nightmare_runtime.ctx.nm && nightmare_runtime.ctx.nm->ops &&
45 nightmare_runtime.ctx.nm->ops->worker)
46 nightmare_runtime.ctx.nm->ops->worker(&nightmare_runtime.ctx,
47 worker);
48 } else {
49 size_t pidx = worker->index - nightmare_runtime.ctx.worker_count;
50 if (pidx < nightmare_runtime.perturber_count &&
51 nightmare_runtime.perturbers[pidx] &&
52 nightmare_runtime.perturbers[pidx]->fn) {
53 const struct test_perturb_env env = {
54 .conc = &nightmare_runtime.conc,
55 .subject_count = nightmare_runtime.ctx.worker_count,
56 .victim_cpu = TEST_PERTURB_VICTIM_ANY,
57 .finding = nightmare_perturb_finding,
58 };
59 nightmare_runtime.perturbers[pidx]->fn(&env, worker);
60 }
61 }
62 }
63
64 test_conc_unpark_self(c: &nightmare_runtime.conc, w: worker);
65}
66
67void nightmare_heartbeat_main(void *arg) {
68 cc_ignore(arg);
69 event_wait(e: &nightmare_runtime.conc.start, type: THREAD_WAIT_UNINTERRUPTIBLE,
70 reason: THREAD_BLOCK_REASON_MANUAL);
71
72 time_ms_t next = time_get_ms() + nightmare_runtime.stat_interval_ms;
73 do {
74 nightmare_liveness_poll();
75
76 time_ms_t now = time_get_ms();
77 if (now >= next) {
78 nightmare_record_stat(progress: test_conc_progress_sum(),
79 workers: nightmare_runtime.ctx.worker_count);
80 next = now + nightmare_runtime.stat_interval_ms;
81 }
82 thread_sleep_for_ms(ms: 10);
83 } while (!nightmare_must_stop());
84
85 nightmare_liveness_poll();
86
87 nightmare_record_stat(progress: test_conc_progress_sum(),
88 workers: nightmare_runtime.ctx.worker_count);
89}
90#endif
91