Subversion Repositories shark

Rev

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