Subversion Repositories shark

Rev

Rev 159 | 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
 ------------
212 giacomo 23
 CVS :        $Id: cbs.c,v 1.6 2003-07-23 09:59:11 giacomo Exp $
2 pj 24
 
25
 File:        $File$
212 giacomo 26
 Revision:    $Revision: 1.6 $
27
 Last update: $Date: 2003-07-23 09:59:11 $
2 pj 28
 ------------
29
 
30
 This file contains the aperiodic server CBS (Total Bandwidth Server)
31
 
32
 Read CBS.h for further details.
33
 
34
**/
35
 
36
/*
37
 * Copyright (C) 2000 Paolo Gai
38
 *
39
 * This program is free software; you can redistribute it and/or modify
40
 * it under the terms of the GNU General Public License as published by
41
 * the Free Software Foundation; either version 2 of the License, or
42
 * (at your option) any later version.
43
 *
44
 * This program is distributed in the hope that it will be useful,
45
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
46
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
47
 * GNU General Public License for more details.
48
 *
49
 * You should have received a copy of the GNU General Public License
50
 * along with this program; if not, write to the Free Software
51
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
52
 *
53
 */
54
 
55
 
56
#include <modules/cbs.h>
57
#include <ll/stdio.h>
58
#include <ll/string.h>
59
#include <kernel/model.h>
60
#include <kernel/descr.h>
61
#include <kernel/var.h>
62
#include <kernel/func.h>
63
#include <kernel/trace.h>
64
 
65
/*+ 4 debug purposes +*/
66
#undef CBS_TEST
67
#undef CBS_COUNTER
68
 
69
#ifdef TESTG
70
#include "drivers/glib.h"
71
TIME x,oldx;
72
extern TIME starttime;
73
#endif
74
 
75
 
76
/*+ Status used in the level +*/
77
#define CBS_IDLE          APER_STATUS_BASE   /*+ waiting the activation +*/
78
#define CBS_ZOMBIE        APER_STATUS_BASE+1 /*+ waiting the period end +*/
79
 
80
/*+ task flags +*/
81
#define CBS_SAVE_ARRIVALS 1
82
#define CBS_APERIODIC     2
212 giacomo 83
#define CBS_SLEEP         4
2 pj 84
 
85
/*+ the level redefinition for the Total Bandwidth Server level +*/
86
typedef struct {
87
  level_des l;     /*+ the standard level descriptor          +*/
88
 
89
  /* The wcet are stored in the task descriptor, but we need
90
     an array for the deadlines. We can't use the timespec_priority
91
     field because it is used by the master level!!!...
92
     Notice that however the use of the timespec_priority field
93
     does not cause any problem...                     */
94
 
95
  struct timespec cbs_dline[MAX_PROC]; /*+ CBS deadlines      +*/
96
 
97
  TIME period[MAX_PROC]; /*+ CBS activation period            +*/
98
 
99
  struct timespec reactivation_time[MAX_PROC];
100
        /*+ the time at witch  the reactivation timer is post +*/
101
  int reactivation_timer[MAX_PROC];
102
                                   /*+ the recativation timer +*/
103
 
104
  int nact[MAX_PROC]; /*+ number of pending activations       +*/
105
 
106
  BYTE flag[MAX_PROC]; /*+ task flags                         +*/
107
 
108
  int flags;       /*+ the init flags...                      +*/
109
 
110
  bandwidth_t U;   /*+ the used bandwidth by the server       +*/
111
 
112
  LEVEL scheduling_level;
113
 
114
} CBS_level_des;
115
 
116
#ifdef CBS_COUNTER
117
int cbs_counter=0;
118
int cbs_counter2=0;
119
#endif
120
 
121
 
122
static void CBS_activation(CBS_level_des *lev,
123
                           PID p,
124
                           struct timespec *acttime)
