| 1 | #include "sch/tests/test_internal.h" |
| 2 | #include <sync/event.h> |
| 3 | |
| 4 | static struct event lock_two_release; |
| 5 | |
| 6 | static 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 | |
| 12 | TEST_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 | |