aboutsummaryrefslogtreecommitdiffstats
path: root/litmus/dgl.c
diff options
context:
space:
mode:
Diffstat (limited to 'litmus/dgl.c')
-rw-r--r--litmus/dgl.c248
1 files changed, 248 insertions, 0 deletions
diff --git a/litmus/dgl.c b/litmus/dgl.c
new file mode 100644
index 000000000000..e09d57cc2672
--- /dev/null
+++ b/litmus/dgl.c
@@ -0,0 +1,248 @@
1#include <linux/sched.h>
2#include <litmus/litmus.h>
3#include <litmus/dgl.h>
4#include <litmus/sched_trace.h>
5
6/* Word, bit -> resource id */
7#define ri(w, b) (w * MASK_SIZE + b)
8
9 /* For loop, where @i iterates over each set bit in @bit_arr */
10#define for_each_resource(bit_arr, w, b, i) \
11 for(w = 0; w < MASK_WORDS; ++w) \
12 for(b = find_first_bit(&bit_arr[w],MASK_SIZE), i = ri(w, b); \
13 b < MASK_SIZE; \
14 b = find_next_bit(&bit_arr[w],MASK_SIZE,b+1), i = ri(w, b))
15
16/* Return resource id in dgl @d for resource @r */
17#define resource_id(d, r) ((((void*)r) - (void*)(&(d)->resources))/ sizeof(*r))
18
19/* Return request group of req @r for resource @i */
20#define req_group(r, i) (container_of(((void*)r) - sizeof(*r)*(i), \
21 struct dgl_group_req, requests))
22
23/* Resource id -> word, bit */
24static inline void mask_idx(int resource, int *word, int *bit)
25{
26 *word = resource / MASK_SIZE;
27 *bit = resource % MASK_SIZE;
28}
29
30
31static void print_waiting(struct dgl *dgl, struct dgl_resource *resource)
32{
33 struct dgl_req *pos;
34 struct dgl_group_req *greq;
35 int rid = resource_id(dgl, resource);
36 unsigned long long last = 0;
37
38 TRACE("List for rid %d\n", resource_id(dgl, resource));
39 list_for_each_entry(pos, &resource->waiting, list) {
40 greq = req_group(pos, rid);
41 TRACE(" 0x%p with timestamp %llu\n", greq, greq->ts);
42 BUG_ON(greq->ts < last);
43 last = greq->ts;
44 }
45}
46
47void dgl_init(struct dgl *dgl)
48{
49 int i;
50 struct dgl_resource *resource;
51
52 for (i = 0; i < NR_CPUS; ++i)
53 dgl->acquired[i] = NULL;
54
55 for (i = 0; i < NUM_RESOURCES; ++i) {
56 resource = &dgl->resources[i];
57
58 INIT_LIST_HEAD(&resource->waiting);
59 resource->free_replicas = NUM_REPLICAS;
60 }
61
62 dgl->requests = 0;
63 dgl->running = 0;
64 dgl->ts = 0;
65}
66
67void dgl_group_req_init(struct dgl_group_req *greq)
68{
69 int i;
70 greq->cpu = NO_CPU;
71 for (i = 0; i < MASK_WORDS; ++i) {
72 greq->requested[i] = 0;
73 greq->waiting[i] = 0;
74 }
75}
76
77/**
78 * set_req - create request for @replicas of @resource.
79 */
80void set_req(struct dgl_group_req *greq, int resource, int replicas)
81{
82 int word, bit;
83 struct dgl_req *req;
84
85 BUG_ON(replicas > NUM_REPLICAS);
86
87 mask_idx(resource, &word, &bit);
88 __set_bit(bit, &greq->requested[word]);
89
90 req = &greq->requests[resource];
91 INIT_LIST_HEAD(&req->list);
92 req->replicas = replicas;
93}
94
95/*
96 * Attempt to fulfill request @req for @resource.
97 * Return 1 if successful. If the matching group request has acquired all of
98 * its needed resources, this will then set that req as dgl->acquired[cpu].
99 */
100static unsigned long try_acquire(struct dgl *dgl, struct dgl_resource *resource,
101 struct dgl_req *req)
102{
103 int word, bit, rid, head, empty, room;
104 unsigned long waiting;
105 struct dgl_group_req *greq;
106
107 rid = resource_id(dgl, resource);
108 greq = req_group(req, rid);
109
110 head = resource->waiting.next == &req->list;
111 empty = list_empty(&resource->waiting);
112 room = resource->free_replicas >= req->replicas;
113
114 if (! (room && (head || empty)) ) {
115 TRACE("0x%p cannot acquire %d replicas, %d free\n",
116 greq, req->replicas, resource->free_replicas,
117 room, head, empty);
118 return 0;
119 }
120
121 resource->free_replicas -= req->replicas;
122 BUG_ON(resource->free_replicas > NUM_REPLICAS);
123
124 TRACE("0x%p acquired %d replicas of rid %d\n",
125 greq, req->replicas, rid);
126
127 mask_idx(rid, &word, &bit);
128 clear_bit(bit, &greq->waiting[word]);
129
130 waiting = 0;
131 for (word = 0; word < MASK_WORDS; word++) {
132 waiting |= greq->waiting[word];
133 if (waiting)
134 break;
135 }
136
137 if (!waiting) {
138 TRACE("0x%p acquired all resources\n", greq);
139 BUG_ON(dgl->acquired[greq->cpu]);
140 dgl->acquired[greq->cpu] = greq;
141 litmus_reschedule(greq->cpu);
142 dgl->running++;
143 }
144
145 return 1;
146}
147
148/**
149 * add_group_req - initiate group request.
150 */
151void add_group_req(struct dgl *dgl, struct dgl_group_req *greq, int cpu)
152{
153 int b, w, i, succ, all_succ = 1;
154 struct dgl_req *req;
155 struct dgl_resource *resource;
156
157 greq->cpu = cpu;
158 greq->ts = dgl->ts++;
159
160 TRACE("0x%p group request added for CPU %d\n", greq, cpu);
161 BUG_ON(dgl->acquired[cpu] == greq);
162
163 ++dgl->requests;
164
165 for_each_resource(greq->requested, w, b, i) {
166 __set_bit(b, &greq->waiting[w]);
167 }
168
169 for_each_resource(greq->requested, w, b, i) {
170 req = &greq->requests[i];
171 resource = &dgl->resources[i];
172
173 succ = try_acquire(dgl, resource, req);
174 all_succ &= succ;
175
176 if (!succ) {
177 TRACE("0x%p waiting on rid %d\n", greq, i);
178 list_add_tail(&req->list, &resource->waiting);
179 }
180 }
181
182 /* Grant empty requests */
183 if (all_succ && !dgl->acquired[cpu]) {
184 TRACE("0x%p empty group request acquired cpu %d\n", greq, cpu);
185 dgl->acquired[cpu] = greq;
186 ++dgl->running;
187 }
188
189 BUG_ON(dgl->requests && !dgl->running);
190}
191
192/**
193 * remove_group_req - abandon group request.
194 *
195 * This will also progress the waiting queues of resources acquired by @greq.
196 */
197void remove_group_req(struct dgl *dgl, struct dgl_group_req *greq)
198{
199 int b, w, i;
200 struct dgl_req *req, *next;
201 struct dgl_resource *resource;
202
203 TRACE("0x%p removing group request for CPU %d\n", greq, greq->cpu);
204
205 --dgl->requests;
206
207 if (dgl->acquired[greq->cpu] == greq) {
208 TRACE("0x%p no longer acquired on CPU %d\n", greq, greq->cpu);
209 dgl->acquired[greq->cpu] = NULL;
210 --dgl->running;
211 }
212
213 for_each_resource(greq->requested, w, b, i) {
214 req = &greq->requests[i];
215 resource = &dgl->resources[i];
216
217 if (!list_empty(&req->list)) {
218 /* Waiting on resource */
219 clear_bit(b, &greq->waiting[w]);
220 list_del_init(&req->list);
221 TRACE("Quitting 0x%p from rid %d\n",
222 req, i);
223 } else {
224 /* Have resource */
225 resource->free_replicas += req->replicas;
226 BUG_ON(resource->free_replicas > NUM_REPLICAS);
227 TRACE("0x%p releasing %d of %d replicas, rid %d\n",
228 greq, req->replicas, resource->free_replicas, i);
229
230 if (!list_empty(&resource->waiting)) {
231 /* Give it to the next guy */
232 next = list_first_entry(&resource->waiting,
233 struct dgl_req,
234 list);
235
236 BUG_ON(req_group(next, i)->ts < greq->ts);
237
238 if (try_acquire(dgl, resource, next)) {
239 list_del_init(&next->list);
240 print_waiting(dgl, resource);
241
242 }
243 }
244 }
245 }
246
247 BUG_ON(dgl->requests && !dgl->running);
248}