125
{
126
  JOB_TASK_MODEL job;
127
 
128
  /* we have to check if the deadline and the wcet are correct before
129
     activating a new task or an old task... */
130
 
131
  /* check 1: if the deadline is before than the actual scheduling time */
132
 
133
  /* check 2: if ( avail_time >= (cbs_dline - acttime)* (wcet/period) )
134
     (rule 7 in the CBS article!) */
135
  TIME t;
136
  struct timespec t2,t3;
137
 
138
  t = (lev->period[p] * proc_table[p].avail_time) / proc_table[p].wcet;
139
  t3.tv_sec = t / 1000000;
140
  t3.tv_nsec = (t % 1000000) * 1000;
141
 
142
  SUBTIMESPEC(&lev->cbs_dline[p], acttime, &t2);
143
 
144
  if (/* 1 */ TIMESPEC_A_LT_B(&lev->cbs_dline[p], acttime) ||
145
      /* 2 */ TIMESPEC_A_GT_B(&t3, &t2) ) {
146
/*    if (TIMESPEC_A_LT_B(&lev->cbs_dline[p], acttime) )
147
      kern_printf("$");
148
    else
212 giacomo 149
      kern_printf("(Ûdline%d.%d act%d.%d wcet%d per%d avail%dÛ)",
2 pj 150
                  lev->cbs_dline[p].tv_sec,lev->cbs_dline[p].tv_nsec/1000,
151
                  acttime->tv_sec, acttime->tv_nsec/1000,
152
                  proc_table[p].wcet, lev->period[p], proc_table[p].avail_time);
153
*/  /* we modify the deadline ... */
154
    TIMESPEC_ASSIGN(&lev->cbs_dline[p], acttime);
155
    ADDUSEC2TIMESPEC(lev->period[p], &lev->cbs_dline[p]);
156
 
157
    /* and the capacity */
158
    proc_table[p].avail_time = proc_table[p].wcet;
159
  }
160
 
161
#ifdef TESTG
162
      if (starttime && p == 3) {
163
      oldx = x;
164
      x = ((lev->cbs_dline[p].tv_sec*1000000+lev->cbs_dline[p].tv_nsec/1000)/5000 - starttime) + 20;
165
//      kern_printf("(a%d)",lev->cbs_dline[p].tv_sec*1000000+lev->cbs_dline[p].tv_nsec/1000);
166
      if (oldx > x) sys_end();
167
      if (x<640)
168
        grx_plot(x, 15, 8);
169
      }
170
#endif
171
 
172
  /* and, finally, we reinsert the task in the master level */
173
  job_task_default_model(job, lev->cbs_dline[p]);
174
  job_task_def_noexc(job);
175
  level_table[ lev->scheduling_level ]->
38 pj 176
    private_insert(lev->scheduling_level, p, (TASK_MODEL *)&job);
2 pj 177
}
178
 
179
static void CBS_avail_time_check(CBS_level_des *lev, PID p)
180
{
181
  /* there is a while because if the wcet is << than the system tick
182
     we need to postpone the deadline many times */
183
  while (proc_table[p].avail_time <= 0) {
184
    ADDUSEC2TIMESPEC(lev->period[p], &lev->cbs_dline[p]);
185
    proc_table[p].avail_time += proc_table[p].wcet;
186
 
187
#ifdef TESTG
188
    if (starttime && p == 3) {
189
    oldx = x;
190
    x = ((lev->cbs_dline[p].tv_sec*1000000+lev->cbs_dline[p].tv_nsec/1000)/5000 - starttime) + 20;
191
//      kern_printf("(e%d avail%d)",lev->cbs_dline[p].tv_sec*1000000+lev->cbs_dline[p].tv_nsec/1000,proc_table[p].avail_time);
192
    if (oldx > x) sys_end();
193
    if (x<640)
194
      grx_plot(x, 15, 2);
195
    }
196
#endif
197
  }
198
}
199
 
200
 
201
/* this is the periodic reactivation of the task... it is posted only
202
   if the task is a periodic task */
