1#include <mem/alloc.h>
2#include <mem/alloc_or_die.h>
3#include <sch/sched.h>
4#include <thread/daemon.h>
5#include <thread/reaper.h>
6#include <thread/workqueue.h>
7
8static struct reaper_thread **reapers = NULL;
9static atomic_size_t reaped_threads = ATOMIC_VAR_INIT(0);
10
11void reaper_enqueue(struct thread *t) {
12 kassert(reapers);
13 size_t d = domain_local_id(c: TOPC_NONE);
14 locked_list_add(ll: &reapers[d]->list, lh: &t->reaper_list);
15 semaphore_post(s: &reapers[d]->sem);
16}
17
18void reaper_init(void) {
19 size_t reaper_count = global.domain_count;
20 reapers = kmalloc_or_die(sizeof(struct reaper_thread *) * reaper_count,
21 ALLOC_FLAGS_ZERO);
22
23 for (size_t i = 0; i < reaper_count; i++) {
24 reapers[i] =
25 alloc_or_die(kmalloc_from_domain(i, sizeof(struct reaper_thread)));
26
27 locked_list_init(ll: &reapers[i]->list, LOCKED_LIST_INIT_IRQ_DISABLE);
28 semaphore_init(s: &reapers[i]->sem, value: 1, SEMAPHORE_INIT_IRQ_DISABLE);
29 reapers[i]->thread = alloc_or_die(
30 thread_create("reaper_thread", reaper_thread_main, NULL));
31
32 domain_set_cpu_mask(mask: &reapers[i]->thread->allowed_cpus,
33 domain: global.domains[i]);
34 reapers[i]->thread->private = reapers[i];
35 thread_enqueue(t: reapers[i]->thread);
36 }
37}
38
39size_t reaper_get_reaped_thread_count(void) {
40 return atomic_load_explicit(&reaped_threads, memory_order_acquire);
41}
42
43void reaper_thread_main(void *unused) {
44 (void) unused;
45 struct reaper_thread *reaper = thread_get_current()->private;
46 while (true) {
47
48 while (locked_list_empty(ll: &reaper->list))
49 semaphore_wait(s: &reaper->sem);
50
51 struct list_head local;
52 INIT_LIST_HEAD(list: &local);
53
54 enum irql tlist = spin_lock_irq_disable(&reaper->list.lock);
55 list_splice_init(src: &reaper->list.list, dst: &local);
56 spin_unlock(&reaper->list.lock, tlist);
57
58 struct list_head *lh;
59 while ((lh = list_pop_front_init(head: &local)) != NULL) {
60 struct thread *t = container_of(lh, struct thread, reaper_list);
61
62 kassert(refcount_read(&t->refcount) == 0);
63 thread_free(t);
64 atomic_fetch_add(&reaped_threads, 1);
65 }
66
67 scheduler_yield();
68 }
69}
70