Subversion Repositories shark

Rev

Rev 38 | Rev 212 | 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
 ------------
159 pj 23
 CVS :        $Id: cbs.c,v 1.5 2003-05-05 07:31:43 pj Exp $
2 pj 24
 
25
 File:        $File$
159 pj 26
 Revision:    $Revision: 1.5 $
27
 Last update: $Date: 2003-05-05 07:31:43 $
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
 
159 pj 262
  if (*freebandwidth >= lev->U) {
263
    *freebandwidth -= lev->U;
264
    return 1;
2 pj 265
  }
266
  else
159 pj 267
    return 0;
2 pj 268
}
269
 
38 pj 270
static int CBS_public_create(LEVEL l, PID p, TASK_MODEL *m)
2 pj 271
{
272
  CBS_level_des *lev = (CBS_level_des *)(level_table[l]);
38 pj 273
  SOFT_TASK_MODEL *soft;
2 pj 274
 
38 pj 275
  if (m->pclass != SOFT_PCLASS) return -1;
276
  if (m->level != 0 && m->level != l) return -1;
277
  soft = (SOFT_TASK_MODEL *)m;
278
  if (!(soft->met && soft->period)) return -1;
2 pj 279
 
38 pj 280
  soft = (SOFT_TASK_MODEL *)m;
281
 
159 pj 282
  if (lev->flags & CBS_ENABLE_GUARANTEE) {
283
    bandwidth_t b;
284
    b = (MAX_BANDWIDTH / soft->period) * soft->met;
285
 
286
    /* really update lev->U, checking an overflow... */
287
    if (MAX_BANDWIDTH - lev->U > b)
288
      lev->U += b;
289
    else
290
      return -1;
291
  }
292
 
2 pj 293
  /* Enable wcet check */
294
  proc_table[p].avail_time = soft->met;
295
  proc_table[p].wcet       = soft->met;
296
  proc_table[p].control   |= CONTROL_CAP;
297
 
298
  lev->nact[p] = 0;
299
  lev->period[p] = soft->period;
300
  NULL_TIMESPEC(&lev->cbs_dline[p]);
301
 
302
  if (soft->periodicity == APERIODIC)
303
    lev->flag[p] = CBS_APERIODIC;
304
  else
305
    lev->flag[p] = 0;
306
 
307
  if (soft->arrivals == SAVE_ARRIVALS)
308
    lev->flag[p] |= CBS_SAVE_ARRIVALS;
309
 
310
  return 0; /* OK, also if the task cannot be guaranteed... */
311
}
312
 
38 pj 313
static void CBS_public_detach(LEVEL l, PID p)
2 pj 314
{
315
  /* the CBS level doesn't introduce any dinamic allocated new field.
159 pj 316
     we have only to decrement the allocated bandwidth */
2 pj 317
 
318
  CBS_level_des *lev = (CBS_level_des *)(level_table[l]);
319
 
159 pj 320
  if (lev->flags & CBS_ENABLE_GUARANTEE) {
2 pj 321
    lev->U -= (MAX_BANDWIDTH / lev->period[p]) * proc_table[p].wcet;
159 pj 322
  }
2 pj 323
}
324
 
38 pj 325
static int CBS_public_eligible(LEVEL l, PID p)
2 pj 326
{
327
  CBS_level_des *lev = (CBS_level_des *)(level_table[l]);
328
  JOB_TASK_MODEL job;
329
 
330
  /* we have to check if the deadline and the wcet are correct...
331
     if the CBS level schedules in background with respect to others
332
     levels, there can be the case in witch a task is scheduled by
333
     schedule_time > CBS_deadline; in this case (not covered in the
334
     article because if there is only the standard scheduling policy
335
     this never apply) we reassign the deadline */
336
 
337
  if ( TIMESPEC_A_LT_B(&lev->cbs_dline[p], &schedule_time) ) {
338
    /* we kill the current activation */
339
    level_table[ lev->scheduling_level ]->
38 pj 340
      private_extract(lev->scheduling_level, p);
2 pj 341
 
342
    /* we modify the deadline ... */
343
    TIMESPEC_ASSIGN(&lev->cbs_dline[p], &schedule_time);
344
    ADDUSEC2TIMESPEC(lev->period[p], &lev->cbs_dline[p]);
345
 
346
    /* and the capacity */
347
    proc_table[p].avail_time = proc_table[p].wcet;
348
 
349
    /* and, finally, we reinsert the task in the master level */
350
    job_task_default_model(job, lev->cbs_dline[p]);
351
    job_task_def_noexc(job);
352
    level_table[ lev->scheduling_level ]->
38 pj 353
      private_insert(lev->scheduling_level, p, (TASK_MODEL *)&job);
2 pj 354
 
355
    return -1;
356
  }
357
 
358
  return 0;
359
}
360
 