203
static void CBS_timer_reactivate(void *par)
204
{
205
  PID p = (PID) par;
206
  CBS_level_des *lev;
207
 
208
  lev = (CBS_level_des *)level_table[proc_table[p].task_level];
209
 
210
  #ifdef CBS_COUNTER
211
    if (p==5) cbs_counter++;
212
  #endif
213
 
212 giacomo 214
  if (lev->flag[p] & CBS_SLEEP && proc_table[p].status == CBS_IDLE) {
215
    proc_table[p].status = SLEEP;
216
    proc_table[p].avail_time = proc_table[p].wcet;
217
    NULL_TIMESPEC(&lev->cbs_dline[p]);
218
    return;
219
  }
220
 
2 pj 221
  if (proc_table[p].status == CBS_IDLE) {
222
    /* the task has finished the current activation and must be
223
       reactivated */
224
    CBS_activation(lev,p,&lev->reactivation_time[p]);
225
 
226
    event_need_reschedule();
227
  }
228
  else if (lev->flag[p] & CBS_SAVE_ARRIVALS)
229
    /* the task has not completed the current activation, so we save
230
       the activation incrementing nact... */
231
    lev->nact[p]++;
232
 
233
  /* repost the event at the next period end... */
234
  ADDUSEC2TIMESPEC(lev->period[p], &lev->reactivation_time[p]);
235
  lev->reactivation_timer[p] = kern_event_post(&lev->reactivation_time[p],
236
                                               CBS_timer_reactivate,
237
                                               (void *)p);
238
  #ifdef CBS_COUNTER
239
    if (p==5) cbs_counter2++;
240
  #endif
241
  /* tracer stuff */
242
  trc_logevent(TRC_INTACTIVATION,&p);
243
 
244
}
245
 
246
/*+ this function is called when a killed or ended task reach the
247
    period end +*/
248
static void CBS_timer_zombie(void *par)
249
{
250
  PID p = (PID) par;
251
  CBS_level_des *lev;
252
 
253
  lev = (CBS_level_des *)level_table[proc_table[p].task_level];
254
 
255
  /* we finally put the task in the ready queue */
256
  proc_table[p].status = FREE;
29 pj 257
  iq_insertfirst(p,&freedesc);
2 pj 258
 
259
  /* and free the allocated bandwidth */
260
  lev->U -= (MAX_BANDWIDTH/lev->period[p]) * proc_table[p].wcet;
261
 
262
}
263
 
264
 
265
/* The on-line guarantee is enabled only if the appropriate flag is set... */
38 pj 266
static int CBS_public_guarantee(LEVEL l, bandwidth_t *freebandwidth)
2 pj 267
{
268
  CBS_level_des *lev = (CBS_level_des *)(level_table[l]);
269
 
159 pj 270
  if (*freebandwidth >= lev->U) {
271
    *freebandwidth -= lev->U;
272
    return 1;
2 pj 273
  }
274
  else
159 pj 275
    return 0;
2 pj 276
}
277
 
38 pj 278
static int CBS_public_create(LEVEL l, PID p, TASK_MODEL *m)
2 pj 279
{
280
  CBS_level_des *lev = (CBS_level_des *)(level_table[l]);
38 pj 281
  SOFT_TASK_MODEL *soft;
2 pj 282
 
38 pj 283
  if (m->pclass != SOFT_PCLASS) return -1;
284
  if (m->level != 0 && m->level != l) return -1;
285
  soft = (SOFT_TASK_MODEL *)m;
286
  if (!(soft->met && soft->period)) return -1;
2 pj 287
 
38 pj 288
  soft = (SOFT_TASK_MODEL *)m;
289
 
159 pj 290
  if (lev->flags & CBS_ENABLE_GUARANTEE) {
291
    bandwidth_t b;
292
    b = (MAX_BANDWIDTH / soft->period) * soft->met;
293
 
294
    /* really update lev->U, checking an overflow... */
295
    if (MAX_BANDWIDTH - lev->U > b)
296
      lev->U += b;
297
    else
298
      return -1;
299
  }
300
 
2 pj 301
  /* Enable wcet check */
302
  proc_table[p].avail_time = soft->met;
303
  proc_table[p].wcet       = soft->met;
304
  proc_table[p].control   |= CONTROL_CAP;
305
 
306
  lev->nact[p] = 0;
307
  lev->period[p] = soft->period;
308
  NULL_TIMESPEC(&lev->cbs_dline[p]);
309
 
310
  if (soft->periodicity == APERIODIC)
311
    lev->flag[p] = CBS_APERIODIC;
312
  else
313
    lev->flag[p] = 0;
314
 
315
  if (soft->arrivals == SAVE_ARRIVALS)
316
    lev->flag[p] |= CBS_SAVE_ARRIVALS;
317
 
318
  return 0; /* OK, also if the task cannot be guaranteed... */
319
}
320
 
