Subversion Repositories shark

Rev

Rev 211 | Details | Compare with Previous | Last modification | View Log | RSS feed

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