1#include "mem/slab/tests/test_internal.h"
2#include <acpi/lapic.h>
3#include <irq/irq.h>
4
5#define KFREE_IRQ_TEST_SPIN_MASK 0x3f
6static void **kfree_irq_allocs = NULL;
7static size_t kfree_irq_total_allocs = 0;
8static atomic_size_t kfree_irq_test_consumed = 0;
9
10static enum irq_result kfree_irq_test_irq(void *ctx, uint8_t vector,
11 struct irq_context *ictx) {
12 (void) ctx;
13 (void) vector;
14 (void) ictx;
15 size_t total = kfree_irq_total_allocs;
16 int midrange = total / 10;
17 int delta = (prng_next() % (midrange * 2)) - midrange;
18 int possible = midrange + delta;
19 if (possible < 1)
20 possible = 1;
21
22 if (possible + atomic_load(&kfree_irq_test_consumed) > total)
23 possible = total - atomic_load(&kfree_irq_test_consumed);
24
25 for (int i = 0; i < possible; i++) {
26 size_t idx = atomic_fetch_add(&kfree_irq_test_consumed, 1);
27 if (idx < total) {
28 kfree_defer_irq(ptr: kfree_irq_allocs[idx]);
29 int spins = prng_next() & KFREE_IRQ_TEST_SPIN_MASK;
30
31 while (spins) {
32 cpu_relax();
33 spins--;
34 }
35 }
36 }
37
38 return IRQ_HANDLED;
39}
40
41TEST_DECLARE_INTEGRATION(slab, kfree_defer_irq,
42 TEST_INTENSITY(256, 2048, 16384)) {
43 if (global.core_count < 4) {
44 return TEST_SKIP(TEST_SKIP_NONE);
45 }
46
47 size_t total = ctx->intensity_val ? ctx->intensity_val : 2048;
48 kfree_irq_total_allocs = total;
49 kfree_irq_allocs = kmalloc(sizeof(void *) * total);
50 TEST_ASSERT_NONNULL(kfree_irq_allocs);
51
52 atomic_store(&kfree_irq_test_consumed, 0);
53
54 irq_t irq = irq_alloc_entry();
55 irq_register(name: "kfree_defer_irq_test", vector: irq, handler: kfree_irq_test_irq, NULL,
56 flags: IRQ_FLAG_NONE);
57 irq_set_chip(vector: irq, chip: lapic_get_chip(), NULL);
58
59 for (size_t i = 0; i < total; i++) {
60 kfree_irq_allocs[i] = kmalloc(64);
61 TEST_ASSERT_NONNULL(kfree_irq_allocs[i]);
62 }
63
64 while (atomic_load(&kfree_irq_test_consumed) < total) {
65 ipi_send(apic_id: 3, vector: irq);
66 int spins = prng_next() & KFREE_IRQ_TEST_SPIN_MASK;
67
68 while (spins) {
69 cpu_relax();
70 spins--;
71 }
72 }
73
74 kfree(kfree_irq_allocs);
75 kfree_irq_allocs = NULL;
76
77 return TEST_SUCCESS;
78}
79