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