Rev 14 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2 | 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 | ------------ |
||
38 | pj | 23 | CVS : $Id: srp.c,v 1.3 2003-01-07 17:07:51 pj Exp $ |
2 | pj | 24 | |
25 | File: $File$ |
||
38 | pj | 26 | Revision: $Revision: 1.3 $ |
27 | Last update: $Date: 2003-01-07 17:07:51 $ |
||
2 | pj | 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 <modules/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 | typedef struct SRP_mutexstruct_t SRP_mutex_t; |
||
150 | |||
151 | /* The SRP resource level descriptor */ |
||
152 | typedef struct { |
||
153 | mutex_resource_des m; /*+ the mutex interface +*/ |
||
154 | |||
155 | int nlocked[MAX_PROC]; /*+ how many mutex a task currently locks +*/ |
||
156 | |||
157 | struct { |
||
158 | DWORD preempt; |
||
159 | PID next; |
||
160 | PID prev; |
||
161 | } proc_preempt[MAX_PROC]; /*+ the preemption level of each task in the |
||
162 | system; if a task don't use SRP its value |
||
163 | is 0; if a task use SRP the field preempt |
||
164 | is != 0 and the item is enqueued in the |
||
165 | ordered list tasklist +*/ |
||
166 | |||
167 | PID tasklist; /*+ A list of all the task that can use SRP, |
||
168 | ordered by the preemption level of each |
||
169 | task. +*/ |
||
170 | PID current; /*+ A pointer used to set shadows +*/ |
||
171 | |||
172 | PID lobbylist; /*+ A list for all the new tasks created when |
||
173 | the system ceiling is != 0. These tasks |
||
174 | will be inserted into tasklist when the |
||
175 | ceiling return to 0. +*/ |
||
176 | SRP_mutex_t *srpstack; /*+ this is the stack where we store the system |
||
177 | ceiling +*/ |
||
178 | |||
179 | SRP_mutex_t *srprecalc; /*+ the list of all mutexes that need a ceiling |
||
180 | recalc +*/ |
||
181 | |||
182 | SRP_mutex_t *srplist; /*+ an unordered list of all created SRP |
||
183 | mutexes +*/ |
||
184 | |||
185 | } SRP_mutex_resource_des; |
||
186 | |||
187 | |||
188 | /* this is the structure normally pointed by the opt field in the |
||
189 | mutex_t structure */ |
||
190 | struct SRP_mutexstruct_t { |
||
191 | RES_MODEL r; /*+ This little trick make possible the use of |
||
192 | SRP_usemutex +*/ |
||
193 | |||
194 | /* because the number of mutexes that can be created is not limited, |
||
195 | the stack normally used to store the system ceiling is implemented |
||
196 | through these two fields in the mutex descriptor. Note that the mutex |
||
197 | are mono-resource, so when we alloc space for a mutex descriptor we |
||
198 | alloc also the needed space for the stack... */ |
||
199 | DWORD sysceiling; /*+ The system ceiling; this field contains |
||
200 | - a meaningless value if the struct is not inserted |
||
201 | into the srpstack |
||
202 | - the system ceiling if the struct is on the top of |
||
203 | the srpstack |
||
204 | - a "frozen" system ceiling if the struct is not on |
||
205 | the top of the srpstack. |
||
206 | when a mutex is locked, it is inserted into srpstack |
||
207 | updating the system ceiling automatically |
||
208 | +*/ |
||
209 | SRP_mutex_t *srpstack_next; /*+ the next entry on the srpstack +*/ |
||
210 | |||
211 | |||
212 | |||
213 | BYTE use[MAX_PROC]; /*+ use[p]==1 if the task p declared that it uses the |
||
214 | mutex +*/ |
||
215 | |||
216 | DWORD ceiling; /*+ max premption level of the tasks that use the mutex +*/ |
||
217 | |||
218 | PID owner; /*+ the task that owns the mutex, NIL otherwise +*/ |
||
219 | |||
220 | int in_recalc_list; /*+ a flag: 1 if the mutex is in the recalc list +*/ |
||
221 | SRP_mutex_t *srprecalc_next; /*+ the next item in the recalc list +*/ |
||
222 | SRP_mutex_t *srprecalc_prev; /*+ the prev item; useful in extractions +*/ |
||
223 | |||
224 | SRP_mutex_t *srplist_next; /*+ the next item in the srplist list +*/ |
||
225 | SRP_mutex_t *srplist_prev; /*+ the prev item; useful in extractions+*/ |
||
226 | }; |
||
227 | |||
228 | |||
229 | |||
230 | |||
231 | |||
232 | |||
233 | |||
234 | |||
235 | |||
236 | |||
237 | |||
238 | /* ----------------------------------------------------------------------- |
||
239 | LISTS HANDLING |
||
240 | ----------------------------------------------------------------------- */ |
||
241 | |||
242 | /*+ this function inserts a task into the tasklist ordered list +*/ |
||
243 | static void SRP_insert_tasklist(SRP_mutex_resource_des *m, PID t) |
||
244 | { |
||
245 | PID p,q; |
||
246 | |||
247 | p = NIL; |
||
248 | q = m->tasklist; |
||
249 | |||
250 | while ((q != NIL) && |
||
251 | (m->proc_preempt[t].preempt >= m->proc_preempt[q].preempt)) { |
||
252 | p = q; |
||
253 | q = m->proc_preempt[q].next; |
||
254 | } |
||
255 | |||
256 | if (p != NIL) |
||
257 | m->proc_preempt[p].next = t; |
||
258 | else |
||
259 | m->tasklist = t; |
||
260 | |||
261 | if (q != NIL) m->proc_preempt[q].prev = t; |
||
262 | |||
263 | m->proc_preempt[t].next = q; |
||
264 | m->proc_preempt[t].prev = p; |
||
265 | } |
||
266 | |||
267 | /*+ this function extracts a task from the tasklist +*/ |
||
268 | static void SRP_extract_tasklist(SRP_mutex_resource_des *m, PID i) |
||
269 | { |
||
270 | PID p,q; |
||
271 | |||
272 | p = m->proc_preempt[i].prev; |
||
273 | q = m->proc_preempt[i].next; |
||
274 | |||
275 | if (p == NIL) m->tasklist = q; |
||
276 | else m->proc_preempt[p].next = m->proc_preempt[i].next; |
||
277 | |||
278 | if (q != NIL) m->proc_preempt[q].prev = m->proc_preempt[i].prev; |
||
279 | } |
||
280 | |||
281 | |||
282 | /*+ this function inserts a task into the lobbylist (in an unordered way) +*/ |
||
283 | static void SRP_insertfirst_lobbylist(SRP_mutex_resource_des *m, PID p) |
||
284 | { |
||
285 | m->proc_preempt[p].next = m->lobbylist; |
||
286 | m->proc_preempt[p].prev = NIL; |
||
287 | |||
288 | m->proc_preempt[m->lobbylist].prev = p; |
||
289 | m->lobbylist = p; |
||
290 | } |
||
291 | |||
292 | /*+ this function extract the first task from the lobbylist |
||
293 | the lobbylist must be not-empty!!!! +*/ |
||
294 | static __inline__ PID SRP_extractfirst_lobbylist(SRP_mutex_resource_des *m) |
||
295 | { |
||
296 | PID lobby = m->lobbylist; |
||
297 | m->lobbylist = m->proc_preempt[m->lobbylist].next; |
||
298 | return lobby; |
||
299 | } |
||
300 | |||
301 | |||
302 | |||
303 | /*+ This function insert a mutex into the recalc list ONLY if the mutex |
||
304 | isn't already in that list... +*/ |
||
305 | static void SRP_insertfirst_recalclist(SRP_mutex_resource_des *m, |
||
306 | SRP_mutex_t *mut) |
||
307 | { |
||
308 | if (!mut->in_recalc_list) { |
||
309 | mut->srprecalc_next = m->srprecalc; |
||
310 | mut->srprecalc_prev = NULL; |
||
311 | if (m->srprecalc) m->srprecalc->srprecalc_prev = mut; |
||
312 | m->srprecalc = mut; |
||
313 | |||
314 | mut->in_recalc_list = 1; |
||
315 | } |
||
316 | } |
||
317 | |||
318 | /*+ this function extracts mut from the list l. +*/ |
||
319 | static void SRP_extract_recalclist(SRP_mutex_resource_des *m, |
||
320 | SRP_mutex_t *mut) |
||
321 | { |
||
322 | SRP_mutex_t *p, *q; |
||
323 | |||
324 | p = mut->srprecalc_prev; |
||
325 | q = mut->srprecalc_next; |
||
326 | |||
327 | if (p) |
||
328 | p->srprecalc_next = mut->srprecalc_next; |
||
329 | else |
||
330 | m->srprecalc = q; |
||
331 | |||
332 | if (q) q->srprecalc_prev = mut->srprecalc_prev; |
||
333 | } |
||
334 | |||
335 | /*+ this function extracts mut from the list l. +*/ |
||
336 | static void SRP_extract_srplist(SRP_mutex_resource_des *m, |
||
337 | SRP_mutex_t *mut) |
||
338 | { |
||
339 | SRP_mutex_t *p, *q; |
||
340 | |||
341 | p = mut->srplist_prev; |
||
342 | q = mut->srplist_next; |
||
343 | |||
344 | if (p) |
||
345 | p->srplist_next = mut->srplist_next; |
||
346 | else |
||
347 | m->srplist = q; |
||
348 | |||
349 | if (q) q->srplist_prev = mut->srplist_prev; |
||
350 | } |
||
351 | |||
352 | |||
353 | |||
354 | /* ----------------------------------------------------------------------- |
||
355 | End of LISTS HANDLING |
||
356 | ----------------------------------------------------------------------- */ |
||
357 | |||
358 | |||
359 | |||
360 | |||
361 | /*+ This funcyion returns the actual system ceiling +*/ |
||
362 | static __inline__ DWORD sysceiling(SRP_mutex_resource_des *m) |
||
363 | { |
||
364 | if (m->srpstack) |
||
365 | return m->srpstack->sysceiling; |
||
366 | else |
||
367 | return 0; |
||
368 | } |
||
369 | |||
370 | /*+ this function recalc the mutex ceiling basing on the preemption levels |
||
371 | stored in the mevel m +*/ |
||
372 | static void SRP_recalc_ceiling_value(SRP_mutex_resource_des *m, |
||
373 | SRP_mutex_t *mut) |
||
374 | { |
||
375 | PID p; |
||
376 | int ceiling; |
||
377 | |||
378 | ceiling = 0; |
||
379 | for (p = 0; p < MAX_PROC; p++) |
||
380 | if (mut->use[p] && ceiling < m->proc_preempt[p].preempt) |
||
381 | ceiling = m->proc_preempt[p].preempt; |
||
382 | |||
383 | mut->ceiling = ceiling; |
||
384 | } |
||
385 | |||
386 | |||
38 | pj | 387 | static int SRP_res_register(RLEVEL l, PID p, RES_MODEL *r) |
2 | pj | 388 | { |
38 | pj | 389 | SRP_mutex_resource_des *m = (SRP_mutex_resource_des *)(resource_table[l]); |
2 | pj | 390 | |
38 | pj | 391 | if (r->level && r->level !=l) |
2 | pj | 392 | return -1; |
393 | |||
38 | pj | 394 | if (r->rclass == SRP_RCLASS) { |
2 | pj | 395 | /* SRP_RES_MODEL resource model */ |
396 | // kern_printf("!%d %d",((SRP_RES_MODEL *)r)->preempt,p); |
||
397 | |||
398 | if (m->proc_preempt[p].preempt == 0) { |
||
399 | /* only the first SRP_RES_MODEL is considered */ |
||
400 | SRP_RES_MODEL *srp = (SRP_RES_MODEL *)r; |
||
401 | |||
402 | m->proc_preempt[p].preempt = srp->preempt; |
||
403 | // kern_printf("res_register: preempt=%d, p=%d\n",srp->preempt,p); |
||
404 | |||
405 | /* insert the new task in the ordered list tasklist or in the lobby |
||
406 | list */ |
||
407 | if (m->srpstack) { |
||
408 | SRP_insertfirst_lobbylist(m,p); |
||
409 | /* we have also to freeze the activations... */ |
||
410 | task_block_activation(p); |
||
411 | // kern_printf("LOBBY!!!"); |
||
412 | } |
||
413 | else |
||
414 | SRP_insert_tasklist(m,p); |
||
415 | } |
||
416 | |||
417 | m->nlocked[p] = 0; |
||
38 | pj | 418 | return 0; |
2 | pj | 419 | } |
38 | pj | 420 | else if (r->rclass == SRP2_RCLASS) { |
2 | pj | 421 | /* a mutex passed via SRP_useres() */ |
422 | SRP_mutex_t *mut = (SRP_mutex_t *)r; |
||
423 | |||
424 | if (mut->use[p]) |
||
425 | /* the mutex is already registered, do nothing! */ |
||
38 | pj | 426 | return -1; |
2 | pj | 427 | |
428 | /* register the mutex for the task */ |
||
429 | mut->use[p] = 1; |
||
430 | |||
431 | if (m->srpstack) |
||
432 | SRP_insertfirst_recalclist(m,mut); |
||
433 | else { |
||
434 | /* we recalc the mutex ceiling */ |
||
435 | if (mut->ceiling < m->proc_preempt[p].preempt) |
||
436 | mut->ceiling = m->proc_preempt[p].preempt; |
||
437 | |||
438 | } |
||
38 | pj | 439 | return 0; |
2 | pj | 440 | } |
38 | pj | 441 | else |
442 | return -1; |
||
2 | pj | 443 | } |
444 | |||
445 | static void SRP_res_detach(RLEVEL l, PID p) |
||
446 | { |
||
447 | SRP_mutex_resource_des *m = (SRP_mutex_resource_des *)(resource_table[l]); |
||
448 | SRP_mutex_t *mut; |
||
449 | |||
450 | if (m->proc_preempt[p].preempt == 0) |
||
451 | return; |
||
452 | |||
453 | if (m->nlocked[p]) |
||
454 | kern_raise(XMUTEX_OWNER_KILLED, p); |
||
455 | else |
||
456 | m->nlocked[p] = 0; |
||
457 | |||
458 | for (mut = m->srplist; mut; mut = mut->srplist_next) |
||
459 | { |
||
460 | if (!mut->use[p]) |
||
461 | /* the mutex is not registered, do nothing! */ |
||
462 | continue; |
||
463 | |||
464 | /* unregister the mutex for the task */ |
||
465 | mut->use[p] = 0; |
||
466 | |||
467 | if (m->srpstack) |
||
468 | SRP_insertfirst_recalclist(m,mut); |
||
469 | else |
||
470 | SRP_recalc_ceiling_value(m,mut); |
||
471 | } |
||
472 | |||
473 | /* check if current points to the task being killed */ |
||
474 | if (m->current == p) |
||
475 | m->current = m->proc_preempt[m->current].prev; |
||
476 | |||
477 | /* remove the task from the tasklist */ |
||
478 | SRP_extract_tasklist(m, p); |
||
479 | } |
||
480 | |||
481 | static int SRP_init(RLEVEL l, mutex_t *m, const mutexattr_t *a) |
||
482 | { |
||
483 | SRP_mutex_resource_des *lev = (SRP_mutex_resource_des *)(resource_table[l]); |
||
484 | SRP_mutex_t *p; |
||
485 | PID x; |
||
486 | |||
38 | pj | 487 | if (a->mclass != SRP_MCLASS) |
488 | return -1; |
||
489 | |||
2 | pj | 490 | p = (SRP_mutex_t *) kern_alloc(sizeof(SRP_mutex_t)); |
491 | |||
492 | /* control if there is enough memory; no control on init on a |
||
493 | non- destroyed mutex */ |
||
494 | |||
495 | if (!p) |
||
496 | return (ENOMEM); |
||
497 | |||
498 | res_default_model(p->r, SRP2_RCLASS); |
||
499 | p->sysceiling = 0; /* dummy value :-) */ |
||
500 | p->srpstack_next = NULL; /* dummy value :-) */ |
||
501 | |||
502 | for (x = 0; x < MAX_PROC; x++) |
||
503 | p->use[x] = 0; |
||
504 | |||
505 | p->ceiling = 0; |
||
506 | p->owner = NIL; |
||
507 | |||
508 | p->in_recalc_list = 0; |
||
509 | p->srprecalc_next = NULL; /* dummy value :-) */ |
||
510 | p->srprecalc_prev = NULL; /* dummy value :-) */ |
||
511 | |||
512 | p->srplist_next = lev->srplist; |
||
513 | p->srplist_prev = NULL; |
||
514 | if (lev->srplist) lev->srplist->srplist_prev = p; |
||
515 | lev->srplist = p; |
||
516 | |||
517 | m->mutexlevel = l; |
||
518 | m->opt = (void *)p; |
||
519 | |||
520 | return 0; |
||
521 | } |
||
522 | |||
523 | |||
524 | static int SRP_destroy(RLEVEL l, mutex_t *m) |
||
525 | { |
||
526 | SRP_mutex_resource_des *lev = (SRP_mutex_resource_des *)(resource_table[l]); |
||
527 | SRP_mutex_t *mut; |
||
528 | |||
529 | mut = m->opt; |
||
530 | |||
531 | if (mut->owner != NIL) |
||
532 | return (EBUSY); |
||
533 | |||
534 | kern_cli(); |
||
535 | |||
536 | /* the mutex isn't in the srpstack, because it is not busy */ |
||
537 | |||
538 | /* check srprecalc list */ |
||
539 | if (mut->in_recalc_list) |
||
540 | SRP_extract_recalclist(lev, mut); |
||
541 | |||
542 | /* extract from srplist */ |
||
543 | SRP_extract_srplist(lev, mut); |
||
544 | |||
545 | if (m->opt) { |
||
546 | kern_free(m->opt,sizeof(SRP_mutex_t)); |
||
547 | m->opt = NULL; |
||
548 | } |
||
549 | kern_sti(); |
||
550 | |||
551 | return 0; |
||
552 | } |
||
553 | |||
554 | static int SRP_lock(RLEVEL l, mutex_t *m) |
||
555 | { |
||
556 | SRP_mutex_resource_des *lev = (SRP_mutex_resource_des *)(resource_table[l]); |
||
557 | SRP_mutex_t *mut; |
||
558 | DWORD oldsysceiling; |
||
559 | |||
560 | kern_cli(); |
||
561 | |||
562 | mut = (SRP_mutex_t *)m->opt; |
||
563 | if (!mut) { |
||
564 | /* if the mutex is not initialized */ |
||
565 | kern_sti(); |
||
566 | return (EINVAL); |
||
567 | } |
||
568 | |||
569 | if (mut->owner == exec_shadow) { |
||
570 | /* the task already owns the mutex */ |
||
571 | kern_sti(); |
||
572 | return (EDEADLK); |
||
573 | } |
||
574 | |||
575 | if (!mut->use[exec_shadow] || |
||
576 | lev->proc_preempt[exec_shadow].preempt == 0 || |
||
577 | mut->owner != NIL) |
||
578 | { |
||
579 | // kern_printf("SRP:lev =%d owner=%d use=%d preempt=%d exec_shadow=%d\n", |
||
580 | // lev, mut->owner, |
||
581 | // mut->use[exec_shadow], |
||
582 | // lev->proc_preempt[exec_shadow].preempt,exec_shadow); |
||
14 | pj | 583 | kern_raise(XSRP_INVALID_LOCK, exec_shadow); |
2 | pj | 584 | kern_sti(); |
585 | return (EINVAL); |
||
586 | } |
||
587 | |||
588 | /* we know that: |
||
589 | - the task use the SRP protocol and the mutex that it wants to lock |
||
590 | - the mutex is free |
||
591 | => the task can lock now the mutex |
||
592 | */ |
||
593 | |||
594 | lev->nlocked[exec_shadow]++; |
||
595 | mut->owner = exec_shadow; |
||
596 | |||
597 | oldsysceiling = sysceiling(lev); |
||
598 | |||
599 | /* update the system ceiling */ |
||
600 | mut->sysceiling = (oldsysceiling>mut->ceiling) ? |
||
601 | oldsysceiling : mut->ceiling; |
||
602 | |||
603 | /* update the srpstack */ |
||
604 | mut->srpstack_next = lev->srpstack; |
||
605 | lev->srpstack = mut; |
||
606 | |||
607 | /* if the system ceiling is changed we have to change the shadows |
||
608 | Note that mut->sysceiling is the NEW sysceiling */ |
||
609 | if (oldsysceiling != mut->sysceiling) { |
||
610 | /* we set the shadow of the last task that did a lock */ |
||
611 | if (mut->srpstack_next) |
||
612 | proc_table[mut->srpstack_next->owner].shadow = exec_shadow; |
||
613 | |||
614 | /* now we set the shadow field of the remainig tasks */ |
||
615 | |||
616 | /* first, get the first task to manage */ |
||
617 | if (lev->current == NIL) |
||
618 | lev->current = lev->tasklist; |
||
619 | else |
||
620 | /* Note that because the sysceiling is increased by the lock, currrent |
||
621 | can't be at the end of the tasklist, so the operation is legal */ |
||
622 | lev->current = lev->proc_preempt[lev->current].next; |
||
623 | |||
624 | for (;;) { |
||
625 | PID x; /* for readablenesss only :-) */ |
||
626 | |||
627 | proc_table[lev->current].shadow = exec_shadow; |
||
628 | |||
629 | /* test if we have to touch the next task in the tasklist */ |
||
630 | x = lev->proc_preempt[lev->current].next; |
||
631 | if (x == NIL || |
||
632 | lev->proc_preempt[x].preempt > mut->sysceiling) |
||
633 | break; |
||
634 | |||
635 | /* look at the next task ! */ |
||
636 | lev->current = lev->proc_preempt[lev->current].next; |
||
637 | } |
||
638 | } |
||
639 | |||
640 | kern_sti(); |
||
641 | |||
642 | return 0; |
||
643 | } |
||
644 | |||
645 | /* SRP_trylock is equal to SRP_lock because the SRP_lock don't block !!! */ |
||
646 | |||
647 | static int SRP_unlock(RLEVEL l, mutex_t *m) |
||
648 | { |
||
649 | SRP_mutex_resource_des *lev; |
||
650 | SRP_mutex_t *mut; |
||
651 | DWORD newsysceiling; |
||
652 | |||
653 | lev = (SRP_mutex_resource_des *)(resource_table[l]); |
||
654 | mut = (SRP_mutex_t *)m->opt; |
||
655 | |||
656 | if (!mut) |
||
657 | return (EINVAL); |
||
658 | |||
659 | if (mut->owner != exec_shadow) { |
||
660 | /* the mutex is owned by another task!!! */ |
||
661 | kern_sti(); |
||
662 | return (EPERM); |
||
663 | } |
||
664 | |||
665 | if (!lev->srpstack || lev->srpstack != mut) { |
||
666 | /* the mutex is not the top of the stack!!! (erroneous nesting!) */ |
||
667 | kern_sti(); |
||
668 | return (EINVAL); |
||
669 | } |
||
670 | |||
671 | proc_table[exec_shadow].context = kern_context_save(); |
||
672 | |||
673 | /* the mutex is mine and it is at the top of the stack */ |
||
674 | lev->nlocked[exec_shadow]--; |
||
675 | |||
676 | mut->owner = NIL; |
||
677 | // kern_printf("Ûnlocked=%dÛ",lev->nlocked[exec_shadow]); |
||
678 | |||
679 | /* extract the top of the stack */ |
||
680 | lev->srpstack = lev->srpstack->srpstack_next; |
||
681 | |||
682 | /* if the sysceiling decreases, we update the shadows */ |
||
683 | newsysceiling = sysceiling(lev); |
||
684 | if (newsysceiling < mut->sysceiling) { |
||
685 | do { |
||
686 | proc_table[lev->current].shadow = lev->current; |
||
687 | lev->current = lev->proc_preempt[lev->current].prev; |
||
688 | } while (lev->current != NIL && |
||
689 | lev->proc_preempt[lev->current].preempt > newsysceiling); |
||
690 | |||
691 | if (lev->srpstack) |
||
692 | /* this is the stack that owns the mutex with the current sysceiling*/ |
||
693 | proc_table[lev->srpstack->owner].shadow = lev->srpstack->owner; |
||
694 | } |
||
695 | |||
696 | /* if it is the last mutex in the stack, handle lobbylist and srprecalc */ |
||
697 | if (!lev->srpstack) { |
||
698 | // kern_printf("UNLOBBY:"); |
||
699 | while (lev->lobbylist != NIL) { |
||
700 | PID x = SRP_extractfirst_lobbylist(lev); |
||
701 | // kern_printf("x=%d - ",x); |
||
702 | SRP_insert_tasklist(lev, x); |
||
703 | |||
704 | /* activate the task if it was activated while in lobby list! */ |
||
705 | if (task_unblock_activation(x)) { |
||
706 | LEVEL sl = proc_table[x].task_level; |
||
38 | pj | 707 | level_table[sl]->public_activate(sl,x); |
2 | pj | 708 | // kern_printf("activate it!!!"); |
709 | } |
||
710 | } |
||
711 | |||
712 | while (lev->srprecalc) { |
||
713 | SRP_recalc_ceiling_value(lev, lev->srprecalc); |
||
714 | SRP_extract_recalclist(lev, lev->srprecalc); |
||
715 | } |
||
716 | } |
||
717 | |||
718 | scheduler(); |
||
719 | kern_context_load(proc_table[exec_shadow].context); |
||
720 | |||
721 | return 0; |
||
722 | } |
||
723 | |||
38 | pj | 724 | RLEVEL SRP_register_module(void) |
2 | pj | 725 | { |
726 | RLEVEL l; /* the level that we register */ |
||
727 | SRP_mutex_resource_des *m; /* for readableness only */ |
||
728 | PID i; /* a counter */ |
||
729 | |||
730 | printk("SRP_register_module\n"); |
||
731 | |||
732 | /* request an entry in the level_table */ |
||
733 | l = resource_alloc_descriptor(); |
||
734 | |||
735 | /* alloc the space needed for the EDF_level_des */ |
||
736 | m = (SRP_mutex_resource_des *)kern_alloc(sizeof(SRP_mutex_resource_des)); |
||
737 | |||
738 | /* update the level_table with the new entry */ |
||
739 | resource_table[l] = (resource_des *)m; |
||
740 | |||
741 | /* fill the resource_des descriptor */ |
||
742 | m->m.r.rtype = MUTEX_RTYPE; |
||
743 | m->m.r.res_register = SRP_res_register; |
||
744 | m->m.r.res_detach = SRP_res_detach; |
||
745 | |||
746 | /* fill the mutex_resource_des descriptor */ |
||
747 | m->m.init = SRP_init; |
||
748 | m->m.destroy = SRP_destroy; |
||
749 | m->m.lock = SRP_lock; |
||
750 | m->m.trylock = SRP_lock; /* equal!!! */ |
||
751 | m->m.unlock = SRP_unlock; |
||
752 | |||
753 | /* fill the SRP_mutex_resource_des descriptor */ |
||
754 | for (i=0; i<MAX_PROC; i++) { |
||
755 | m->nlocked[i]=0; |
||
756 | m->proc_preempt[i].preempt = 0; |
||
757 | m->proc_preempt[i].next = NIL; |
||
758 | m->proc_preempt[i].prev = NIL; |
||
759 | } |
||
760 | |||
761 | m->tasklist = NIL; |
||
762 | m->current = NIL; |
||
763 | m->lobbylist = NIL; |
||
764 | |||
765 | m->srpstack = NULL; |
||
766 | m->srprecalc = NULL; |
||
767 | m->srplist = NULL; |
||
38 | pj | 768 | |
769 | return l; |
||
2 | pj | 770 | } |
771 |