1#ifdef TEST_APC
2#include <sch/sched.h>
3#include <test.h>
4#include <thread/apc.h>
5#include <thread/reaper.h>
6#include <thread/thread.h>
7#include <thread/workqueue.h>
8#include <time/spin_sleep.h>
9
10static atomic_bool apc_ran = false;
11static void the_apc(void *a) {
12 atomic_store(&apc_ran, true);
13}
14
15static void apc_thread(void *) {
16 while (!atomic_load(&apc_ran))
17 scheduler_yield();
18}
19
20static struct thread *ted = NULL;
21TEST_DECLARE(apc_test, .tier = TEST_TIER_UNIT) {
22 ted = thread_spawn(name: "apc_test_thread", entry: apc_thread, NULL);
23 struct apc *a = kmalloc(sizeof(struct apc), ALLOC_FLAGS_ZERO);
24 if (!a || !ted)
25 goto pluh;
26
27 apc_init(a, fn: the_apc, NULL);
28
29 apc_enqueue(t: ted, a, type: APC_TYPE_KERNEL);
30
31 while (!atomic_load(&apc_ran))
32 scheduler_yield();
33
34pluh:
35 return TEST_SUCCESS;
36}
37
38static atomic_uint the_event_apc_ran_times = 0;
39static atomic_bool event_apc_test_ok = false;
40static void the_event_apc(void *pc) {
41 atomic_fetch_add(&the_event_apc_ran_times, 1);
42}
43
44APC_EVENT_CREATE(apc_event_test, "TEST_EVENT");
45
46static void apc_event_test_thread(void *) {
47 /* We want to enqueue an event APC, then raise to DISPATCH, trigger it a
48 * few times, check that no APCs got triggered, and then lower from there,
49 * and then check that APCs got triggered, and then test masking, etc. */
50 struct event_apc *evtapc = apc_event_apc_create();
51 apc_event_apc_init(a: evtapc, fn: the_event_apc, NULL);
52 apc_enqueue_event_apc(a: evtapc, APC_EVENT(apc_event_test));
53
54 enum irql old = irql_raise(new_level: IRQL_DISPATCH_LEVEL);
55 apc_event_signal(APC_EVENT(apc_event_test));
56 TEST_ASSERT_VOID(atomic_load(&the_event_apc_ran_times) == 0);
57 irql_lower(old_level: old);
58
59 TEST_ASSERT_VOID(atomic_load(&the_event_apc_ran_times) == 1);
60
61 apc_disable_kernel();
62 apc_event_signal(APC_EVENT(apc_event_test));
63 TEST_ASSERT_VOID(atomic_load(&the_event_apc_ran_times) == 1);
64 apc_enable_kernel();
65
66 TEST_ASSERT_VOID(atomic_load(&the_event_apc_ran_times) == 2);
67 apc_event_signal(APC_EVENT(apc_event_test));
68 TEST_ASSERT_VOID(atomic_load(&the_event_apc_ran_times) == 3);
69 atomic_store(&event_apc_test_ok, true);
70}
71
72static struct thread *ated = NULL;
73TEST_DECLARE(apc_event_test, .tier = TEST_TIER_UNIT) {
74 ated = thread_spawn(name: "apc_event_test_thread", entry: apc_event_test_thread, NULL);
75 while (!atomic_load(&event_apc_test_ok))
76 scheduler_yield();
77
78 return TEST_SUCCESS;
79}
80
81#endif
82