1#include <console/printf.h>
2#include <mem/alloc.h>
3#include <sch/sched.h>
4#include <stdbool.h>
5#include <stddef.h>
6#include <stdint.h>
7#include <thread/reaper.h>
8#include <thread/workqueue.h>
9
10static size_t scheduler_thread_get_data(struct rbt_node *n) {
11 return thread_from_rq_rbt_node(n)->virtual_runtime_left;
12}
13
14static int32_t scheduler_cmp_threads(const struct rbt_node *a,
15 const struct rbt_node *b) {
16 int32_t vrla = thread_from_rq_rbt_node(a)->virtual_runtime_left;
17 int32_t vrlb = thread_from_rq_rbt_node(b)->virtual_runtime_left;
18 return vrla - vrlb;
19}
20
21void scheduler_init(void) {
22 scheduler_data.max_concurrent_stealers = global.core_count / 4;
23
24 /* I mean, if we have one core and that core wants
25 * to steal work from itself, go ahead? */
26 if (scheduler_data.max_concurrent_stealers == 0)
27 scheduler_data.max_concurrent_stealers = 1;
28
29 global.schedulers = kmalloc(sizeof(struct scheduler *) * global.core_count);
30 if (!global.schedulers)
31 panic("Could not allocate scheduler pointer array");
32
33 size_t i;
34 for_each_cpu_id(i) {
35 struct scheduler *s =
36 kmalloc(sizeof(struct scheduler), ALLOC_FLAGS_ZERO);
37 if (!s)
38 panic("Could not allocate scheduler %lu", i);
39
40 spinlock_init(lock: &s->lock);
41 rbt_init(t: &s->thread_rbt, get_data: scheduler_thread_get_data,
42 compare: scheduler_cmp_threads);
43 rbt_init(t: &s->completed_rbt, get_data: scheduler_thread_get_data,
44 compare: scheduler_cmp_threads);
45 rbt_init(t: &s->climb_threads, get_data: climb_get_thread_data,
46 compare: scheduler_cmp_threads);
47 s->tick_enabled = false;
48 s->current_period = 1; /* Start at period 1 to avoid
49 * starting at 0 because
50 * that would lead to threads
51 * being mistakenly identified
52 * as completed */
53
54 s->core_id = i;
55
56 struct thread *idle_thread =
57 thread_create(name: "idle_thread_%u", entry_point: scheduler_idle_main, NULL, i);
58 idle_thread->flags |= THREAD_FLAG_PINNED;
59 idle_thread->state = THREAD_STATE_IDLE_THREAD;
60 s->idle_thread = idle_thread;
61
62 INIT_LIST_HEAD(list: &s->rt_threads);
63 INIT_LIST_HEAD(list: &s->urgent_threads);
64 INIT_LIST_HEAD(list: &s->bg_threads);
65
66 if (!i) {
67 struct thread *t = thread_create(name: "main_thread", entry_point: k_sch_main, NULL);
68 t->flags |= THREAD_FLAG_PINNED;
69 scheduler_add_thread(sched: s, thread: t, false);
70 }
71
72 global.schedulers[i] = s;
73 }
74}
75