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 cc_counted_by(num_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 rt_scheduler_acquire_two_mappings(
25 struct rt_scheduler_mapping *a, struct rt_scheduler_mapping *b,
26 enum irql *out_a, enum irql *out_b) TSA_NO_ANALYSIS {
27 if (a < b) {
28 *out_a = spin_lock_high(&a->lock);
29 *out_b = spin_lock_high(&b->lock);
30 } else if (b < a) {
31 *out_b = spin_lock_high(&b->lock);
32 *out_a = spin_lock_high(&a->lock);
33 } else {
34 panic("Trying to acquire two locks on the same mapping");
35 }
36}
37
38static inline void rt_scheduler_release_two_mappings(
39 struct rt_scheduler_mapping *a, struct rt_scheduler_mapping *b,
40 enum irql out_a, enum irql out_b) TSA_NO_ANALYSIS {
41 if (a < b) {
42 spin_unlock(&b->lock, out_b);
43 spin_unlock(&a->lock, out_a);
44 } else if (b < a) {
45 spin_unlock(&a->lock, out_a);
46 spin_unlock(&b->lock, out_b);
47 } else {
48 panic("Trying to release two locks on the same mapping");
49 }
50}
51
52static inline void
53rt_scheduler_acquire_two_locks(struct rt_scheduler *a, struct rt_scheduler *b,
54 enum irql *oa, enum irql *ob) TSA_NO_ANALYSIS {
55 if (a == b) {
56 *oa = spin_lock_high(&a->lock);
57 return;
58 }
59
60 if (a < b) {
61 *oa = spin_lock_high(&a->lock);
62 *ob = spin_lock_high(&b->lock);
63 } else {
64 *ob = spin_lock_high(&b->lock);
65 *oa = spin_lock_high(&a->lock);
66 }
67}
68
69static inline void
70rt_scheduler_release_two_locks(struct rt_scheduler *a, struct rt_scheduler *b,
71 enum irql oa, enum irql ob) TSA_NO_ANALYSIS {
72 if (a == b) {
73 spin_unlock(&a->lock, oa);
74 return;
75 }
76
77 if (a < b) {
78 spin_unlock(&b->lock, ob);
79 spin_unlock(&a->lock, oa);
80 } else {
81 spin_unlock(&a->lock, oa);
82 spin_unlock(&b->lock, ob);
83 }
84}
85
86static inline enum rt_scheduler_static_state
87rt_scheduler_static_get_state(struct rt_scheduler_static *rts) {
88 return atomic_load_acq(&rts->state);
89}
90
91static inline void
92rt_scheduler_static_set_state(struct rt_scheduler_static *rts,
93 enum rt_scheduler_static_state new) {
94 atomic_store_release(&rts->state, new);
95}
96
97REFCOUNT_GENERATE_GETREF_FOR_STRUCT_WITH_FAILURE_COND(
98 rt_scheduler_static, refcount, state, == RT_SCHEDULER_STATIC_DESTROYING);
99
100static inline void rt_scheduler_static_putref(struct rt_scheduler_static *rts) {
101 if (refcount_dec_and_test(rc: &rts->refcount)) {
102 enforce(rt_scheduler_static_get_state(rts) ==
103 RT_SCHEDULER_STATIC_DESTROYING);
104 rt_scheduler_static_destroy_work_enqueue(rts);
105 }
106}
107