38 pj 321
static void CBS_public_detach(LEVEL l, PID p)
2 pj 322
{
323
  /* the CBS level doesn't introduce any dinamic allocated new field.
159 pj 324
     we have only to decrement the allocated bandwidth */
2 pj 325
 
326
  CBS_level_des *lev = (CBS_level_des *)(level_table[l]);
327
 
159 pj 328
  if (lev->flags & CBS_ENABLE_GUARANTEE) {
2 pj 329
    lev->U -= (MAX_BANDWIDTH / lev->period[p]) * proc_table[p].wcet;
159 pj 330
  }
2 pj 331
}
332
 
38 pj 333
static int CBS_public_eligible(LEVEL l, PID p)
2 pj 334
{
335
  CBS_level_des *lev = (CBS_level_des *)(level_table[l]);
336
  JOB_TASK_MODEL job;
337
 
338
  /* we have to check if the deadline and the wcet are correct...
339
     if the CBS level schedules in background with respect to others
340
     levels, there can be the case in witch a task is scheduled by
341
     schedule_time > CBS_deadline; in this case (not covered in the
342
     article because if there is only the standard scheduling policy
343
     this never apply) we reassign the deadline */
344
 
345
  if ( TIMESPEC_A_LT_B(&lev->cbs_dline[p], &schedule_time) ) {
346
    /* we kill the current activation */
347
    level_table[ lev->scheduling_level ]->
38 pj 348
      private_extract(lev->scheduling_level, p);
2 pj 349
 
350
    /* we modify the deadline ... */
351
    TIMESPEC_ASSIGN(&lev->cbs_dline[p], &schedule_time);
352
    ADDUSEC2TIMESPEC(lev->period[p], &lev->cbs_dline[p]);
353
 
354
    /* and the capacity */
355
    proc_table[p].avail_time = proc_table[p].wcet;
356
 
357
    /* and, finally, we reinsert the task in the master level */
358
    job_task_default_model(job, lev->cbs_dline[p]);
359
    job_task_def_noexc(job);
360
    level_table[ lev->scheduling_level ]->
38 pj 361
      private_insert(lev->scheduling_level, p, (TASK_MODEL *)&job);
2 pj 362
 
363
    return -1;
364
  }
365
 
366
  return 0;
367
}
368
 
38 pj 369
static void CBS_public_dispatch(LEVEL l, PID p, int nostop)
2 pj 370
{
371
  CBS_level_des *lev = (CBS_level_des *)(level_table[l]);
372
  level_table[ lev->scheduling_level ]->
38 pj 373
    private_dispatch(lev->scheduling_level,p,nostop);
2 pj 374
}
375
 
38 pj 376
static void CBS_public_epilogue(LEVEL l, PID p)
2 pj 377
{
378
  CBS_level_des *lev = (CBS_level_des *)(level_table[l]);
379
  JOB_TASK_MODEL job;
380
 
381
  /* check if the wcet is finished... */
382
  if ( proc_table[p].avail_time <= 0) {
383
    /* we kill the current activation */
384
    level_table[ lev->scheduling_level ]->
38 pj 385
      private_extract(lev->scheduling_level, p);
2 pj 386
 
387
    /* we modify the deadline according to rule 4 ... */
388
    CBS_avail_time_check(lev, p);
389
 
390
    /* and, finally, we reinsert the task in the master level */
391
    job_task_default_model(job, lev->cbs_dline[p]);
392
    job_task_def_noexc(job);
393
    level_table[ lev->scheduling_level ]->
38 pj 394
      private_insert(lev->scheduling_level, p, (TASK_MODEL *)&job);
2 pj 395
//    kern_printf("epil : dl %d per %d p %d |\n",
396
//              lev->cbs_dline[p].tv_nsec/1000,lev->period[p],p);
397
 
398
  }
399
  else
400
    /* the task has been preempted. it returns into the ready queue by
401
       calling the guest_epilogue... */
402
    level_table[ lev->scheduling_level ]->
38 pj 403
      private_epilogue(lev->scheduling_level,p);
2 pj 404
}
405
 
