diff options
Diffstat (limited to 'litmus/dgl.c')
-rw-r--r-- | litmus/dgl.c | 248 |
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 */ | ||
24 | static inline void mask_idx(int resource, int *word, int *bit) | ||
25 | { | ||
26 | *word = resource / MASK_SIZE; | ||
27 | *bit = resource % MASK_SIZE; | ||
28 | } | ||
29 | |||
30 | |||
31 | static 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 | |||
47 | void 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 | |||
67 | void 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 | */ | ||
80 | void 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 | */ | ||
100 | static 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 | */ | ||
151 | void 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 | */ | ||
197 | void 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 | } | ||