Subversion Repositories shark

Rev

Rev 211 | Go to most recent revision | Details | 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>
12
 *   Giacomo Guidi       <giacomo@gandalf.sssup.it>
13
 *     [Hard Reservation]
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,
92
                           PID p,
93
                           struct timespec *acttime)
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) ) {
115
 
116
    /* we modify the deadline ... */
117
    TIMESPEC_ASSIGN(&lev->cbs_dline[p], acttime);
118
    ADDUSEC2TIMESPEC(lev->period[p], &lev->cbs_dline[p]);
119
 
120
    /* and the capacity */
121
    proc_table[p].avail_time = proc_table[p].wcet;
122
 
123
  }
124
 
125
  /* and, finally, we reinsert the task in the master level */
126
  job_task_default_model(job, lev->cbs_dline[p]);
127
  job_task_def_noexc(job);
128
  level_table[ lev->scheduling_level ]->
129
    private_insert(lev->scheduling_level, p, (TASK_MODEL *)&job);
130
 
131
}
132
 
133
static void HCBS_avail_time_check(HCBS_level_des *lev, PID p)
134
{
135
 
136
  if (proc_table[p].avail_time < 0) {
137
    ADDUSEC2TIMESPEC(lev->period[p], &lev->cbs_dline[p]);
138
    proc_table[p].avail_time += proc_table[p].wcet;
139
  }
140
 
141
}
142
 
143
 
144
/* this is the periodic reactivation of the task... it is posted only
145
   if the task is a periodic task */
146
static void HCBS_timer_reactivate(void *par)
147
{
148
  PID p = (PID) par;
149
  HCBS_level_des *lev;
150
 
151
  lev = (HCBS_level_des *)level_table[proc_table[p].task_level];
152
 
153
  if (lev->flag[p] & HCBS_SLEEP && proc_table[p].status == HCBS_IDLE) {
154
    proc_table[p].status = SLEEP;
155
    return;
156
  }
157
 
158
  if (proc_table[p].status == HCBS_IDLE) {
159
    /* the task has finished the current activation and must be
160
       reactivated */
161
    HCBS_activation(lev,p,&lev->reactivation_time[p]);
162
 
163
    event_need_reschedule();
164
 
165
  }
166
  else if (lev->flag[p] & HCBS_SAVE_ARRIVALS)
167
    /* the task has not completed the current activation, so we save
168
       the activation incrementing nact... */
169
    lev->nact[p]++;
170
 
171
  /* repost the event at the next period end...
172
     For bandwidth hard reservation, an aperiodic
173
     task is forced to generate a reactivate event */
174
  if (!(lev->flag[p] & HCBS_APERIODIC)) {
175
    ADDUSEC2TIMESPEC(lev->period[p], &lev->reactivation_time[p]);
176
    lev->reactivation_timer[p] = kern_event_post(&lev->reactivation_time[p],
177
                                               HCBS_timer_reactivate,
178
                                               (void *)p);
179
  }
180
 
181
  /* tracer stuff */
182
  trc_logevent(TRC_INTACTIVATION,&p);
183
 
184
}
185
 
186
/*+ this function is called when a killed or ended task reach the
187
    period end +*/
188
static void HCBS_timer_zombie(void *par)
189
{
190
  PID p = (PID) par;
191
 
192
  /* we finally put the task in the free queue */
193
  proc_table[p].status = FREE;
194
  iq_insertfirst(p,&freedesc);
195
 
196
}
197
 
198
/* The on-line guarantee is enabled only if the appropriate flag is set... */
199
static int HCBS_public_guarantee(LEVEL l, bandwidth_t *freebandwidth)
200
{
201
  HCBS_level_des *lev = (HCBS_level_des *)(level_table[l]);
202
 
203
  if (*freebandwidth >= lev->U) {
204
    *freebandwidth -= lev->U;
205
    return 1;
206
  }
207
  else
208
    return 0;
209
}
210
 
