1#include "sch/tests/test_internal.h"
2#include <sync/event.h>
3
4static struct event lock_two_release;
5
6static void lock_two_parked(void *arg) {
7 cc_ignore(arg);
8 event_wait(e: &lock_two_release, type: THREAD_WAIT_UNINTERRUPTIBLE,
9 reason: THREAD_BLOCK_REASON_MANUAL);
10}
11
12TEST_DEFINE_INTEGRATION(sched, lock_two_runqueues_irql, .min_cores = 2) {
13 event_init(e: &lock_two_release, type: EVENT_NOTIFICATION, false);
14
15 struct thread *t0 = thread_spawn("lock_two_0", lock_two_parked, .on_cpu = 0,
16 .pinned = true, .joinable = true);
17 struct thread *t1 = thread_spawn("lock_two_1", lock_two_parked, .on_cpu = 1,
18 .pinned = true, .joinable = true);
19 TEST_ASSERT_NONNULL(t0);
20 TEST_ASSERT_NONNULL(t1);
21
22 struct thread *a = t0;
23 struct thread *b = t1;
24 if (thread_get_scheduler_unsafe(t: a) < thread_get_scheduler_unsafe(t: b)) {
25 a = t1;
26 b = t0;
27 }
28
29 enum irql entry = irql_get();
30 TEST_ASSERT_LT(entry, IRQL_HIGH_LEVEL);
31
32 struct scheduler *rq_a, *rq_b;
33 enum irql irql_a, irql_b;
34 thread_lock_two_runqueues(a, b, out_rq_a: &rq_a, out_rq_b: &rq_b, irq_a: &irql_a, irq_b: &irql_b);
35 TEST_ASSERT_NE(rq_a, rq_b);
36 TEST_ASSERT(rq_a > rq_b);
37
38 TEST_ASSERT_EQ(irql_b, entry);
39 TEST_ASSERT_EQ(irql_a, IRQL_HIGH_LEVEL);
40
41 scheduler_release_two_locks(a: rq_a, b: rq_b, a_irql: irql_a, b_irql: irql_b);
42 TEST_ASSERT_EQ(irql_get(), entry);
43
44 event_set(e: &lock_two_release);
45 thread_join(t: t0);
46 thread_join(t: t1);
47
48 return TEST_SUCCESS;
49}
50