1#include <mem/alloc.h>
2#include <mem/nofail.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 enforce(reapers, UNINITIALIZED);
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 = nofail_vnews(reapers, reaper_count, ALLOC_ZERO);
21
22 for (size_t i = 0; i < reaper_count; i++) {
23 reapers[i] =
24 nofail(valloc_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 = nofail(thread_spawn(
29 "reaper_thread", reaper_thread_main, .private = reapers[i],
30 .allowed_cpus = global.domains[i]->cpu_mask));
31 }
32}
33
34size_t reaper_get_reaped_thread_count(void) {
35 return atomic_load_acq(&reaped_threads);
36}
37
38void reaper_thread_main(void *unused) {
39 cc_ignore(unused);
40 struct reaper_thread *reaper = thread_get_current()->private;
41 while (true) {
42
43 while (locked_list_empty(ll: &reaper->list))
44 semaphore_wait(s: &reaper->sem);
45
46 struct list_head local;
47 list_head_init(h: &local);
48
49 enum irql tlist = spin_lock_high(&reaper->list.lock);
50 list_head_splice_back_init(dst: &local, src: &reaper->list.list);
51 spin_unlock(&reaper->list.lock, tlist);
52
53 struct list_node *lh;
54 while ((lh = list_head_pop_front_init(h: &local)) != NULL) {
55 struct thread *t = container_of(lh, struct thread, reaper_list);
56
57 enforce(refcount_read(&t->refcount) == 0);
58 thread_free(t);
59 atomic_inc(&reaped_threads);
60 }
61
62 scheduler_yield();
63 }
64}
65