38 pj 406
static void CBS_public_activate(LEVEL l, PID p)
2 pj 407
{
408
  CBS_level_des *lev = (CBS_level_des *)(level_table[l]);
38 pj 409
  struct timespec t;
2 pj 410
 
212 giacomo 411
  if (lev->flag[p] & CBS_SLEEP) {
412
    lev->flag[p] &= ~CBS_SLEEP;
413
    if (proc_table[p].status != SLEEP) return;
414
  }
415
 
2 pj 416
  /* save activation (only if needed... */
417
  if (proc_table[p].status != SLEEP) {
418
    if (lev->flag[p] & CBS_SAVE_ARRIVALS)
419
      lev->nact[p]++;
420
    return;
421
  }
422
 
38 pj 423
  kern_gettime(&t);
2 pj 424
 
38 pj 425
  CBS_activation(lev, p, &t);
2 pj 426
 
427
  /* Set the reactivation timer */
428
  if (!(lev->flag[p] & CBS_APERIODIC))
429
  {
430
    /* we cannot use the deadline computed by CBS_activation because
431
       the deadline may be != from actual_time + period
432
       (if we call the task_activate after a task_sleep, and the
433
       deadline was postponed a lot...) */
38 pj 434
    TIMESPEC_ASSIGN(&lev->reactivation_time[p], &t);
2 pj 435
    ADDUSEC2TIMESPEC(lev->period[p], &lev->reactivation_time[p]);
436
//    TIMESPEC_ASSIGN(&lev->reactivation_time[p], &lev->cbs_dline[p]);
437
    lev->reactivation_timer[p] = kern_event_post(&lev->reactivation_time[p],
438
                                                 CBS_timer_reactivate,
439
                                                 (void *)p);
440
    #ifdef CBS_COUNTER
441
      if (p==5) cbs_counter2++;
442
    #endif
443
  }
444
//  kern_printf("act : %d %d |",lev->cbs_dline[p].tv_nsec/1000,p);
445
}
446
 
38 pj 447
static void CBS_public_unblock(LEVEL l, PID p)
2 pj 448
{
449
  CBS_level_des *lev = (CBS_level_des *)(level_table[l]);
450
  struct timespec acttime;
451
 
38 pj 452
  kern_gettime(&acttime);
2 pj 453
 
454
  CBS_activation(lev,p,&acttime);
455
}
456
 
38 pj 457
static void CBS_public_block(LEVEL l, PID p)
2 pj 458
{
459
  CBS_level_des *lev = (CBS_level_des *)(level_table[l]);
460
 
461
  /* check if the wcet is finished... */
462
  CBS_avail_time_check(lev, p);
463
 
464
  level_table[ lev->scheduling_level ]->
38 pj 465
    private_extract(lev->scheduling_level,p);
2 pj 466
}
467
 
38 pj 468
static int CBS_public_message(LEVEL l, PID p, void *m)
2 pj 469
{
470
  CBS_level_des *lev = (CBS_level_des *)(level_table[l]);
471
 
212 giacomo 472
  switch((long)(m)) {
2 pj 473
 
212 giacomo 474
    case (long)(NULL):
2 pj 475
 
212 giacomo 476
      /* check if the wcet is finished... */
477
      CBS_avail_time_check(lev, p);
478
 
479
      if (lev->nact[p]) {
480
        /* continue!!!! */
481
        lev->nact[p]--;
482
        level_table[ lev->scheduling_level ]->
483
          private_epilogue(lev->scheduling_level,p);
484
      } else {
485
        level_table[ lev->scheduling_level ]->
486
          private_extract(lev->scheduling_level,p);
487
 
488
        if (lev->flag[p] & CBS_APERIODIC)
489
          proc_table[p].status = SLEEP;
490
        else  /* the task is soft_periodic */
491
          proc_table[p].status = CBS_IDLE;
492
      }
493
 
494
      jet_update_endcycle(); /* Update the Jet data... */
495
      trc_logevent(TRC_ENDCYCLE,&exec_shadow); /* tracer stuff */
496
 
497
      break;
498
 
499
    case 1:
500
 
501
      lev->flag[p] |= CBS_SLEEP;
502
 
503
      break;
504
 
38 pj 505
  }
2 pj 506
 
212 giacomo 507
  return 0;
38 pj 508
 
2 pj 509
}
510
 
