| 1 | #include "sch/tests/test_internal.h" |
| 2 | |
| 3 | #define YIELD_APC_SPIN_LIMIT 2000000 |
| 4 | #define YIELD_APC_NO_READING 999 |
| 5 | |
| 6 | static atomic_bool yd_apc_ran = false; |
| 7 | static atomic_uint yd_nesting_at_delivery = YIELD_APC_NO_READING; |
| 8 | static atomic_bool yd_gave_up = false; |
| 9 | |
| 10 | static void yd_apc(void *arg) { |
| 11 | (void) arg; |
| 12 | atomic_store(&yd_nesting_at_delivery, |
| 13 | scheduler_yield_nesting(thread_get_current())); |
| 14 | atomic_store(&yd_apc_ran, true); |
| 15 | } |
| 16 | |
| 17 | static void yd_subject_main(void *) { |
| 18 | for (size_t i = 0; i < YIELD_APC_SPIN_LIMIT; i++) { |
| 19 | if (atomic_load(&yd_apc_ran)) |
| 20 | return; |
| 21 | scheduler_yield(); |
| 22 | } |
| 23 | atomic_store(&yd_gave_up, true); |
| 24 | } |
| 25 | |
| 26 | static void yd_enqueue_main(void *arg) { |
| 27 | struct thread *target = arg; |
| 28 | struct apc *apc = apc_create(); |
| 29 | if (!apc) |
| 30 | return; |
| 31 | |
| 32 | apc_init(a: apc, fn: yd_apc, NULL, destroy: apc_destroy_free); |
| 33 | if (thread_get(obj: target)) { |
| 34 | apc_enqueue(t: target, a: apc, type: APC_TYPE_KERNEL); |
| 35 | thread_put(t: target); |
| 36 | } |
| 37 | apc_put(a: apc); |
| 38 | } |
| 39 | |
| 40 | TEST_DECLARE_INTEGRATION(sched, yield_defers_kernel_apcs) { |
| 41 | if (global.core_count < 3) { |
| 42 | test_info("too few cores" ); |
| 43 | return TEST_SKIP(TEST_SKIP_NONE); |
| 44 | } |
| 45 | |
| 46 | atomic_store(&yd_apc_ran, false); |
| 47 | atomic_store(&yd_gave_up, false); |
| 48 | atomic_store(&yd_nesting_at_delivery, YIELD_APC_NO_READING); |
| 49 | |
| 50 | struct thread *subject = |
| 51 | thread_spawn_joinable_on_core(name: "yd_subject" , entry: yd_subject_main, NULL, core_id: 1); |
| 52 | TEST_ASSERT_NONNULL(subject); |
| 53 | |
| 54 | struct thread *enq = |
| 55 | thread_spawn_joinable_on_core(name: "yd_enq" , entry: yd_enqueue_main, arg: subject, core_id: 2); |
| 56 | TEST_ASSERT_NONNULL(enq); |
| 57 | |
| 58 | thread_join(t: subject); |
| 59 | thread_join(t: enq); |
| 60 | |
| 61 | TEST_ASSERT(!atomic_load(&yd_gave_up)); |
| 62 | TEST_ASSERT(atomic_load(&yd_apc_ran)); |
| 63 | |
| 64 | TEST_ASSERT_EQ_S((int) atomic_load(&yd_nesting_at_delivery), 0); |
| 65 | |
| 66 | return TEST_SUCCESS; |
| 67 | } |
| 68 | |