38 pj 361
static void CBS_public_dispatch(LEVEL l, PID p, int nostop)
2 pj 362
{
363
  CBS_level_des *lev = (CBS_level_des *)(level_table[l]);
364
  level_table[ lev->scheduling_level ]->
38 pj 365
    private_dispatch(lev->scheduling_level,p,nostop);
2 pj 366
}
367
 
38 pj 368
static void CBS_public_epilogue(LEVEL l, PID p)
2 pj 369
{
370
  CBS_level_des *lev = (CBS_level_des *)(level_table[l]);
371
  JOB_TASK_MODEL job;
372
 
373
  /* check if the wcet is finished... */
374
  if ( proc_table[p].avail_time <= 0) {
375
    /* we kill the current activation */
376
    level_table[ lev->scheduling_level ]->
38 pj 377
      private_extract(lev->scheduling_level, p);
2 pj 378
 
379
    /* we modify the deadline according to rule 4 ... */
380
    CBS_avail_time_check(lev, p);
381
 
382
    /* and, finally, we reinsert the task in the master level */
383
    job_task_default_model(job, lev->cbs_dline[p]);
384
    job_task_def_noexc(job);
385
    level_table[ lev->scheduling_level ]->
38 pj 386
      private_insert(lev->scheduling_level, p, (TASK_MODEL *)&job);
2 pj 387
//    kern_printf("epil : dl %d per %d p %d |\n",
388
//              lev->cbs_dline[p].tv_nsec/1000,lev->period[p],p);
389
 
390
  }
391
  else
392
    /* the task has been preempted. it returns into the ready queue by
393
       calling the guest_epilogue... */
394
    level_table[ lev->scheduling_level ]->
38 pj 395
      private_epilogue(lev->scheduling_level,p);
2 pj 396
}
397
 
38 pj 398
static void CBS_public_activate(LEVEL l, PID p)
2 pj 399
{
400
  CBS_level_des *lev = (CBS_level_des *)(level_table[l]);
38 pj 401
  struct timespec t;
2 pj 402
 
403
  /* save activation (only if needed... */
404
  if (proc_table[p].status != SLEEP) {
405
    if (lev->flag[p] & CBS_SAVE_ARRIVALS)
406
      lev->nact[p]++;
407
    return;
408
  }
409
 
38 pj 410
  kern_gettime(&t);
2 pj 411
 
38 pj 412
  CBS_activation(lev, p, &t);
2 pj 413
 
414
  /* Set the reactivation timer */
415
  if (!(lev->flag[p] & CBS_APERIODIC))
416
  {
417
    /* we cannot use the deadline computed by CBS_activation because
418
       the deadline may be != from actual_time + period
419
       (if we call the task_activate after a task_sleep, and the
420
       deadline was postponed a lot...) */
38 pj 421
    TIMESPEC_ASSIGN(&lev->reactivation_time[p], &t);
2 pj 422
    ADDUSEC2TIMESPEC(lev->period[p], &lev->reactivation_time[p]);
423
//    TIMESPEC_ASSIGN(&lev->reactivation_time[p], &lev->cbs_dline[p]);
424
    lev->reactivation_timer[p] = kern_event_post(&lev->reactivation_time[p],
425
                                                 CBS_timer_reactivate,
426
                                                 (void *)p);
427
    #ifdef CBS_COUNTER
428
      if (p==5) cbs_counter2++;
429
    #endif
430
  }
431
//  kern_printf("act : %d %d |",lev->cbs_dline[p].tv_nsec/1000,p);
432
}
433
 
38 pj 434
static void CBS_public_unblock(LEVEL l, PID p)
2 pj 435
{
436
  CBS_level_des *lev = (CBS_level_des *)(level_table[l]);
437
  struct timespec acttime;
438
 
38 pj 439
  kern_gettime(&acttime);
2 pj 440
 
441
  CBS_activation(lev,p,&acttime);
442
}
443
 
38 pj 444
static void CBS_public_block(LEVEL l, PID p)
2 pj 445
{
446
  CBS_level_des *lev = (CBS_level_des *)(level_table[l]);
447
 
448
  /* check if the wcet is finished... */
449
  CBS_avail_time_check(lev, p);
450
 
451
  level_table[ lev->scheduling_level ]->
38 pj 452
    private_extract(lev->scheduling_level,p);
2 pj 453
}
454
 
38 pj 455
static int CBS_public_message(LEVEL l, PID p, void *m)
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
  if (lev->nact[p]) {
463
    /* continue!!!! */
464
    lev->nact[p]--;
465
    level_table[ lev->scheduling_level ]->
38 pj 466
      private_epilogue(lev->scheduling_level,p);
2 pj 467
  }
