Rev 29 | 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: ps.c,v 1.4 2003-01-07 17:07:50 pj Exp $ |
2 | pj | 24 | |
25 | File: $File$ |
||
38 | pj | 26 | Revision: $Revision: 1.4 $ |
27 | Last update: $Date: 2003-01-07 17:07:50 $ |
||
2 | pj | 28 | ------------ |
29 | |||
30 | This file contains the aperiodic server PS (Polling Server) |
||
31 | |||
32 | when scheduling in background the flags field has the PS_BACKGROUND bit set |
||
33 | |||
34 | when scheduling a task because it is pointed by another task via shadows, |
||
35 | the task have to be extracted from the wait queue or the master level. To |
||
36 | check this we have to look at the activated field; it is != NIL if a task |
||
37 | is inserted into the master level. Only a task at a time can be inserted |
||
38 | into the master level. |
||
39 | |||
40 | The capacity of the server must be updated |
||
41 | - when scheduling a task normally |
||
42 | - when scheduling a task because it is pointed by a shadow |
||
43 | but not when scheduling in background. |
||
44 | |||
45 | When a task is extracted from the system no scheduling has to be done |
||
46 | until the task reenter into the system. to implement this, when a task |
||
47 | is extracted we block the background scheduling (the scheduling with the |
||
48 | master level is already blocked because the activated field is not |
||
49 | reset to NIL) using the PS_BACKGROUNDBLOCK bit. |
||
50 | |||
51 | nact[p] is -1 if the task set the activations to SKIP, >= 0 otherwise |
||
52 | |||
53 | Note that if the period event fires and there aren't any task to schedule, |
||
54 | the server capacity is set to 0. This is correct, but there is a subtle |
||
55 | variant: the server capacity may be set to 0 later because if at the |
||
56 | period end the running task have priority > than the server, the capacity |
||
57 | may be set to zero the first time the server become the highest priority |
||
58 | running task and there aren't task to serve. The second implementation |
||
59 | is more efficient but more complicated, because normally we don't know the |
||
60 | priority of the running task. |
||
61 | |||
62 | An implementation can be done in this way: when there are not task to |
||
63 | schedule, we does not set the lev->activated field to nil, but to a "dummy" |
||
64 | task that is inserted into the master level queue. |
||
65 | When the master level scheduler try to schedule the "dummy" task (this is |
||
66 | the situation in witch there are not task to schedule and the PS is the |
||
67 | task with greater priority), it calls the PS_task_eligible, that set the |
||
68 | server capacity to 0, remove the dummy task from the queue with a guest_end |
||
69 | and ask to reschedule. |
||
70 | |||
71 | Because this implementation is more complex than the first, I don't |
||
72 | implement it... see (*), near line 169, 497 and 524 |
||
73 | |||
74 | |||
75 | Read PS.h for further details. |
||
76 | |||
77 | **/ |
||
78 | |||
79 | /* |
||
80 | * Copyright (C) 2000 Paolo Gai |
||
81 | * |
||
82 | * This program is free software; you can redistribute it and/or modify |
||
83 | * it under the terms of the GNU General Public License as published by |
||
84 | * the Free Software Foundation; either version 2 of the License, or |
||
85 | * (at your option) any later version. |
||
86 | * |
||
87 | * This program is distributed in the hope that it will be useful, |
||
88 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
89 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
90 | * GNU General Public License for more details. |
||
91 | * |
||
92 | * You should have received a copy of the GNU General Public License |
||
93 | * along with this program; if not, write to the Free Software |
||
94 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||
95 | * |
||
96 | */ |
||
97 | |||
98 | |||
99 | #include <modules/ps.h> |
||
100 | #include <ll/stdio.h> |
||
101 | #include <ll/string.h> |
||
102 | #include <kernel/model.h> |
||
103 | #include <kernel/descr.h> |
||
104 | #include <kernel/var.h> |
||
105 | #include <kernel/func.h> |
||
38 | pj | 106 | #include <kernel/trace.h> |
2 | pj | 107 | |
108 | /*+ Status used in the level +*/ |
||
109 | #define PS_WAIT APER_STATUS_BASE /*+ waiting the service +*/ |
||
110 | |||
111 | /*+ the level redefinition for the Total Bandwidth Server level +*/ |
||
112 | typedef struct { |
||
113 | level_des l; /*+ the standard level descriptor +*/ |
||
114 | |||
115 | /* The wcet are stored in the task descriptor's priority |
||
116 | field, so no other fields are needed */ |
||
117 | |||
118 | int nact[MAX_PROC]; /*+ number of pending activations +*/ |
||
119 | |||
120 | struct timespec lastdline; /*+ the last deadline assigned to |
||
121 | a PS task +*/ |
||
122 | |||
123 | int Cs; /*+ server capacity +*/ |
||
124 | int availCs; /*+ server avail time +*/ |
||
125 | |||
29 | pj | 126 | IQUEUE wait; /*+ the wait queue of the PS +*/ |
2 | pj | 127 | PID activated; /*+ the task inserted in another queue +*/ |
128 | |||
129 | int flags; /*+ the init flags... +*/ |
||
130 | |||
131 | bandwidth_t U; /*+ the used bandwidth by the server +*/ |
||
132 | int period; |
||
133 | |||
134 | LEVEL scheduling_level; |
||
135 | |||
136 | } PS_level_des; |
||
137 | |||
138 | /* This static function activates the task pointed by lev->activated) */ |
||
139 | static __inline__ void PS_activation(PS_level_des *lev) |
||
140 | { |
||
141 | PID p; /* for readableness */ |
||
142 | JOB_TASK_MODEL j; /* the guest model */ |
||
143 | LEVEL m; /* the master level... only for readableness*/ |
||
144 | |||
145 | p = lev->activated; |
||
146 | m = lev->scheduling_level; |
||
147 | job_task_default_model(j,lev->lastdline); |
||
148 | job_task_def_period(j,lev->period); |
||
38 | pj | 149 | level_table[m]->private_insert(m,p,(TASK_MODEL *)&j); |
2 | pj | 150 | // kern_printf("(%d %d)",lev->lastdline.tv_sec,lev->lastdline.tv_nsec); |
151 | } |
||
152 | |||
153 | static void PS_deadline_timer(void *a) |
||
154 | { |
||
155 | PS_level_des *lev = (PS_level_des *)(level_table[(LEVEL)a]); |
||
156 | |||
157 | ADDUSEC2TIMESPEC(lev->period, &lev->lastdline); |
||
158 | |||
159 | // kern_printf("(%d:%d %d)",lev->lastdline.tv_sec,lev->lastdline.tv_nsec, lev->period); |
||
160 | if (lev->availCs >= 0) |
||
161 | lev->availCs = lev->Cs; |
||
162 | else |
||
163 | lev->availCs += lev->Cs; |
||
164 | |||
165 | /* availCs may be <0 because a task executed via a shadow fo many time |
||
166 | lev->activated == NIL only if the prec task was finished and there |
||
167 | was not any other task to be put in the ready queue |
||
168 | ... we are now activating the next task */ |
||
169 | if (lev->availCs > 0 && lev->activated == NIL) { |
||
29 | pj | 170 | if (iq_query_first(&lev->wait) != NIL) { |
171 | lev->activated = iq_getfirst(&lev->wait); |
||
2 | pj | 172 | PS_activation(lev); |
173 | event_need_reschedule(); |
||
174 | } |
||
175 | else |
||
176 | lev->availCs = 0; /* see note (*) at the begin of the file */ |
||
177 | } |
||
178 | |||
179 | kern_event_post(&lev->lastdline, PS_deadline_timer, a); |
||
180 | // kern_printf("!"); |
||
181 | } |
||
182 | |||
38 | pj | 183 | static PID PS_public_schedulerbackground(LEVEL l) |
2 | pj | 184 | { |
185 | /* the PS catch the background time to exec aperiodic activities */ |
||
186 | PS_level_des *lev = (PS_level_des *)(level_table[l]); |
||
187 | |||
188 | lev->flags |= PS_BACKGROUND; |
||
189 | |||
190 | if (lev->flags & PS_BACKGROUND_BLOCK) |
||
191 | return NIL; |
||
192 | else |
||
29 | pj | 193 | return iq_query_first(&lev->wait); |
2 | pj | 194 | } |
195 | |||
196 | /* The on-line guarantee is enabled only if the appropriate flag is set... */ |
||
38 | pj | 197 | static int PS_public_guaranteeEDF(LEVEL l, bandwidth_t *freebandwidth) |
2 | pj | 198 | { |
199 | PS_level_des *lev = (PS_level_des *)(level_table[l]); |
||
200 | |||
201 | if (*freebandwidth >= lev->U) { |
||
202 | *freebandwidth -= lev->U; |
||
203 | return 1; |
||
204 | } |
||
205 | else |
||
206 | return 0; |
||
207 | } |
||
208 | |||
38 | pj | 209 | static int PS_public_guaranteeRM(LEVEL l, bandwidth_t *freebandwidth) |
2 | pj | 210 | { |
211 | PS_level_des *lev = (PS_level_des *)(level_table[l]); |
||
212 | |||
213 | if (*freebandwidth > lev->U + RM_MINFREEBANDWIDTH) { |
||
214 | *freebandwidth -= lev->U; |
||
215 | return 1; |
||
216 | } |
||
217 | else |
||
218 | return 0; |
||
219 | } |
||
220 | |||
38 | pj | 221 | static int PS_public_create(LEVEL l, PID p, TASK_MODEL *m) |
2 | pj | 222 | { |
223 | PS_level_des *lev = (PS_level_des *)(level_table[l]); |
||
38 | pj | 224 | SOFT_TASK_MODEL *s; |
2 | pj | 225 | |
38 | pj | 226 | if (m->pclass != SOFT_PCLASS) return -1; |
227 | if (m->level != 0 && m->level != l) return -1; |
||
228 | s = (SOFT_TASK_MODEL *)m; |
||
229 | if (s->periodicity != APERIODIC) return -1; |
||
230 | |||
231 | s = (SOFT_TASK_MODEL *)m; |
||
2 | pj | 232 | |
233 | if (s->arrivals == SAVE_ARRIVALS) |
||
234 | lev->nact[p] = 0; |
||
235 | else |
||
236 | lev->nact[p] = -1; |
||
237 | |||
238 | return 0; /* OK, also if the task cannot be guaranteed... */ |
||
239 | } |
||
240 | |||
38 | pj | 241 | static void PS_public_dispatch(LEVEL l, PID p, int nostop) |
2 | pj | 242 | { |
243 | PS_level_des *lev = (PS_level_des *)(level_table[l]); |
||
244 | struct timespec ty; |
||
245 | |||
246 | // if (nostop) kern_printf("NOSTOP!!!!!!!!!!!!"); |
||
247 | /* there is at least one task ready inserted in an EDF or similar |
||
248 | level note that we can't check the status because the scheduler set it |
||
249 | to exe before calling task_dispatch. we have to check |
||
250 | lev->activated != p instead */ |
||
251 | if (lev->activated != p) { |
||
29 | pj | 252 | iq_extract(p, &lev->wait); |
2 | pj | 253 | //kern_printf("#%d#",p); |
254 | } |
||
255 | else { |
||
256 | //if (nostop) kern_printf("(gd status=%d)",proc_table[p].status); |
||
257 | level_table[ lev->scheduling_level ]-> |
||
38 | pj | 258 | private_dispatch(lev->scheduling_level,p,nostop); |
2 | pj | 259 | } |
260 | |||
261 | /* set the capacity timer */ |
||
262 | if (!nostop) { |
||
263 | TIMESPEC_ASSIGN(&ty, &schedule_time); |
||
264 | ADDUSEC2TIMESPEC(lev->availCs,&ty); |
||
265 | cap_timer = kern_event_post(&ty, capacity_timer, NULL); |
||
266 | } |
||
267 | |||
268 | // kern_printf("(disp %d %d)",ty.tv_sec, ty.tv_nsec); |
||
269 | } |
||
270 | |||
38 | pj | 271 | static void PS_public_epilogue(LEVEL l, PID p) |
2 | pj | 272 | { |
273 | PS_level_des *lev = (PS_level_des *)(level_table[l]); |
||
274 | struct timespec ty; |
||
275 | TIME tx; |
||
276 | |||
277 | /* update the server capacity */ |
||
278 | if (lev->flags & PS_BACKGROUND) |
||
279 | lev->flags &= ~PS_BACKGROUND; |
||
280 | else { |
||
281 | SUBTIMESPEC(&schedule_time, &cap_lasttime, &ty); |
||
282 | tx = TIMESPEC2USEC(&ty); |
||
283 | lev->availCs -= tx; |
||
284 | } |
||
285 | |||
286 | // kern_printf("(epil %d %d)",lev->availCs, proc_table[p].avail_time); |
||
287 | |||
288 | /* check if the server capacity is finished... */ |
||
289 | if (lev->availCs < 0) { |
||
290 | // kern_printf("(epil Cs%d %d:%d act%d p%d)", |
||
291 | // lev->availCs,proc_table[p].timespec_priority.tv_sec, |
||
292 | // proc_table[p].timespec_priority.tv_nsec, |
||
293 | // lev->activated,p); |
||
294 | /* the server slice has finished... do the task_end!!! |
||
295 | a first version of the module used the task_endcycle, but it was |
||
296 | not conceptually correct because the task didn't stop because it |
||
297 | finished all the work but because the server didn't have budget! |
||
298 | So, if the task_endcycle is called, the task remain into the |
||
299 | master level, and we can't wake him up if, for example, another |
||
300 | task point the shadow to it!!!*/ |
||
301 | if (lev->activated == p) |
||
302 | level_table[ lev->scheduling_level ]-> |
||
38 | pj | 303 | private_extract(lev->scheduling_level,p); |
29 | pj | 304 | iq_insertfirst(p, &lev->wait); |
2 | pj | 305 | proc_table[p].status = PS_WAIT; |
306 | lev->activated = NIL; |
||
307 | } |
||
308 | else |
||
309 | /* the task has been preempted. it returns into the ready queue or to the |
||
310 | wait queue by calling the guest_epilogue... */ |
||
311 | if (lev->activated == p) {//kern_printf("Û1"); |
||
312 | level_table[ lev->scheduling_level ]-> |
||
38 | pj | 313 | private_epilogue(lev->scheduling_level,p); |
2 | pj | 314 | } else { //kern_printf("Û2"); |
29 | pj | 315 | iq_insertfirst(p, &lev->wait); |
2 | pj | 316 | proc_table[p].status = PS_WAIT; |
317 | } |
||
318 | } |
||
319 | |||
38 | pj | 320 | static void PS_public_activate(LEVEL l, PID p) |
2 | pj | 321 | { |
322 | PS_level_des *lev = (PS_level_des *)(level_table[l]); |
||
323 | |||
324 | if (lev->activated == p || proc_table[p].status == PS_WAIT) { |
||
325 | if (lev->nact[p] != -1) |
||
326 | lev->nact[p]++; |
||
327 | } |
||
328 | else if (proc_table[p].status == SLEEP) { |
||
329 | |||
330 | if (lev->activated == NIL && lev->availCs > 0) { |
||
331 | lev->activated = p; |
||
332 | PS_activation(lev); |
||
333 | } |
||
334 | else { |
||
29 | pj | 335 | iq_insertlast(p, &lev->wait); |
2 | pj | 336 | proc_table[p].status = PS_WAIT; |
337 | } |
||
338 | } |
||
339 | else |
||
340 | { kern_printf("PS_REJ%d %d %d %d ",p, proc_table[p].status, lev->activated, lev->wait.first); |
||
341 | return; } |
||
342 | |||
343 | } |
||
344 | |||
38 | pj | 345 | static void PS_public_unblock(LEVEL l, PID p) |
2 | pj | 346 | { |
347 | PS_level_des *lev = (PS_level_des *)(level_table[l]); |
||
348 | |||
349 | lev->flags &= ~PS_BACKGROUND_BLOCK; |
||
350 | |||
351 | lev->activated = -1; |
||
352 | |||
353 | /* when we reinsert the task into the system, the server capacity |
||
354 | is always 0 because nobody executes with the PS before... */ |
||
29 | pj | 355 | iq_insertfirst(p, &lev->wait); |
2 | pj | 356 | proc_table[p].status = PS_WAIT; |
357 | } |
||
358 | |||
38 | pj | 359 | static void PS_public_block(LEVEL l, PID p) |
2 | pj | 360 | { |
361 | PS_level_des *lev = (PS_level_des *)(level_table[l]); |
||
362 | |||
363 | /* update the server capacity */ |
||
364 | lev->availCs = 0; |
||
365 | |||
366 | lev->flags |= PS_BACKGROUND_BLOCK; |
||
367 | |||
368 | if (lev->activated == p) |
||
369 | level_table[ lev->scheduling_level ]-> |
||
38 | pj | 370 | private_extract(lev->scheduling_level,p); |
2 | pj | 371 | } |
372 | |||
38 | pj | 373 | static int PS_public_message(LEVEL l, PID p, void *m) |
2 | pj | 374 | { |
375 | PS_level_des *lev = (PS_level_des *)(level_table[l]); |
||
376 | struct timespec ty; |
||
377 | TIME tx; |
||
378 | |||
379 | /* update the server capacity */ |
||
380 | if (lev->flags & PS_BACKGROUND) |
||
381 | lev->flags &= ~PS_BACKGROUND; |
||
382 | else { |
||
383 | SUBTIMESPEC(&schedule_time, &cap_lasttime, &ty); |
||
384 | tx = TIMESPEC2USEC(&ty); |
||
385 | lev->availCs -= tx; |
||
386 | } |
||
387 | |||
388 | if (lev->activated == p) |
||
389 | level_table[ lev->scheduling_level ]-> |
||
38 | pj | 390 | private_extract(lev->scheduling_level,p); |
2 | pj | 391 | else |
29 | pj | 392 | iq_extract(p, &lev->wait); |
2 | pj | 393 | |
394 | if (lev->nact[p] > 0) |
||
395 | { |
||
396 | lev->nact[p]--; |
||
29 | pj | 397 | iq_insertlast(p, &lev->wait); |
2 | pj | 398 | proc_table[p].status = PS_WAIT; |
399 | } |
||
400 | else |
||
401 | proc_table[p].status = SLEEP; |
||
402 | |||
29 | pj | 403 | lev->activated = iq_getfirst(&lev->wait); |
2 | pj | 404 | if (lev->activated == NIL) |
405 | lev->availCs = 0; /* see note (*) at the begin of the file */ |
||
406 | else |
||
407 | PS_activation(lev); |
||
38 | pj | 408 | |
409 | jet_update_endcycle(); /* Update the Jet data... */ |
||
410 | trc_logevent(TRC_ENDCYCLE,&exec_shadow); /* tracer stuff */ |
||
411 | |||
412 | return 0; |
||
2 | pj | 413 | } |
414 | |||
38 | pj | 415 | static void PS_public_end(LEVEL l, PID p) |
2 | pj | 416 | { |
417 | PS_level_des *lev = (PS_level_des *)(level_table[l]); |
||
418 | struct timespec ty; |
||
419 | TIME tx; |
||
420 | |||
421 | /* update the server capacity */ |
||
422 | if (lev->flags & PS_BACKGROUND) |
||
423 | lev->flags &= ~PS_BACKGROUND; |
||
424 | else { |
||
425 | SUBTIMESPEC(&schedule_time, &cap_lasttime, &ty); |
||
426 | tx = TIMESPEC2USEC(&ty); |
||
427 | lev->availCs -= tx; |
||
428 | } |
||
429 | |||
430 | if (lev->activated == p) |
||
431 | level_table[ lev->scheduling_level ]-> |
||
38 | pj | 432 | private_extract(lev->scheduling_level,p); |
2 | pj | 433 | |
434 | proc_table[p].status = FREE; |
||
29 | pj | 435 | iq_insertfirst(p,&freedesc); |
2 | pj | 436 | |
29 | pj | 437 | lev->activated = iq_getfirst(&lev->wait); |
2 | pj | 438 | if (lev->activated == NIL) |
439 | lev->availCs = 0; /* see note (*) at the begin of the file */ |
||
440 | else |
||
441 | PS_activation(lev); |
||
442 | } |
||
443 | |||
444 | /* Registration functions */ |
||
445 | |||
446 | |||
447 | /*+ This init function install the PS deadline timer |
||
448 | +*/ |
||
449 | static void PS_dline_install(void *l) |
||
450 | { |
||
451 | PS_level_des *lev = (PS_level_des *)(level_table[(LEVEL)l]); |
||
452 | |||
38 | pj | 453 | kern_gettime(&lev->lastdline); |
2 | pj | 454 | ADDUSEC2TIMESPEC(lev->period, &lev->lastdline); |
455 | |||
456 | kern_event_post(&lev->lastdline, PS_deadline_timer, l); |
||
457 | } |
||
458 | |||
459 | |||
460 | |||
461 | /*+ Registration function: |
||
462 | int flags the init flags ... see PS.h +*/ |
||
38 | pj | 463 | LEVEL PS_register_level(int flags, LEVEL master, int Cs, int per) |
2 | pj | 464 | { |
465 | LEVEL l; /* the level that we register */ |
||
466 | PS_level_des *lev; /* for readableness only */ |
||
467 | PID i; /* a counter */ |
||
468 | |||
469 | printk("PS_register_level\n"); |
||
470 | |||
471 | /* request an entry in the level_table */ |
||
38 | pj | 472 | l = level_alloc_descriptor(sizeof(PS_level_des)); |
2 | pj | 473 | |
38 | pj | 474 | lev = (PS_level_des *)level_table[l]; |
2 | pj | 475 | |
476 | printk(" lev=%d\n",(int)lev); |
||
477 | |||
478 | /* fill the standard descriptor */ |
||
479 | |||
480 | if (flags & PS_ENABLE_BACKGROUND) |
||
38 | pj | 481 | lev->l.public_scheduler = PS_public_schedulerbackground; |
2 | pj | 482 | |
483 | if (flags & PS_ENABLE_GUARANTEE_EDF) |
||
38 | pj | 484 | lev->l.public_guarantee = PS_public_guaranteeEDF; |
2 | pj | 485 | else if (flags & PS_ENABLE_GUARANTEE_RM) |
38 | pj | 486 | lev->l.public_guarantee = PS_public_guaranteeRM; |
2 | pj | 487 | else |
38 | pj | 488 | lev->l.public_guarantee = NULL; |
2 | pj | 489 | |
38 | pj | 490 | lev->l.public_create = PS_public_create; |
491 | lev->l.public_end = PS_public_end; |
||
492 | lev->l.public_dispatch = PS_public_dispatch; |
||
493 | lev->l.public_epilogue = PS_public_epilogue; |
||
494 | lev->l.public_activate = PS_public_activate; |
||
495 | lev->l.public_unblock = PS_public_unblock; |
||
496 | lev->l.public_block = PS_public_block; |
||
497 | lev->l.public_message = PS_public_message; |
||
2 | pj | 498 | |
499 | /* fill the PS descriptor part */ |
||
500 | |||
501 | for (i=0; i<MAX_PROC; i++) |
||
502 | lev->nact[i] = -1; |
||
503 | |||
504 | lev->Cs = Cs; |
||
505 | lev->availCs = 0; |
||
506 | |||
507 | lev->period = per; |
||
508 | |||
29 | pj | 509 | iq_init(&lev->wait, &freedesc, 0); |
2 | pj | 510 | lev->activated = NIL; |
511 | |||
512 | lev->U = (MAX_BANDWIDTH / per) * Cs; |
||
513 | |||
514 | lev->scheduling_level = master; |
||
515 | |||
516 | lev->flags = flags & 0x07; |
||
517 | |||
518 | sys_atrunlevel(PS_dline_install,(void *) l, RUNLEVEL_INIT); |
||
38 | pj | 519 | |
520 | return l; |
||
2 | pj | 521 | } |
522 | |||
523 | bandwidth_t PS_usedbandwidth(LEVEL l) |
||
524 | { |
||
525 | PS_level_des *lev = (PS_level_des *)(level_table[l]); |
||
38 | pj | 526 | |
527 | return lev->U; |
||
2 | pj | 528 | } |
529 |