211
static int HCBS_public_create(LEVEL l, PID p, TASK_MODEL *m)
212
{
213
  HCBS_level_des *lev = (HCBS_level_des *)(level_table[l]);
214
  SOFT_TASK_MODEL *soft;
215
 
216
  if (m->pclass != SOFT_PCLASS) return -1;
217
  if (m->level != 0 && m->level != l) return -1;
218
  soft = (SOFT_TASK_MODEL *)m;
219
  if (!(soft->met && soft->period)) return -1;
220
 
221
  soft = (SOFT_TASK_MODEL *)m;
222
 
223
  if (lev->flags & HCBS_ENABLE_GUARANTEE) {
224
    bandwidth_t b;
225
    b = (MAX_BANDWIDTH / soft->period) * soft->met;
226
 
227
    /* really update lev->U, checking an overflow... */
228
    if (MAX_BANDWIDTH - lev->U > b)
229
      lev->U += b;
230
    else
231
      return -1;
232
  }
233
 
234
  /* Enable wcet check */
235
  proc_table[p].avail_time = soft->met;
236
  proc_table[p].wcet       = soft->met;
237
  proc_table[p].control   |= CONTROL_CAP;
238
 
239
  lev->nact[p] = 0;
240
  lev->period[p] = soft->period;
241
  NULL_TIMESPEC(&lev->cbs_dline[p]);
242
 
243
  if (soft->periodicity == APERIODIC)
244
    lev->flag[p] = HCBS_APERIODIC;
245
  else
246
    lev->flag[p] = 0;
247
 
248
  if (soft->arrivals == SAVE_ARRIVALS)
249
    lev->flag[p] |= HCBS_SAVE_ARRIVALS;
250
 
251
  return 0; /* OK, also if the task cannot be guaranteed... */
252
}
253
 
254
static void HCBS_public_detach(LEVEL l, PID p)
255
{
256
  /* the CBS level doesn't introduce any dinamic allocated new field.
257
     we have only to decrement the allocated bandwidth */
258
 
259
  HCBS_level_des *lev = (HCBS_level_des *)(level_table[l]);
260
 
261
  if (lev->flags & HCBS_ENABLE_GUARANTEE) {
262
    lev->U -= (MAX_BANDWIDTH / lev->period[p]) * proc_table[p].wcet;
263
  }
264
}
265
 
266
static int HCBS_public_eligible(LEVEL l, PID p)
267
{
268
  HCBS_level_des *lev = (HCBS_level_des *)(level_table[l]);
269
  JOB_TASK_MODEL job;
270
 
271
  /* we have to check if the deadline and the wcet are correct...
272
     if the CBS level schedules in background with respect to others
273
     levels, there can be the case in witch a task is scheduled by
274
     schedule_time > CBS_deadline; in this case (not covered in the
275
     article because if there is only the standard scheduling policy
276
     this never apply) we reassign the deadline */
277
 
278
  if ( TIMESPEC_A_LT_B(&lev->cbs_dline[p], &schedule_time) ) {
279
    /* we kill the current activation */
280
    level_table[ lev->scheduling_level ]->
281
      private_extract(lev->scheduling_level, p);
282
 
283
    /* we modify the deadline ... */
284
    TIMESPEC_ASSIGN(&lev->cbs_dline[p], &schedule_time);
285
    ADDUSEC2TIMESPEC(lev->period[p], &lev->cbs_dline[p]);
286
 
287
    /* and the capacity */
288
    proc_table[p].avail_time = proc_table[p].wcet;
289
 
290
    /* and, finally, we reinsert the task in the master level */
291
    job_task_default_model(job, lev->cbs_dline[p]);
292
    job_task_def_noexc(job);
293
    level_table[ lev->scheduling_level ]->
294
      private_insert(lev->scheduling_level, p, (TASK_MODEL *)&job);
295
 
296
    return -1;
297
  }
298
 
299
  return 0;
300
}
301
 
302
static void HCBS_public_dispatch(LEVEL l, PID p, int nostop)
303
{
304
  HCBS_level_des *lev = (HCBS_level_des *)(level_table[l]);
305
  level_table[ lev->scheduling_level ]->
306
    private_dispatch(lev->scheduling_level,p,nostop);
307
}
308
 
309
static void HCBS_public_epilogue(LEVEL l, PID p)
310
{
311
  HCBS_level_des *lev = (HCBS_level_des *)(level_table[l]);
312
 
313
  /* check if the wcet is finished... */
314
  if ( proc_table[p].avail_time <= 0) {
315
 
316
    lev->flag[p] |= HCBS_OVERLOAD;
317
 
318
    /* we kill the current activation */
319
    level_table[ lev->scheduling_level ]->
320
      private_extract(lev->scheduling_level, p);
321
 
322
    /* Hard Reservation: The avail_time will be reloaded in the
323
       next reactivation event. The task is suspended */
324
    proc_table[p].status = HCBS_IDLE;
325
    if (lev->flag[p] & HCBS_APERIODIC) {
326
 
327
      ADDUSEC2TIMESPEC(lev->period[p], &lev->reactivation_time[p]);
328
      lev->reactivation_timer[p] = kern_event_post(&lev->reactivation_time[p],
329
                                                 HCBS_timer_reactivate,
330
                                                 (void *)p);
331
    }
332
 
333
  }
334
  else
335
    /* the task has been preempted. it returns into the ready queue by
336
       calling the guest_epilogue... */
337
    level_table[ lev->scheduling_level ]->
338
      private_epilogue(lev->scheduling_level,p);
339
}
340
 
