1#include <sch/irql.h>
2#include <sch/rt_sched.h>
3#include <sync/spinlock.h>
4
5/* Globally, we keep track of RT_SCHEDULER_SLOTS_PER_THREAD of these. */
6struct rt_slot {
7 size_t slot_index; /* What index in the slots[] of the thread(s)? */
8 struct rt_scheduler_static *in_use; /* From whom? */
9};
10
11/* Tracking database structure for all of these */
12struct rt_slot_db {
13 size_t num_slots;
14 struct spinlock lock;
15 struct rt_slot *slots;
16};
17
18void rt_scheduler_static_destroy_work_enqueue(struct rt_scheduler_static *rts);
19enum rt_scheduler_error
20rt_slots_init_for_scheduler(struct rt_scheduler_static *rts);
21void rt_slots_dealloc_for_scheduler(struct rt_scheduler_static *rts);
22size_t rt_slot_get_num_available(void);
23
24static inline void
25rt_scheduler_acquire_two_mappings(struct rt_scheduler_mapping *a,
26 struct rt_scheduler_mapping *b,
27 enum irql *out_a, enum irql *out_b) {
28 if (a < b) {
29 *out_a = spin_lock_irq_disable(lock: &a->lock);
30 *out_b = spin_lock_irq_disable(lock: &b->lock);
31 } else if (b < a) {
32 *out_b = spin_lock_irq_disable(lock: &b->lock);
33 *out_a = spin_lock_irq_disable(lock: &a->lock);
34 } else {
35 panic("Trying to acquire two locks on the same mapping");
36 }
37}
38
39static inline void
40rt_scheduler_release_two_mappings(struct rt_scheduler_mapping *a,
41 struct rt_scheduler_mapping *b,
42 enum irql out_a, enum irql out_b) {
43 if (a < b) {
44 spin_unlock(lock: &b->lock, old: out_b);
45 spin_unlock(lock: &a->lock, old: out_a);
46 } else if (b < a) {
47 spin_unlock(lock: &a->lock, old: out_a);
48 spin_unlock(lock: &b->lock, old: out_b);
49 } else {
50 panic("Trying to release two locks on the same mapping");
51 }
52}
53
54static inline void rt_scheduler_acquire_two_locks(struct rt_scheduler *a,
55 struct rt_scheduler *b,
56 enum irql *oa,
57 enum irql *ob) {
58 if (a == b) {
59 *oa = spin_lock_irq_disable(lock: &a->lock);
60 return;
61 }
62
63 if (a < b) {
64 *oa = spin_lock_irq_disable(lock: &a->lock);
65 *ob = spin_lock_irq_disable(lock: &b->lock);
66 } else {
67 *ob = spin_lock_irq_disable(lock: &b->lock);
68 *oa = spin_lock_irq_disable(lock: &a->lock);
69 }
70}
71
72static inline void rt_scheduler_release_two_locks(struct rt_scheduler *a,
73 struct rt_scheduler *b,
74 enum irql oa, enum irql ob) {
75 if (a == b) {
76 spin_unlock(lock: &a->lock, old: oa);
77 return;
78 }
79
80 if (a < b) {
81 spin_unlock(lock: &b->lock, old: ob);
82 spin_unlock(lock: &a->lock, old: oa);
83 } else {
84 spin_unlock(lock: &a->lock, old: oa);
85 spin_unlock(lock: &b->lock, old: ob);
86 }
87}
88
89static inline enum rt_scheduler_static_state
90rt_scheduler_static_get_state(struct rt_scheduler_static *rts) {
91 return atomic_load_explicit(&rts->state, memory_order_acquire);
92}
93
94static inline void
95rt_scheduler_static_set_state(struct rt_scheduler_static *rts,
96 enum rt_scheduler_static_state new) {
97 atomic_store_explicit(&rts->state, new, memory_order_release);
98}
99
100REFCOUNT_GENERATE_GET_FOR_STRUCT_WITH_FAILURE_COND(
101 rt_scheduler_static, refcount, state, == RT_SCHEDULER_STATIC_DESTROYING);
102
103static inline void rt_scheduler_static_put(struct rt_scheduler_static *rts) {
104 if (refcount_dec_and_test(rc: &rts->refcount)) {
105 kassert(rt_scheduler_static_get_state(rts) ==
106 RT_SCHEDULER_STATIC_DESTROYING);
107 rt_scheduler_static_destroy_work_enqueue(rts);
108 }
109}
110