Rev 961 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
961 | pj | 1 | /* |
2 | * Project: S.Ha.R.K. |
||
3 | * |
||
4 | * Coordinators: |
||
5 | * Giorgio Buttazzo <giorgio@sssup.it> |
||
6 | * Paolo Gai <pj@gandalf.sssup.it> |
||
7 | * |
||
8 | * Authors : |
||
9 | * Paolo Gai <pj@gandalf.sssup.it> |
||
10 | * Massimiliano Giorgi <massy@gandalf.sssup.it> |
||
11 | * Luca Abeni <luca@gandalf.sssup.it> |
||
12 | * (see the web pages for full authors list) |
||
13 | * |
||
14 | * ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy) |
||
15 | * |
||
16 | * http://www.sssup.it |
||
17 | * http://retis.sssup.it |
||
18 | * http://shark.sssup.it |
||
19 | */ |
||
20 | |||
21 | /** |
||
22 | ------------ |
||
23 | CVS : $Id: srp.c,v 1.1 2005-02-25 10:40:58 pj Exp $ |
||
24 | |||
25 | File: $File$ |
||
26 | Revision: $Revision: 1.1 $ |
||
27 | Last update: $Date: 2005-02-25 10:40:58 $ |
||
28 | ------------ |
||
29 | |||
30 | Stack Resource Policy. see srp.h for general details... |
||
31 | |||
32 | |||
33 | HOW the shadows are managed in this module |
||
34 | ------------------------------------------ |
||
35 | |||
36 | All the task that use SRP are inserted in an ordered list, called tasklist. |
||
37 | |||
38 | when a task lock a mutex and change the system ceiling, all the shadows |
||
39 | of the tasks with preemption level <= are set to the locking task, and |
||
40 | viceversa when a mutex is unlocked. |
||
41 | |||
42 | The real algorithm is slightly different: for example consider a task set |
||
43 | of 8 tasks. We represent each task here as (PID, shadow, preemption level). |
||
44 | |||
45 | There is also a field, current, used to scan the tasklist. |
||
46 | |||
47 | When the system starts, the situation is as follows: |
||
48 | |||
49 | system ceiling = 0, current = NIL |
||
50 | (a,a,1) (b,b,2) (c,c,2) (d,d,2) (e,e,3) (f,f,4) (g,g,4) (h,h,5) |
||
51 | |||
52 | for example, task a is scheduled, and lock a mutex that cause the system |
||
53 | ceiling to become 2. The situation will be the following: |
||
54 | |||
55 | system ceiling = 2, current = d |
||
56 | (a,a,1) (b,a,2) (c,a,2) (d,a,2) (e,e,3) (f,f,4) (g,g,4) (h,h,5) |
||
57 | |||
58 | Now suppose that task f preempts on task a. (no change to the shadows) |
||
59 | |||
60 | Then the task f locks a mutex and the system ceiling become 4. The shadows |
||
61 | will be set as follows: |
||
62 | |||
63 | system ceiling = 4, current = g |
||
64 | (a,f,1) (b,a,2) (c,a,2) (d,a,2) (e,f,3) (f,f,4) (g,f,4) (h,h,5) |
||
65 | |||
66 | The system maintains a stack of the locked mutexes. each mutex has in the |
||
67 | descriptor the space for implementing a stack, useful in the unlock() |
||
68 | function to undo the modify done whith the last lock()... |
||
69 | |||
70 | This approach minimizes the number of shadows to be set, so minimizes |
||
71 | the complexity of the lock/unlock operations. |
||
72 | |||
73 | Unfortunately, it creates a tree in the shadows (i.e., when sys_ceiling=4, |
||
74 | task c points to task a that points to task f, and so on....). This may |
||
75 | cause a performance a little worse with respect to a one-jump shadow set. |
||
76 | This is not a big problem because when a task is preempted it is very |
||
77 | difficult (if not impossible!) that it may be rescheduled before the end |
||
78 | of another high priority task. |
||
79 | |||
80 | Dynamic creation and termination of tasks |
||
81 | ----------------------------------------- |
||
82 | This module allows dynamic creation and termination of tasks. |
||
83 | |||
84 | To be correct the system have to really activate the task only when the |
||
85 | system ceiling is 0. |
||
86 | |||
87 | To implement this there is a list, the lobbylist, that contains that tasks. |
||
88 | |||
89 | When a task is created and the system ceiling is > 0, the task is inserted |
||
90 | on the top of the list, and his activation are frozen via a call to |
||
91 | task_block_activations. |
||
92 | |||
93 | When the system_ceiling returns to 0, the lobby list is purged and for each |
||
94 | task in that list the task_unblock_activations is called. if the function |
||
95 | return a number >0, a task call task_activate is done on the task. |
||
96 | |||
97 | the tasks are inserted into the lobby list using only the next field. |
||
98 | |||
99 | |||
100 | |||
101 | When a mutex is destryed or a task is created or killed, the ceiling |
||
102 | have to be recalculated. The recalc is made when the system ceiling go down |
||
103 | to 0. to know whitch are the mutexes that need the operation they are |
||
104 | inserted into the srp_recalc list. |
||
105 | |||
106 | |||
107 | The SRP_usemutex function (see srp.h) is used to declare the used mutexes |
||
108 | of a task. Why this and how it works? |
||
109 | In this way, a task can insert directly the list of the mutexes that it uses |
||
110 | without allocating others resource models, but using directly the mutexes |
||
111 | that MUST be (in any case) initialized before the task creation... |
||
112 | This is done in a simple way, inheriting the SRP_mutex_t from the RES_MODEL. |
||
113 | When a task registers a mutex, the SRP module receive the pointer to that |
||
114 | mutex, so it can do all the stuffs with the needed data structures. |
||
115 | |||
116 | **/ |
||
117 | |||
118 | /* |
||
119 | * Copyright (C) 2000 Paolo Gai |
||
120 | * |
||
121 | * This program is free software; you can redistribute it and/or modify |
||
122 | * it under the terms of the GNU General Public License as published by |
||
123 | * the Free Software Foundation; either version 2 of the License, or |
||
124 | * (at your option) any later version. |
||
125 | * |
||
126 | * This program is distributed in the hope that it will be useful, |
||
127 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
128 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
129 | * GNU General Public License for more details. |
||
130 | * |
||
131 | * You should have received a copy of the GNU General Public License |
||
132 | * along with this program; if not, write to the Free Software |
||
133 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||
134 | * |
||
135 | */ |
||
136 | |||
137 | |||
138 | #include <srp/srp/srp.h> |
||
139 | |||
140 | #include <ll/ll.h> |
||
141 | #include <ll/string.h> |
||
142 | #include <ll/stdio.h> |
||
143 | #include <kernel/const.h> |
||
144 | #include <sys/types.h> |
||
145 | #include <kernel/descr.h> |
||
146 | #include <kernel/var.h> |
||
147 | #include <kernel/func.h> |
||
148 | |||
149 | #include <tracer.h> |
||
150 | |||
151 | typedef struct SRP_mutexstruct_t SRP_mutex_t; |
||
152 | |||
153 | /* The SRP resource level descriptor */ |
||
154 | typedef struct { |
||
155 | mutex_resource_des m; /*+ the mutex interface +*/ |
||
156 | |||
157 | int nlocked[MAX_PROC]; /*+ how many mutex a task currently locks +*/ |
||
158 | |||
159 | struct { |
||
160 | DWORD preempt; |
||
161 | PID next; |
||
162 | PID prev; |
||
163 | } proc_preempt[MAX_PROC]; /*+ the preemption level of each task in the |
||
164 | system; if a task don't use SRP its value |
||
165 | is 0; if a task use SRP the field preempt |
||
166 | is != 0 and the item is enqueued in the |
||
167 | ordered list tasklist +*/ |
||
168 | |||
169 | PID tasklist; /*+ A list of all the task that can use SRP, |
||
170 | ordered by the preemption level of each |
||
171 | task. +*/ |
||
172 | PID current; /*+ A pointer used to set shadows +*/ |
||
173 | |||
174 | PID lobbylist; /*+ A list for all the new tasks created when |
||
175 | the system ceiling is != 0. These tasks |
||
176 | will be inserted into tasklist when the |
||
177 | ceiling return to 0. +*/ |
||
178 | SRP_mutex_t *srpstack; /*+ this is the stack where we store the system |
||
179 | ceiling +*/ |
||
180 | |||
181 | SRP_mutex_t *srprecalc; /*+ the list of all mutexes that need a ceiling |
||
182 | recalc +*/ |
||
183 | |||
184 | SRP_mutex_t *srplist; /*+ an unordered list of all created SRP |
||
185 | mutexes +*/ |
||
186 | |||
187 | } SRP_mutex_resource_des; |
||
188 | |||
189 | |||
190 | /* this is the structure normally pointed by the opt field in the |
||
191 | mutex_t structure */ |
||
192 | struct SRP_mutexstruct_t { |
||
193 | RES_MODEL r; /*+ This little trick make possible the use of |
||
194 | SRP_usemutex +*/ |
||
195 | |||
196 | /* because the number of mutexes that can be created is not limited, |
||
197 | the stack normally used to store the system ceiling is implemented |
||
198 | through these two fields in the mutex descriptor. Note that the mutex |
||
199 | are mono-resource, so when we alloc space for a mutex descriptor we |
||
200 | alloc also the needed space for the stack... */ |
||
201 | DWORD sysceiling; /*+ The system ceiling; this field contains |
||
202 | - a meaningless value if the struct is not inserted |
||
203 | into the srpstack |
||
204 | - the system ceiling if the struct is on the top of |
||
205 | the srpstack |
||
206 | - a "frozen" system ceiling if the struct is not on |
||
207 | the top of the srpstack. |
||
208 | when a mutex is locked, it is inserted into srpstack |
||
209 | updating the system ceiling automatically |
||
210 | +*/ |
||
211 | SRP_mutex_t *srpstack_next; /*+ the next entry on the srpstack +*/ |
||
212 | |||
213 | |||
214 | |||
215 | BYTE use[MAX_PROC]; /*+ use[p]==1 if the task p declared that it uses the |
||
216 | mutex +*/ |
||
217 | |||
218 | DWORD ceiling; /*+ max premption level of the tasks that use the mutex +*/ |
||
219 | |||
220 | PID owner; /*+ the task that owns the mutex, NIL otherwise +*/ |
||
221 | |||
222 | int in_recalc_list; /*+ a flag: 1 if the mutex is in the recalc list +*/ |
||
223 | SRP_mutex_t *srprecalc_next; /*+ the next item in the recalc list +*/ |
||
224 | SRP_mutex_t *srprecalc_prev; /*+ the prev item; useful in extractions +*/ |
||
225 | |||
226 | SRP_mutex_t *srplist_next; /*+ the next item in the srplist list +*/ |
||
227 | SRP_mutex_t *srplist_prev; /*+ the prev item; useful in extractions+*/ |
||
228 | }; |
||
229 | |||
230 | |||
231 | |||
232 | |||
233 | |||
234 | |||
235 | |||
236 | |||
237 | |||
238 | |||
239 | |||
240 | /* ----------------------------------------------------------------------- |
||
241 | LISTS HANDLING |
||
242 | ----------------------------------------------------------------------- */ |
||
243 | |||
244 | /*+ this function inserts a task into the tasklist ordered list +*/ |
||
245 | static void SRP_insert_tasklist(SRP_mutex_resource_des *m, PID t) |
||
246 | { |
||
247 | PID p,q; |
||
248 | |||
249 | p = NIL; |
||
250 | q = m->tasklist; |
||
251 | |||
252 | while ((q != NIL) && |
||
253 | (m->proc_preempt[t].preempt >= m->proc_preempt[q].preempt)) { |
||
254 | p = q; |
||
255 | q = m->proc_preempt[q].next; |
||
256 | } |
||
257 | |||
258 | if (p != NIL) |
||
259 | m->proc_preempt[p].next = t; |
||
260 | else |
||
261 | m->tasklist = t; |
||
262 | |||
263 | if (q != NIL) m->proc_preempt[q].prev = t; |
||
264 | |||
265 | m->proc_preempt[t].next = q; |
||
266 | m->proc_preempt[t].prev = p; |
||
267 | } |
||
268 | |||
269 | /*+ this function extracts a task from the tasklist +*/ |
||
270 | static void SRP_extract_tasklist(SRP_mutex_resource_des *m, PID i) |
||
271 | { |
||
272 | PID p,q; |
||
273 | |||
274 | p = m->proc_preempt[i].prev; |
||
275 | q = m->proc_preempt[i].next; |
||
276 | |||
277 | if (p == NIL) m->tasklist = q; |
||
278 | else m->proc_preempt[p].next = m->proc_preempt[i].next; |
||
279 | |||
280 | if (q != NIL) m->proc_preempt[q].prev = m->proc_preempt[i].prev; |
||
281 | } |
||
282 | |||
283 | |||
284 | /*+ this function inserts a task into the lobbylist (in an unordered way) +*/ |
||
285 | static void SRP_insertfirst_lobbylist(SRP_mutex_resource_des *m, PID p) |
||
286 | { |
||
287 | m->proc_preempt[p].next = m->lobbylist; |
||
288 | m->proc_preempt[p].prev = NIL; |
||
289 | |||
290 | m->proc_preempt[m->lobbylist].prev = p; |
||
291 | m->lobbylist = p; |
||
292 | } |
||
293 | |||
294 | /*+ this function extract the first task from the lobbylist |
||
295 | the lobbylist must be not-empty!!!! +*/ |
||
296 | static __inline__ PID SRP_extractfirst_lobbylist(SRP_mutex_resource_des *m) |
||
297 | { |
||
298 | PID lobby = m->lobbylist; |
||
299 | m->lobbylist = m->proc_preempt[m->lobbylist].next; |
||
300 | return lobby; |
||
301 | } |
||
302 | |||
303 | |||
304 | |||
305 | /*+ This function insert a mutex into the recalc list ONLY if the mutex |
||
306 | isn't already in that list... +*/ |
||
307 | static void SRP_insertfirst_recalclist(SRP_mutex_resource_des *m, |
||
308 | SRP_mutex_t *mut) |
||
309 | { |
||
310 | if (!mut->in_recalc_list) { |
||
311 | mut->srprecalc_next = m->srprecalc; |
||
312 | mut->srprecalc_prev = NULL; |
||
313 | if (m->srprecalc) m->srprecalc->srprecalc_prev = mut; |
||
314 | m->srprecalc = mut; |
||
315 | |||
316 | mut->in_recalc_list = 1; |
||
317 | } |
||
318 | } |
||
319 | |||
320 | /*+ this function extracts mut from the list l. +*/ |
||
321 | static void SRP_extract_recalclist(SRP_mutex_resource_des *m, |
||
322 | SRP_mutex_t *mut) |
||
323 | { |
||
324 | SRP_mutex_t *p, *q; |
||
325 | |||
326 | p = mut->srprecalc_prev; |
||
327 | q = mut->srprecalc_next; |
||
328 | |||
329 | if (p) |
||
330 | p->srprecalc_next = mut->srprecalc_next; |
||
331 | else |
||
332 | m->srprecalc = q; |
||
333 | |||
334 | if (q) q->srprecalc_prev = mut->srprecalc_prev; |
||
335 | } |
||
336 | |||
337 | /*+ this function extracts mut from the list l. +*/ |
||
338 | static void SRP_extract_srplist(SRP_mutex_resource_des *m, |
||
339 | SRP_mutex_t *mut) |
||
340 | { |
||
341 | SRP_mutex_t *p, *q; |
||
342 | |||
343 | p = mut->srplist_prev; |
||
344 | q = mut->srplist_next; |
||
345 | |||
346 | if (p) |
||
347 | p->srplist_next = mut->srplist_next; |
||
348 | else |
||
349 | m->srplist = q; |
||
350 | |||
351 | if (q) q->srplist_prev = mut->srplist_prev; |
||
352 | } |
||
353 | |||
354 | |||
355 | |||
356 | /* ----------------------------------------------------------------------- |
||
357 | End of LISTS HANDLING |
||
358 | ----------------------------------------------------------------------- */ |
||
359 | |||
360 | |||
361 | |||
362 | |||
363 | /*+ This funcyion returns the actual system ceiling +*/ |
||
364 | static __inline__ DWORD sysceiling(SRP_mutex_resource_des *m) |
||
365 | { |
||
366 | if (m->srpstack) |
||
367 | return m->srpstack->sysceiling; |
||
368 | else |
||
369 | return 0; |
||
370 | } |
||
371 | |||
372 | /*+ this function recalc the mutex ceiling basing on the preemption levels |
||
373 | stored in the mevel m +*/ |
||
374 | static void SRP_recalc_ceiling_value(SRP_mutex_resource_des *m, |
||
375 | SRP_mutex_t *mut) |
||
376 | { |
||
377 | PID p; |
||
378 | int ceiling; |
||
379 | |||
380 | ceiling = 0; |
||
381 | for (p = 0; p < MAX_PROC; p++) |
||
382 | if (mut->use[p] && ceiling < m->proc_preempt[p].preempt) |
||
383 | ceiling = m->proc_preempt[p].preempt; |
||
384 | |||
385 | mut->ceiling = ceiling; |
||
386 | } |
||
387 | |||
388 | |||
389 | static int SRP_res_register(RLEVEL l, PID p, RES_MODEL *r) |
||
390 | { |
||
391 | SRP_mutex_resource_des *m = (SRP_mutex_resource_des *)(resource_table[l]); |
||
392 | |||
393 | if (r->level && r->level !=l) |
||
394 | return -1; |
||
395 | |||
396 | if (r->rclass == SRP_RCLASS) { |
||
397 | /* SRP_RES_MODEL resource model */ |
||
398 | // kern_printf("!%d %d",((SRP_RES_MODEL *)r)->preempt,p); |
||
399 | |||
400 | if (m->proc_preempt[p].preempt == 0) { |
||
401 | /* only the first SRP_RES_MODEL is considered */ |
||
402 | SRP_RES_MODEL *srp = (SRP_RES_MODEL *)r; |
||
403 | |||
404 | m->proc_preempt[p].preempt = srp->preempt; |
||
405 | // kern_printf("res_register: preempt=%d, p=%d\n",srp->preempt,p); |
||
406 | |||
407 | /* insert the new task in the ordered list tasklist or in the lobby |
||
408 | list */ |
||
409 | if (m->srpstack) { |
||
410 | SRP_insertfirst_lobbylist(m,p); |
||
411 | /* we have also to freeze the activations... */ |
||
412 | task_block_activation(p); |
||
413 | // kern_printf("LOBBY!!!"); |
||
414 | } |
||
415 | else |
||
416 | SRP_insert_tasklist(m,p); |
||
417 | } |
||
418 | |||
419 | m->nlocked[p] = 0; |
||
420 | return 0; |
||
421 | } |
||
422 | else if (r->rclass == SRP2_RCLASS) { |
||
423 | /* a mutex passed via SRP_useres() */ |
||
424 | SRP_mutex_t *mut = (SRP_mutex_t *)r; |
||
425 | |||
426 | if (mut->use[p]) |
||
427 | /* the mutex is already registered, do nothing! */ |
||
428 | return -1; |
||
429 | |||
430 | /* register the mutex for the task */ |
||
431 | mut->use[p] = 1; |
||
432 | |||
433 | if (m->srpstack) |
||
434 | SRP_insertfirst_recalclist(m,mut); |
||
435 | else { |
||
436 | /* we recalc the mutex ceiling */ |
||
437 | if (mut->ceiling < m->proc_preempt[p].preempt) |
||
438 | mut->ceiling = m->proc_preempt[p].preempt; |
||
439 | |||
440 | } |
||
441 | return 0; |
||
442 | } |
||
443 | else |
||
444 | return -1; |
||
445 | } |
||
446 | |||
447 | static void SRP_res_detach(RLEVEL l, PID p) |
||
448 | { |
||
449 | SRP_mutex_resource_des *m = (SRP_mutex_resource_des *)(resource_table[l]); |
||
450 | SRP_mutex_t *mut; |
||
451 | |||
452 | if (m->proc_preempt[p].preempt == 0) |
||
453 | return; |
||
454 | |||
455 | if (m->nlocked[p]) |
||
456 | kern_raise(XMUTEX_OWNER_KILLED, p); |
||
457 | else |
||
458 | m->nlocked[p] = 0; |
||
459 | |||
460 | for (mut = m->srplist; mut; mut = mut->srplist_next) |
||
461 | { |
||
462 | if (!mut->use[p]) |
||
463 | /* the mutex is not registered, do nothing! */ |
||
464 | continue; |
||
465 | |||
466 | /* unregister the mutex for the task */ |
||
467 | mut->use[p] = 0; |
||
468 | |||
469 | if (m->srpstack) |
||
470 | SRP_insertfirst_recalclist(m,mut); |
||
471 | else |
||
472 | SRP_recalc_ceiling_value(m,mut); |
||
473 | } |
||
474 | |||
475 | /* check if current points to the task being killed */ |
||
476 | if (m->current == p) |
||
477 | m->current = m->proc_preempt[m->current].prev; |
||
478 | |||
479 | /* remove the task from the tasklist */ |
||
480 | SRP_extract_tasklist(m, p); |
||
481 | } |
||
482 | |||
483 | static int SRP_init(RLEVEL l, mutex_t *m, const mutexattr_t *a) |
||
484 | { |
||
485 | SRP_mutex_resource_des *lev = (SRP_mutex_resource_des *)(resource_table[l]); |
||
486 | SRP_mutex_t *p; |
||
487 | PID x; |
||
488 | |||
489 | if (a->mclass != SRP_MCLASS) |
||
490 | return -1; |
||
491 | |||
492 | p = (SRP_mutex_t *) kern_alloc(sizeof(SRP_mutex_t)); |
||
493 | |||
494 | /* control if there is enough memory; no control on init on a |
||
495 | non- destroyed mutex */ |
||
496 | |||
497 | if (!p) |
||
498 | return (ENOMEM); |
||
499 | |||
500 | res_default_model(p->r, SRP2_RCLASS); |
||
501 | p->sysceiling = 0; /* dummy value :-) */ |
||
502 | p->srpstack_next = NULL; /* dummy value :-) */ |
||
503 | |||
504 | for (x = 0; x < MAX_PROC; x++) |
||
505 | p->use[x] = 0; |
||
506 | |||
507 | p->ceiling = 0; |
||
508 | p->owner = NIL; |
||
509 | |||
510 | p->in_recalc_list = 0; |
||
511 | p->srprecalc_next = NULL; /* dummy value :-) */ |
||
512 | p->srprecalc_prev = NULL; /* dummy value :-) */ |
||
513 | |||
514 | p->srplist_next = lev->srplist; |
||
515 | p->srplist_prev = NULL; |
||
516 | if (lev->srplist) lev->srplist->srplist_prev = p; |
||
517 | lev->srplist = p; |
||
518 | |||
519 | m->mutexlevel = l; |
||
520 | m->opt = (void *)p; |
||
521 | |||
522 | return 0; |
||
523 | } |
||
524 | |||
525 | |||
526 | static int SRP_destroy(RLEVEL l, mutex_t *m) |
||
527 | { |
||
528 | SRP_mutex_resource_des *lev = (SRP_mutex_resource_des *)(resource_table[l]); |
||
529 | SRP_mutex_t *mut; |
||
530 | SYS_FLAGS f; |
||
531 | |||
532 | mut = m->opt; |
||
533 | |||
534 | if (mut->owner != NIL) |
||
535 | return (EBUSY); |
||
536 | |||
537 | f = kern_fsave(); |
||
538 | |||
539 | /* the mutex isn't in the srpstack, because it is not busy */ |
||
540 | |||
541 | /* check srprecalc list */ |
||
542 | if (mut->in_recalc_list) |
||
543 | SRP_extract_recalclist(lev, mut); |
||
544 | |||
545 | /* extract from srplist */ |
||
546 | SRP_extract_srplist(lev, mut); |
||
547 | |||
548 | if (m->opt) { |
||
549 | kern_free(m->opt,sizeof(SRP_mutex_t)); |
||
550 | m->opt = NULL; |
||
551 | } |
||
552 | kern_frestore(f); |
||
553 | |||
554 | return 0; |
||
555 | } |
||
556 | |||
557 | static int SRP_lock(RLEVEL l, mutex_t *m) |
||
558 | { |
||
559 | SRP_mutex_resource_des *lev = (SRP_mutex_resource_des *)(resource_table[l]); |
||
560 | SRP_mutex_t *mut; |
||
561 | DWORD oldsysceiling; |
||
562 | SYS_FLAGS f; |
||
563 | |||
564 | f = kern_fsave(); |
||
565 | |||
566 | mut = (SRP_mutex_t *)m->opt; |
||
567 | if (!mut) { |
||
568 | /* if the mutex is not initialized */ |
||
569 | kern_frestore(f); |
||
570 | return (EINVAL); |
||
571 | } |
||
572 | |||
573 | if (mut->owner == exec_shadow) { |
||
574 | /* the task already owns the mutex */ |
||
575 | kern_frestore(f); |
||
576 | return (EDEADLK); |
||
577 | } |
||
578 | |||
579 | if (!mut->use[exec_shadow] || |
||
580 | lev->proc_preempt[exec_shadow].preempt == 0 || |
||
581 | mut->owner != NIL) |
||
582 | { |
||
583 | // kern_printf("SRP:lev =%d owner=%d use=%d preempt=%d exec_shadow=%d\n", |
||
584 | // lev, mut->owner, |
||
585 | // mut->use[exec_shadow], |
||
586 | // lev->proc_preempt[exec_shadow].preempt,exec_shadow); |
||
587 | kern_raise(XSRP_INVALID_LOCK, exec_shadow); |
||
588 | kern_frestore(f); |
||
589 | return (EINVAL); |
||
590 | } |
||
591 | |||
592 | /* we know that: |
||
593 | - the task use the SRP protocol and the mutex that it wants to lock |
||
594 | - the mutex is free |
||
595 | => the task can lock now the mutex |
||
596 | */ |
||
597 | |||
598 | lev->nlocked[exec_shadow]++; |
||
599 | mut->owner = exec_shadow; |
||
600 | |||
601 | oldsysceiling = sysceiling(lev); |
||
602 | |||
603 | /* update the system ceiling */ |
||
604 | mut->sysceiling = (oldsysceiling>mut->ceiling) ? |
||
605 | oldsysceiling : mut->ceiling; |
||
606 | |||
607 | /* update the srpstack */ |
||
608 | mut->srpstack_next = lev->srpstack; |
||
609 | lev->srpstack = mut; |
||
610 | |||
611 | /* if the system ceiling is changed we have to change the shadows |
||
612 | Note that mut->sysceiling is the NEW sysceiling */ |
||
613 | if (oldsysceiling != mut->sysceiling) { |
||
614 | /* we set the shadow of the last task that did a lock */ |
||
615 | if (mut->srpstack_next) |
||
616 | proc_table[mut->srpstack_next->owner].shadow = exec_shadow; |
||
617 | |||
618 | /* now we set the shadow field of the remainig tasks */ |
||
619 | |||
620 | /* first, get the first task to manage */ |
||
621 | if (lev->current == NIL) |
||
622 | lev->current = lev->tasklist; |
||
623 | else |
||
624 | /* Note that because the sysceiling is increased by the lock, currrent |
||
625 | can't be at the end of the tasklist, so the operation is legal */ |
||
626 | lev->current = lev->proc_preempt[lev->current].next; |
||
627 | |||
628 | for (;;) { |
||
629 | PID x; /* for readablenesss only :-) */ |
||
630 | |||
631 | proc_table[lev->current].shadow = exec_shadow; |
||
632 | |||
633 | /* test if we have to touch the next task in the tasklist */ |
||
634 | x = lev->proc_preempt[lev->current].next; |
||
635 | if (x == NIL || |
||
636 | lev->proc_preempt[x].preempt > mut->sysceiling) |
||
637 | break; |
||
638 | |||
639 | /* look at the next task ! */ |
||
640 | lev->current = lev->proc_preempt[lev->current].next; |
||
641 | } |
||
642 | } |
||
643 | |||
644 | kern_frestore(f); |
||
645 | |||
646 | return 0; |
||
647 | } |
||
648 | |||
649 | /* SRP_trylock is equal to SRP_lock because the SRP_lock don't block !!! */ |
||
650 | |||
651 | static int SRP_unlock(RLEVEL l, mutex_t *m) |
||
652 | { |
||
653 | SRP_mutex_resource_des *lev; |
||
654 | SRP_mutex_t *mut; |
||
655 | DWORD newsysceiling; |
||
656 | |||
657 | lev = (SRP_mutex_resource_des *)(resource_table[l]); |
||
658 | mut = (SRP_mutex_t *)m->opt; |
||
659 | |||
660 | if (!mut) |
||
661 | return (EINVAL); |
||
662 | |||
663 | if (mut->owner != exec_shadow) { |
||
664 | /* the mutex is owned by another task!!! */ |
||
665 | kern_sti(); |
||
666 | return (EPERM); |
||
667 | } |
||
668 | |||
669 | if (!lev->srpstack || lev->srpstack != mut) { |
||
670 | /* the mutex is not the top of the stack!!! (erroneous nesting!) */ |
||
671 | kern_sti(); |
||
672 | return (EINVAL); |
||
673 | } |
||
674 | |||
675 | proc_table[exec_shadow].context = kern_context_save(); |
||
676 | |||
677 | /* the mutex is mine and it is at the top of the stack */ |
||
678 | lev->nlocked[exec_shadow]--; |
||
679 | |||
680 | mut->owner = NIL; |
||
681 | // kern_printf("Ûnlocked=%dÛ",lev->nlocked[exec_shadow]); |
||
682 | |||
683 | /* extract the top of the stack */ |
||
684 | lev->srpstack = lev->srpstack->srpstack_next; |
||
685 | |||
686 | /* if the sysceiling decreases, we update the shadows */ |
||
687 | newsysceiling = sysceiling(lev); |
||
688 | if (newsysceiling < mut->sysceiling) { |
||
689 | do { |
||
690 | proc_table[lev->current].shadow = lev->current; |
||
691 | lev->current = lev->proc_preempt[lev->current].prev; |
||
692 | } while (lev->current != NIL && |
||
693 | lev->proc_preempt[lev->current].preempt > newsysceiling); |
||
694 | |||
695 | if (lev->srpstack) |
||
696 | /* this is the stack that owns the mutex with the current sysceiling*/ |
||
697 | proc_table[lev->srpstack->owner].shadow = lev->srpstack->owner; |
||
698 | } |
||
699 | |||
700 | /* if it is the last mutex in the stack, handle lobbylist and srprecalc */ |
||
701 | if (!lev->srpstack) { |
||
702 | // kern_printf("UNLOBBY:"); |
||
703 | while (lev->lobbylist != NIL) { |
||
704 | PID x = SRP_extractfirst_lobbylist(lev); |
||
705 | // kern_printf("x=%d - ",x); |
||
706 | SRP_insert_tasklist(lev, x); |
||
707 | |||
708 | /* activate the task if it was activated while in lobby list! */ |
||
709 | if (task_unblock_activation(x)) { |
||
710 | struct timespec t; |
||
711 | LEVEL sl = proc_table[x].task_level; |
||
712 | kern_gettime(&t); |
||
713 | level_table[sl]->public_activate(sl,x,&t); |
||
714 | // kern_printf("activate it!!!"); |
||
715 | } |
||
716 | } |
||
717 | |||
718 | while (lev->srprecalc) { |
||
719 | SRP_recalc_ceiling_value(lev, lev->srprecalc); |
||
720 | SRP_extract_recalclist(lev, lev->srprecalc); |
||
721 | } |
||
722 | } |
||
723 | |||
724 | scheduler(); |
||
725 | TRACER_LOGEVENT(FTrace_EVT_inheritance,(unsigned short int)proc_table[exec_shadow].context,(unsigned int)proc_table[exec].context); |
||
726 | kern_context_load(proc_table[exec_shadow].context); |
||
727 | |||
728 | return 0; |
||
729 | } |
||
730 | |||
731 | RLEVEL SRP_register_module(void) |
||
732 | { |
||
733 | RLEVEL l; /* the level that we register */ |
||
734 | SRP_mutex_resource_des *m; /* for readableness only */ |
||
735 | PID i; /* a counter */ |
||
736 | |||
737 | printk("SRP_register_module\n"); |
||
738 | |||
739 | /* request an entry in the level_table */ |
||
740 | l = resource_alloc_descriptor(); |
||
741 | |||
742 | /* alloc the space needed for the EDF_level_des */ |
||
743 | m = (SRP_mutex_resource_des *)kern_alloc(sizeof(SRP_mutex_resource_des)); |
||
744 | |||
745 | /* update the level_table with the new entry */ |
||
746 | resource_table[l] = (resource_des *)m; |
||
747 | |||
748 | /* fill the resource_des descriptor */ |
||
749 | m->m.r.rtype = MUTEX_RTYPE; |
||
750 | m->m.r.res_register = SRP_res_register; |
||
751 | m->m.r.res_detach = SRP_res_detach; |
||
752 | |||
753 | /* fill the mutex_resource_des descriptor */ |
||
754 | m->m.init = SRP_init; |
||
755 | m->m.destroy = SRP_destroy; |
||
756 | m->m.lock = SRP_lock; |
||
757 | m->m.trylock = SRP_lock; /* equal!!! */ |
||
758 | m->m.unlock = SRP_unlock; |
||
759 | |||
760 | /* fill the SRP_mutex_resource_des descriptor */ |
||
761 | for (i=0; i<MAX_PROC; i++) { |
||
762 | m->nlocked[i]=0; |
||
763 | m->proc_preempt[i].preempt = 0; |
||
764 | m->proc_preempt[i].next = NIL; |
||
765 | m->proc_preempt[i].prev = NIL; |
||
766 | } |
||
767 | |||
768 | m->tasklist = NIL; |
||
769 | m->current = NIL; |
||
770 | m->lobbylist = NIL; |
||
771 | |||
772 | m->srpstack = NULL; |
||
773 | m->srprecalc = NULL; |
||
774 | m->srplist = NULL; |
||
775 | |||
776 | return l; |
||
777 | } |
||
778 |