341
static void HCBS_public_activate(LEVEL l, PID p)
342
{
343
  HCBS_level_des *lev = (HCBS_level_des *)(level_table[l]);
344
  struct timespec t;
345
 
346
  if (lev->flag[p] & HCBS_SLEEP) {
347
    /* disable HCBS_SLEEP flag */
348
    lev->flag[p] &= ~HCBS_SLEEP;
349
    if (proc_table[p].status != SLEEP) return;
350
  }
351
 
352
  /* save activation (only if needed... */
353
  if (proc_table[p].status != SLEEP) {
354
    if (lev->flag[p] & HCBS_SAVE_ARRIVALS)
355
      lev->nact[p]++;
356
    return;
357
  }
358
 
359
  kern_gettime(&t);
360
 
361
  HCBS_activation(lev, p, &t);
362
 
363
  /* Set the reactivation timer */
364
  if (!(lev->flag[p] & HCBS_APERIODIC))
365
  {
366
    /* we cannot use the deadline computed by CBS_activation because
367
       the deadline may be != from actual_time + period
368
       (if we call the task_activate after a task_sleep, and the
369
       deadline was postponed a lot...) */
370
    TIMESPEC_ASSIGN(&lev->reactivation_time[p], &t);
371
    ADDUSEC2TIMESPEC(lev->period[p], &lev->reactivation_time[p]);
372
//    TIMESPEC_ASSIGN(&lev->reactivation_time[p], &lev->cbs_dline[p]);
373
    lev->reactivation_timer[p] = kern_event_post(&lev->reactivation_time[p],
374
                                                 HCBS_timer_reactivate,
375
                                                 (void *)p);
376
  }
377
}
378
 
379
static void HCBS_public_unblock(LEVEL l, PID p)
380
{
381
  HCBS_level_des *lev = (HCBS_level_des *)(level_table[l]);
382
  struct timespec acttime;
383
 
384
  kern_gettime(&acttime);
385
 
386
  HCBS_activation(lev,p,&acttime);
387
}
388
 
389
static void HCBS_public_block(LEVEL l, PID p)
390
{
391
  HCBS_level_des *lev = (HCBS_level_des *)(level_table[l]);
392
 
393
  /* check if the wcet is finished... */
394
  HCBS_avail_time_check(lev, p);
395
 
396
  level_table[ lev->scheduling_level ]->
397
    private_extract(lev->scheduling_level,p);
398
}
399
 
400
static int HCBS_public_message(LEVEL l, PID p, void *m)
401
{
402
 
403
  HCBS_command_message *msg;
404
  HCBS_level_des *lev = (HCBS_level_des *)(level_table[l]);
405
 
406
  switch((long)(m)) {
407
 
408
    /* task_endcycle */
409
    case (long)(NULL):
410
 
411
      if  (!(lev->flag[p] & HCBS_APERIODIC) && lev->flag[p] & HCBS_OVERLOAD) {
412
        lev->flag[p] &= ~HCBS_OVERLOAD;
413
        lev->nact[p]++;
414
      }
415
 
416
      if (lev->nact[p]) {
417
        /* continue!!!! */
418
        lev->nact[p]--;
419
        level_table[ lev->scheduling_level ]->
420
          private_epilogue(lev->scheduling_level,p);
421
      } else {
422
        level_table[ lev->scheduling_level ]->
423
          private_extract(lev->scheduling_level,p);
424
 
425
        if (lev->flag[p] & HCBS_APERIODIC)
426
          proc_table[p].status = SLEEP;
427
        else  /* the task is soft_periodic */
428
          proc_table[p].status = HCBS_IDLE;
429
      }
430
 
431
      jet_update_endcycle(); /* Update the Jet data... */
432
      trc_logevent(TRC_ENDCYCLE,&exec_shadow); /* tracer stuff */
433
 
434
      break;
435
 
436
    /* task_disable */
437
    case (1):
438
 
439
      lev->flag[p] |= HCBS_SLEEP;
440
 
441
      break;
442
 
443
    /* Set/Get Met/Period */
444
    default:
445
 
446
      msg = (HCBS_command_message *)(m);
447
 
448
      switch (msg->command) {
449
        case HCBS_SET_PERIOD:
450
          lev->U -= (bandwidth_t)(MAX_BANDWIDTH / lev->period[p]
451
                * proc_table[p].wcet);
452
          lev->period[p] = msg->param;
453
          lev->U += (bandwidth_t)(MAX_BANDWIDTH / lev->period[p]
454
                * proc_table[p].wcet);
455
          break;
456
        case HCBS_GET_PERIOD:
457
          msg->param = lev->period[p];
458
          break;
459
        case HCBS_SET_MET:
460
          lev->U -= (bandwidth_t)(MAX_BANDWIDTH / lev->period[p]
461
                * proc_table[p].wcet);
462
          proc_table[p].wcet = msg->param;
463
          lev->U += (bandwidth_t)(MAX_BANDWIDTH / lev->period[p]
464
                * proc_table[p].wcet);
465
          break;
466
        case HCBS_GET_MET:
467
          msg->param = proc_table[p].wcet;
468
          break;
469
      }
470
 
471
      break;
472
 
473
  }
474
 
475
  return 0;
476
 
477
}
478
 