38 pj 511
static void CBS_public_end(LEVEL l, PID p)
2 pj 512
{
513
  CBS_level_des *lev = (CBS_level_des *)(level_table[l]);
514
 
515
  /* check if the wcet is finished... */
516
  CBS_avail_time_check(lev, p);
517
 
518
  level_table[ lev->scheduling_level ]->
38 pj 519
    private_extract(lev->scheduling_level,p);
2 pj 520
 
521
  /* we delete the reactivation timer */
522
  if (!(lev->flag[p] & CBS_APERIODIC)) {
38 pj 523
    kern_event_delete(lev->reactivation_timer[p]);
2 pj 524
    lev->reactivation_timer[p] = -1;
525
  }
526
 
527
  /* Finally, we post the zombie event. when the end period is reached,
528
     the task descriptor and banwidth are freed */
529
  proc_table[p].status = CBS_ZOMBIE;
530
  lev->reactivation_timer[p] = kern_event_post(&lev->cbs_dline[p],
531
                                               CBS_timer_zombie,
532
                                               (void *)p);
533
}
534
 
535
/* Registration functions */
536
 
537
/*+ Registration function:
538
    int flags                 the init flags ... see CBS.h +*/
38 pj 539
LEVEL CBS_register_level(int flags, LEVEL master)
2 pj 540
{
541
  LEVEL l;            /* the level that we register */
542
  CBS_level_des *lev;  /* for readableness only */
543
  PID i;              /* a counter */
544
 
545
  printk("CBS_register_level\n");
546
 
547
  /* request an entry in the level_table */
38 pj 548
  l = level_alloc_descriptor(sizeof(CBS_level_des));
2 pj 549
 
38 pj 550
  lev = (CBS_level_des *)level_table[l];
2 pj 551
 
552
  printk("    lev=%d\n",(int)lev);
553
 
554
  /* fill the standard descriptor */
555
  if (flags & CBS_ENABLE_GUARANTEE)
38 pj 556
    lev->l.public_guarantee = CBS_public_guarantee;
2 pj 557
  else
38 pj 558
    lev->l.public_guarantee = NULL;
559
  lev->l.public_create    = CBS_public_create;
560
  lev->l.public_detach    = CBS_public_detach;
561
  lev->l.public_end       = CBS_public_end;
562
  lev->l.public_eligible  = CBS_public_eligible;
563
  lev->l.public_dispatch  = CBS_public_dispatch;
564
  lev->l.public_epilogue  = CBS_public_epilogue;
565
  lev->l.public_activate  = CBS_public_activate;
566
  lev->l.public_unblock   = CBS_public_unblock;
567
  lev->l.public_block     = CBS_public_block;
568
  lev->l.public_message   = CBS_public_message;
2 pj 569
 
570
  /* fill the CBS descriptor part */
571
  for (i=0; i<MAX_PROC; i++) {
572
     NULL_TIMESPEC(&lev->cbs_dline[i]);
573
     lev->period[i] = 0;
574
     NULL_TIMESPEC(&lev->reactivation_time[i]);
575
     lev->reactivation_timer[i] = -1;
576
     lev->nact[i] = 0;
577
     lev->flag[i] = 0;
578
  }
579
 
580
 
581
  lev->U = 0;
582
 
583
  lev->scheduling_level = master;
584
 
159 pj 585
  lev->flags = flags;
38 pj 586
 
587
  return l;
2 pj 588
}
589
 
590
bandwidth_t CBS_usedbandwidth(LEVEL l)
591
{
592
  CBS_level_des *lev = (CBS_level_des *)(level_table[l]);
38 pj 593
 
594
  return lev->U;
2 pj 595
}
596
 
597
int CBS_get_nact(LEVEL l, PID p)
598
{
599
  CBS_level_des *lev = (CBS_level_des *)(level_table[l]);
600
 
601
  return lev->nact[p];
602
}
603