468
  else {
469
    level_table[ lev->scheduling_level ]->
38 pj 470
      private_extract(lev->scheduling_level,p);
2 pj 471
 
472
    if (lev->flag[p] & CBS_APERIODIC)
473
      proc_table[p].status = SLEEP;
474
    else  /* the task is soft_periodic */
475
      proc_table[p].status = CBS_IDLE;
38 pj 476
  }
2 pj 477
 
38 pj 478
  jet_update_endcycle(); /* Update the Jet data... */
479
  trc_logevent(TRC_ENDCYCLE,&exec_shadow); /* tracer stuff */
480
 
481
  return 0;
2 pj 482
}
483
 
38 pj 484
static void CBS_public_end(LEVEL l, PID p)
2 pj 485
{
486
  CBS_level_des *lev = (CBS_level_des *)(level_table[l]);
487
 
488
  /* check if the wcet is finished... */
489
  CBS_avail_time_check(lev, p);
490
 
491
  level_table[ lev->scheduling_level ]->
38 pj 492
    private_extract(lev->scheduling_level,p);
2 pj 493
 
494
  /* we delete the reactivation timer */
495
  if (!(lev->flag[p] & CBS_APERIODIC)) {
38 pj 496
    kern_event_delete(lev->reactivation_timer[p]);
2 pj 497
    lev->reactivation_timer[p] = -1;
498
  }
499
 
500
  /* Finally, we post the zombie event. when the end period is reached,
501
     the task descriptor and banwidth are freed */
502
  proc_table[p].status = CBS_ZOMBIE;
503
  lev->reactivation_timer[p] = kern_event_post(&lev->cbs_dline[p],
504
                                               CBS_timer_zombie,
505
                                               (void *)p);
506
}
507
 
508
/* Registration functions */
509
 
510
/*+ Registration function:
511
    int flags                 the init flags ... see CBS.h +*/
38 pj 512
LEVEL CBS_register_level(int flags, LEVEL master)
2 pj 513
{
514
  LEVEL l;            /* the level that we register */
515
  CBS_level_des *lev;  /* for readableness only */
516
  PID i;              /* a counter */
517
 
518
  printk("CBS_register_level\n");
519
 
520
  /* request an entry in the level_table */
38 pj 521
  l = level_alloc_descriptor(sizeof(CBS_level_des));
2 pj 522
 
38 pj 523
  lev = (CBS_level_des *)level_table[l];
2 pj 524
 
525
  printk("    lev=%d\n",(int)lev);
526
 
527
  /* fill the standard descriptor */
528
  if (flags & CBS_ENABLE_GUARANTEE)
38 pj 529
    lev->l.public_guarantee = CBS_public_guarantee;
2 pj 530
  else
38 pj 531
    lev->l.public_guarantee = NULL;
532
  lev->l.public_create    = CBS_public_create;
533
  lev->l.public_detach    = CBS_public_detach;
534
  lev->l.public_end       = CBS_public_end;
535
  lev->l.public_eligible  = CBS_public_eligible;
536
  lev->l.public_dispatch  = CBS_public_dispatch;
537
  lev->l.public_epilogue  = CBS_public_epilogue;
538
  lev->l.public_activate  = CBS_public_activate;
539
  lev->l.public_unblock   = CBS_public_unblock;
540
  lev->l.public_block     = CBS_public_block;
541
  lev->l.public_message   = CBS_public_message;
2 pj 542
 
543
  /* fill the CBS descriptor part */
544
  for (i=0; i<MAX_PROC; i++) {
545
     NULL_TIMESPEC(&lev->cbs_dline[i]);
546
     lev->period[i] = 0;
547
     NULL_TIMESPEC(&lev->reactivation_time[i]);
548
     lev->reactivation_timer[i] = -1;
549
     lev->nact[i] = 0;
550
     lev->flag[i] = 0;
551
  }
552
 
553
 
554
  lev->U = 0;
555
 
556
  lev->scheduling_level = master;
557
 
159 pj 558
  lev->flags = flags;
38 pj 559
 
560
  return l;
2 pj 561
}
562
 
563
bandwidth_t CBS_usedbandwidth(LEVEL l)
564
{
565
  CBS_level_des *lev = (CBS_level_des *)(level_table[l]);
38 pj 566
 
567
  return lev->U;
2 pj 568
}
569
 
570
int CBS_get_nact(LEVEL l, PID p)
571
{
572
  CBS_level_des *lev = (CBS_level_des *)(level_table[l]);
573
 
574
  return lev->nact[p];
575
}
576