479
static void HCBS_public_end(LEVEL l, PID p)
480
{
481
  HCBS_level_des *lev = (HCBS_level_des *)(level_table[l]);
482
 
483
  /* check if the wcet is finished... */
484
  HCBS_avail_time_check(lev, p);
485
 
486
  level_table[ lev->scheduling_level ]->
487
    private_extract(lev->scheduling_level,p);
488
 
489
  /* free the allocated bandwidth */
490
  lev->U -= (MAX_BANDWIDTH/lev->period[p]) * proc_table[p].wcet;
491
 
492
  /* we delete the reactivation timer */
493
  if (!(lev->flag[p] & HCBS_APERIODIC)) {
494
    kern_event_delete(lev->reactivation_timer[p]);
495
    lev->reactivation_timer[p] = -1;
496
  }
497
 
498
  /* Finally, we post the zombie event. when the end period is reached,
499
     the task descriptor and banwidth are freed */
500
  proc_table[p].status = HCBS_ZOMBIE;
501
  lev->reactivation_timer[p] = kern_event_post(&lev->cbs_dline[p],
502
                                               HCBS_timer_zombie,
503
                                               (void *)p);
504
}
505
 
506
/* Registration functions */
507
 
508
/*+ Registration function:
509
    int flags                 the init flags ... see CBS.h +*/
510
LEVEL HCBS_register_level(int flags, LEVEL master)
511
{
512
  LEVEL l;            /* the level that we register */
513
  HCBS_level_des *lev;  /* for readableness only */
514
  PID i;              /* a counter */
515
 
516
  printk("HCBS_register_level\n");
517
 
518
  /* request an entry in the level_table */
519
  l = level_alloc_descriptor(sizeof(HCBS_level_des));
520
 
521
  lev = (HCBS_level_des *)level_table[l];
522
 
523
  printk("    lev=%d\n",(int)lev);
524
 
525
  /* fill the standard descriptor */
526
  if (flags & HCBS_ENABLE_GUARANTEE)
527
    lev->l.public_guarantee = HCBS_public_guarantee;
528
  else
529
    lev->l.public_guarantee = NULL;
530
  lev->l.public_create    = HCBS_public_create;
531
  lev->l.public_detach    = HCBS_public_detach;
532
  lev->l.public_end       = HCBS_public_end;
533
  lev->l.public_eligible  = HCBS_public_eligible;
534
  lev->l.public_dispatch  = HCBS_public_dispatch;
535
  lev->l.public_epilogue  = HCBS_public_epilogue;
536
  lev->l.public_activate  = HCBS_public_activate;
537
  lev->l.public_unblock   = HCBS_public_unblock;
538
  lev->l.public_block     = HCBS_public_block;
539
  lev->l.public_message   = HCBS_public_message;
540
 
541
  /* fill the CBS descriptor part */
542
  for (i=0; i<MAX_PROC; i++) {
543
     NULL_TIMESPEC(&lev->cbs_dline[i]);
544
     lev->period[i] = 0;
545
     NULL_TIMESPEC(&lev->reactivation_time[i]);
546
     lev->reactivation_timer[i] = -1;
547
     lev->nact[i] = 0;
548
     lev->flag[i] = 0;
549
  }
550
 
551
 
552
  lev->U = 0;
553
 
554
  lev->scheduling_level = master;
555
 
556
  lev->flags = flags;
557
 
558
  return l;
559
}
560
 
561
bandwidth_t HCBS_usedbandwidth(LEVEL l)
562
{
563
  HCBS_level_des *lev = (HCBS_level_des *)(level_table[l]);
564
 
565
  return lev->U;
566
}
567
 
568
int HCBS_get_nact(LEVEL l, PID p)
569
{
570
  HCBS_level_des *lev = (HCBS_level_des *)(level_table[l]);
571
 
572
  return lev->nact[p];
573
}
574