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