Subversion Repositories shark

Rev

Rev 1100 | Rev 1123 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1085 pj 1
/*
2
 * Project: S.Ha.R.K.
3
 *
4
 * Coordinators: Giorgio Buttazzo <giorgio@sssup.it>
5
 *               Paolo Gai <pj@hartik.sssup.it>
6
 *
7
 * Authors     : Marco Caccamo and Paolo Gai
8
 *
9
 * ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
10
 *
11
 * http://www.sssup.it
12
 * http://retis.sssup.it
13
 * http://shark.sssup.it
14
 */
15
 
16
/**
17
 ------------
1115 pj 18
 CVS :        $Id: cbs_ft.c,v 1.3 2002-11-11 08:14:22 pj Exp $
1085 pj 19
 
20
 File:        $File$
1115 pj 21
 Revision:    $Revision: 1.3 $
22
 Last update: $Date: 2002-11-11 08:14:22 $
1085 pj 23
 ------------
24
 
25
 This file contains the server CBS_FT
26
 
27
 Read CBS_FT.h for further details.
28
 
29
**/
30
 
31
/*
32
 * Copyright (C) 2000 Marco Caccamo and Paolo Gai
33
 *
34
 * This program is free software; you can redistribute it and/or modify
35
 * it under the terms of the GNU General Public License as published by
36
 * the Free Software Foundation; either version 2 of the License, or
37
 * (at your option) any later version.
38
 *
39
 * This program is distributed in the hope that it will be useful,
40
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
41
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
42
 * GNU General Public License for more details.
43
 *
44
 * You should have received a copy of the GNU General Public License
45
 * along with this program; if not, write to the Free Software
46
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
47
 *
48
 */
49
 
50
 
51
#include "cbs_ft.h"
52
 
53
/*+ 4 debug purposes +*/
54
#undef CBS_FT_TEST
55
 
56
#ifdef TESTG
57
#include "drivers/glib.h"
58
TIME x,oldx;
59
extern TIME starttime;
60
#endif
61
 
62
 
63
 
64
 
65
/*+ Status used in the level +*/
66
#define CBS_FT_IDLE          APER_STATUS_BASE   /*+ waiting the activation +*/
67
#define CBS_FT_ZOMBIE        APER_STATUS_BASE+1 /*+ waiting the period end +*/
68
 
69
/* structure of an element of the capacity queue */  
70
struct cap_queue {
71
  int              cap;
72
  struct timespec  dead;
73
  struct cap_queue *next;
74
};  
75
 
76
/*+ the level redefinition for the CBS_FT level +*/
77
typedef struct {
78
  level_des l;     /*+ the standard level descriptor          +*/
79
 
80
  /* The wcet are stored in the task descriptor, but we need
81
     an array for the deadlines. We can't use the timespec_priority
82
     field because it is used by the master level!!!...
83
     Notice that however the use of the timespec_priority field
84
     does not cause any problem...                     */
85
 
86
  struct timespec cbs_ft_dline[MAX_PROC]; /*+ CBS_FT deadlines      +*/
87
 
88
 
89
  TIME period[MAX_PROC]; /*+ CBS_FT activation period            +*/
90
 
91
 
92
  int maxcap[MAX_PROC]; /* amount of capacity reserved to a primary+backup
93
                        couple */
94
 
95
  PID backup[MAX_PROC];  /* Backup task pointers, defined for primary tasks  */
96
 
97
  char CP[MAX_PROC];      /* checkpoint flag */
98
 
99
  char P_or_B[MAX_PROC];  /*  Type of task: PRIMARY or BACKUP */
100
 
101
 
102
  struct timespec reactivation_time[MAX_PROC];
103
        /*+ the time at witch  the reactivation timer is post +*/
104
 
105
  int reactivation_timer[MAX_PROC];  /*+ the recativation timer +*/
106
 
107
  struct cap_queue *queue;         /* pointer to the spare capacity queue */
108
 
109
  int flags;       /*+ the init flags...                      +*/
110
 
111
  bandwidth_t U;   /*+ the used bandwidth by the server       +*/
112
 
113
  int idle;         /* the idle flag...  */
114
 
115
  struct timespec start_idle; /*gives the start time of the last idle period */
116
 
117
  LEVEL scheduling_level;
118
 
119
} CBS_FT_level_des;
120
 
121
 
122
 
123
/* insert a capacity in the queue capacity ordering by deadline */
124
 
125
static int c_insert(struct timespec dead, int cap, struct cap_queue **que,
126
                     PID p)
127
{
128
  struct cap_queue *prev, *n, *new;
129
 
130
    prev = NULL;
131
    n = *que;
132
 
133
    while ((n != NULL) &&
134
           !TIMESPEC_A_LT_B(&dead, &n->dead)) {
135
        prev = n;
136
        n = n->next;
137
    }
138
 
139
 
140
    new = (struct cap_queue *)kern_alloc(sizeof(struct cap_queue));
141
    if (new == NULL) {
142
      kern_printf("\nNew cash_queue element failed\n");
1100 pj 143
      kern_raise(XINVALID_TASK, p);
1085 pj 144
      return -1;
145
    }
146
    new->next = NULL;
147
    new->cap = cap;
148
    new->dead = dead;
149
 
150
    if (prev != NULL)
151
      prev->next = new;
152
    else
153
      *que = new;
154
 
155
    if (n != NULL)
156
      new->next = n;
157
    return 0;
158
 
159
}
160
 
161
/* extract the first element from the capacity queue */
162
 
163
int c_extractfirst(struct cap_queue **que)
164
{
165
    struct cap_queue *p = *que;
166
 
167
 
168
    if (*que == NULL) return(-1);
169
 
170
    *que = (*que)->next;
171
 
172
    kern_free(p, sizeof(struct cap_queue));
173
    return(1);
174
}
175
 
176
/* read data of the first element from the capacity queue */
177
 
178
static void c_readfirst(struct timespec *d, int *c, struct cap_queue *que)
179
{
180
    *d = que->dead;
181
    *c = que->cap;
182
}
183
 
184
/* write data of the first element from the capacity queue */
185
 
186
static void c_writefirst(struct timespec dead, int cap, struct cap_queue *que)
187
{
188
    que->dead = dead;
189
    que->cap = cap;
190
}
191
 
192
 
193
static void CBS_FT_activation(CBS_FT_level_des *lev,
194
                             PID p,
195
                             struct timespec *acttime)
196
{
197
  JOB_TASK_MODEL job;
198
  int capacity;  
199
 
200
  /* This rule is used when we recharge the budget at initial task activation
201
     and each time a new task instance must be activated  */
202
 
203
  if (TIMESPEC_A_GT_B(acttime, &lev->cbs_ft_dline[p])) {
204
    /* we modify the deadline ... */
205
    TIMESPEC_ASSIGN(&lev->cbs_ft_dline[p], acttime);
206
  }
207
 
208
 
209
  if (proc_table[p].avail_time > 0)
210
    proc_table[p].avail_time = 0;
211
 
212
 
213
 
214
  /* A spare capacity is inserted in the capacity queue!! */
215
  ADDUSEC2TIMESPEC(lev->period[p], &lev->cbs_ft_dline[p]);
216
  capacity = lev->maxcap[p] - proc_table[ lev->backup[p] ].wcet;
217
  c_insert(lev->cbs_ft_dline[p], capacity, &lev->queue, p);
218
 
219
 
220
  /* it exploits available capacities from the capacity queue */
221
  while (proc_table[p].avail_time < proc_table[p].wcet &&
222
         lev->queue != NULL) {
223
    struct timespec dead;
224
    int             cap, delta;
225
    delta = proc_table[p].wcet - proc_table[p].avail_time;
226
    c_readfirst(&dead, &cap, lev->queue);
227
    if (!TIMESPEC_A_GT_B(&dead, &lev->cbs_ft_dline[p])) {
228
      if (cap > delta) {
229
        proc_table[p].avail_time += delta;
230
        c_writefirst(dead, cap - delta, lev->queue);
231
      }
232
      else {
233
        proc_table[p].avail_time += cap;
234
        c_extractfirst(&lev->queue);
235
      }
236
    }
237
    else
238
      break;
239
  }
240
 
241
  /* If the budget is still less than 0, an exception is raised */
242
  if (proc_table[p].avail_time <= 0) {
243
    kern_printf("\nnegative value for the budget!\n");
1100 pj 244
    kern_raise(XINVALID_TASK, p);
1085 pj 245
    return;
246
  }
247
 
248
 
249
 
250
  /*if (p==6)
251
    kern_printf("(act_time:%d  dead:%d av_time:%d)\n",
252
                acttime->tv_sec*1000000+
253
                acttime->tv_nsec/1000,
254
                lev->cbs_ft_dline[p].tv_sec*1000000+
255
                lev->cbs_ft_dline[p].tv_nsec/1000,
256
                proc_table[p].avail_time);  */
257
 
258
 
259
 
260
 
261
 
262
 
263
#ifdef TESTG
264
  if (starttime && p == 3) {
265
    oldx = x;
266
    x = ((lev->cbs_ft_dline[p].tv_sec*1000000+lev->cbs_ft_dline[p].tv_nsec/1000)/5000 - starttime) + 20;
267
    //      kern_printf("(a%d)",lev->cbs_ft_dline[p].tv_sec*1000000+lev->cbs_ft_dline[p].tv_nsec/1000);
268
    if (oldx > x) sys_end();
269
    if (x<640)
270
      grx_plot(x, 15, 8);
271
  }
272
#endif
273
 
274
  /* and, finally, we reinsert the task in the master level */
275
  job_task_default_model(job, lev->cbs_ft_dline[p]);
276
  job_task_def_yesexc(job);
277
  level_table[ lev->scheduling_level ]->
278
    guest_create(lev->scheduling_level, p, (TASK_MODEL *)&job);
279
  level_table[ lev->scheduling_level ]->
280
    guest_activate(lev->scheduling_level, p);
281
}
282
 
283
 
284
static char *CBS_FT_status_to_a(WORD status)
285
{
286
  if (status < MODULE_STATUS_BASE)
287
    return status_to_a(status);
288
 
289
  switch (status) {
290
    case CBS_FT_IDLE   : return "CBS_FT_Idle";
291
    case CBS_FT_ZOMBIE : return "CBS_FT_Zombie";
292
    default         : return "CBS_FT_Unknown";
293
  }
294
}
295
 
296
 
297
 
298
 
299
/* this is the periodic reactivation of the task... */
300
static void CBS_FT_timer_reactivate(void *par)
301
{
302
  PID p = (PID) par;
303
  CBS_FT_level_des *lev;
304
 
305
  lev = (CBS_FT_level_des *)level_table[proc_table[p].task_level];
306
 
307
  if (proc_table[p].status == CBS_FT_IDLE) {
308
    /* the task has finished the current activation and must be
309
       reactivated */
310
 
311
    /* request_time represents the time of the last instance release!! */
312
    TIMESPEC_ASSIGN(&proc_table[p].request_time, &lev->reactivation_time[p]);
313
 
314
    /* If idle=1, then we have to discharge the capacities stored in
315
       the capacity queue up to the length of the idle interval */
316
    if (lev->idle == 1) {
317
      TIME interval;
318
      struct timespec delta;
319
      lev->idle = 0;
320
      SUBTIMESPEC(&proc_table[p].request_time, &lev->start_idle, &delta);
321
      /* length of the idle interval expressed in usec! */
322
      interval = TIMESPEC2NANOSEC(&delta) / 1000;
323
 
324
      /* it discharges the available capacities from the capacity queue */
325
      while (interval > 0 && lev->queue != NULL) {
326
        struct timespec dead;
327
        int             cap;
328
        c_readfirst(&dead, &cap, lev->queue);
329
        if (cap > interval) {
330
          c_writefirst(dead, cap - interval, lev->queue);
331
          interval = 0;
332
        }
333
        else {
334
          interval -= cap;
335
          c_extractfirst(&lev->queue);
336
        }      
337
      }
338
    }
339
 
340
    CBS_FT_activation(lev,p,&lev->reactivation_time[p]);
341
 
342
 
343
    /* Set the reactivation timer */
344
    TIMESPEC_ASSIGN(&lev->reactivation_time[p], &lev->cbs_ft_dline[p]);
345
    lev->reactivation_timer[p] = kern_event_post(&lev->reactivation_time[p],
346
                                                 CBS_FT_timer_reactivate,
347
                                                 (void *)p);
348
    event_need_reschedule();
349
  }
350
  else {
351
    /* this situation cannot occur */
352
    kern_printf("\nTrying to reactivate a primary task which is not IDLE!\n");
1100 pj 353
    kern_raise(XINVALID_TASK,p);
1085 pj 354
  }
355
}
356
 
357
 
358
 
359
static void CBS_FT_avail_time_check(CBS_FT_level_des *lev, PID p)
360
{
361
 
362
  /*+ if the capacity became negative the remaining computation time
363
    is diminuished.... +*/
364
  /* if (p==4)
365
    kern_printf("(old dead:%d av_time:%d)\n",
366
                lev->cbs_ft_dline[p].tv_sec*1000000+
367
                lev->cbs_ft_dline[p].tv_nsec/1000,
368
                proc_table[p].avail_time);  */
369
 
370
 
371
  int newcap = proc_table[p].wcet / 100 * 30;
372
  if (newcap <= 0)
373
    newcap = proc_table[p].wcet;
374
  /* it exploits available capacities from the capacity queue */
375
  while (proc_table[p].avail_time < newcap
376
         && lev->queue != NULL) {
377
    struct timespec dead;
378
    int             cap, delta;
379
    delta = newcap - proc_table[p].avail_time;
380
    c_readfirst(&dead, &cap, lev->queue);
381
    if (!TIMESPEC_A_GT_B(&dead, &lev->cbs_ft_dline[p])) {
382
      if (cap > delta) {
383
        proc_table[p].avail_time += delta;
384
        c_writefirst(dead, cap - delta, lev->queue);
385
      }
386
      else {
387
        proc_table[p].avail_time += cap;
388
        c_extractfirst(&lev->queue);
389
      }
390
    }
391
    else
392
      break;
393
  }
394
 
395
 
396
 
397
 /*if (p==6)
398
    kern_printf("(ATC dead:%d av_time:%d)\n",
399
                lev->cbs_ft_dline[p].tv_sec*1000000+
400
                lev->cbs_ft_dline[p].tv_nsec/1000,
401
                proc_table[p].avail_time);  */
402
 
403
 
404
 
405
  /* if the budget is still empty, the backup task must be woken up.
406
     Remind that a short chunk of primary will go ahead executing
407
     before the task switch occurs                                */
408
  if (proc_table[p].avail_time <= 0) {
409
    lev->CP[p] = 1;
410
    proc_table[p].avail_time += proc_table[ lev->backup[p] ].wcet;
411
  }
412
 
413
 
414
 /*if (p==6)
415
    kern_printf("(ATC1 dead:%d av_time:%d)\n",
416
                lev->cbs_ft_dline[p].tv_sec*1000000+
417
                lev->cbs_ft_dline[p].tv_nsec/1000,
418
                proc_table[p].avail_time);  */
419
 
420
 
421
 
422
}
423
 
424
 
425
/*+ this function is called when a killed or ended task reach the
426
  period end +*/
427
static void CBS_FT_timer_zombie(void *par)
428
{
429
  PID p = (PID) par;
430
  CBS_FT_level_des *lev;
431
 
432
  lev = (CBS_FT_level_des *)level_table[proc_table[p].task_level];
433
 
434
  /* we finally put the task in the FREE status */
435
  proc_table[p].status = FREE;
1115 pj 436
  iq_insertfirst(p,&freedesc);
1085 pj 437
 
438
 
439
  /* and free the allocated bandwidth */
440
  lev->U -= (MAX_BANDWIDTH / lev->period[p]) * (TIME)lev->maxcap[p];
441
}
442
 
443
 
444
static int CBS_FT_level_accept_task_model(LEVEL l, TASK_MODEL *m)
445
{
446
 
447
  if (m->pclass == FT_PCLASS || m->pclass ==
448
      (FT_PCLASS | l)) {
449
    FT_TASK_MODEL *f = (FT_TASK_MODEL *) m;
450
 
451
    //kern_printf("accept :FAULT TOLERANT TASK found!!!!!!\n"); */
452
    if (f->type == PRIMARY && f->execP > 0 && f->budget < (int)f->period
453
        && f->backup != NIL) return 0;
454
    if (f->type == BACKUP && f->wcetB > 0)
455
      return 0;
456
  }
457
  return -1;
458
}
459
 
460
 
461
 
462
static int CBS_FT_level_accept_guest_model(LEVEL l, TASK_MODEL *m)
463
{
464
  return -1;
465
}
466
 
467
static char *onoff(int i)
468
{
469
  if (i)
470
    return "On ";
471
  else
472
    return "Off";
473
}
474
 
475
static void CBS_FT_level_status(LEVEL l)
476
{
477
  CBS_FT_level_des *lev = (CBS_FT_level_des *)(level_table[l]);
478
  PID p;
479
 
480
  kern_printf("On-line guarantee : %s\n",
481
              onoff(lev->flags & CBS_FT_ENABLE_GUARANTEE));
482
  kern_printf("Used Bandwidth    : %u/%u\n",
483
              lev->U, MAX_BANDWIDTH);
484
 
485
  for (p=0; p<MAX_PROC; p++)
486
    if (proc_table[p].task_level == l && proc_table[p].status != FREE )
487
      kern_printf("Pid: %2d Name: %10s Period: %9ld Dline: %9ld.%6ld Stat: %s\n",
488
                  p,
489
                  proc_table[p].name,
490
                  lev->period[p],
491
                  lev->cbs_ft_dline[p].tv_sec,
492
                  lev->cbs_ft_dline[p].tv_nsec/1000,
493
                  CBS_FT_status_to_a(proc_table[p].status));
494
}
495
 
496
static PID CBS_FT_level_scheduler(LEVEL l)
497
{
498
  CBS_FT_level_des *lev = (CBS_FT_level_des *)(level_table[l]);
499
 
500
  /* it stores the actual time and set the IDLE flag in order to handle
501
     the capacity queue discharging!!! */
502
  lev->idle = 1;
503
  ll_gettime(TIME_EXACT, &lev->start_idle);
504
 
505
 
506
  /* the CBS_FT don't schedule anything...
507
     it's an EDF level or similar that do it! */
508
  return NIL;
509
}
510
 
511
 
512
/* The on-line guarantee is enabled only if the appropriate flag is set... */
513
static int CBS_FT_level_guarantee(LEVEL l, bandwidth_t *freebandwidth)
514
{
515
  CBS_FT_level_des *lev = (CBS_FT_level_des *)(level_table[l]);
516
 
517
  if (lev->flags & CBS_FT_FAILED_GUARANTEE) {
518
    *freebandwidth = 0;
519
    kern_printf("guarantee :garanzia fallita!!!!!!\n");
520
    return 0;
521
  }
522
  else if (*freebandwidth >= lev->U) {
523
    *freebandwidth -= lev->U;
524
    return 1;
525
  }
526
  else {
527
    kern_printf("guarantee :garanzia fallita per mancanza di banda!!!!!!\n");
528
    kern_printf("freeband: %d request band: %d", *freebandwidth, lev->U);
529
    return 0;
530
  }
531
}
532
 
533
 
534
static int CBS_FT_task_create(LEVEL l, PID p, TASK_MODEL *m)
535
 
536
{
537
  CBS_FT_level_des *lev = (CBS_FT_level_des *)(level_table[l]);
538
 
539
  /* if the CBS_FT_task_create is called, then the pclass must be a
540
     valid pclass. */
541
  FT_TASK_MODEL *s = (FT_TASK_MODEL *)m;
542
 
543
 
544
 
545
  /* Enable budget check */
546
  proc_table[p].control |= CONTROL_CAP;  
547
 
548
  proc_table[p].avail_time = 0;
549
  NULL_TIMESPEC(&lev->cbs_ft_dline[p]);
550
 
551
 
552
  if (s->type == PRIMARY) {
553
    proc_table[p].wcet = (int)s->execP;
554
    lev->period[p] = s->period;
555
    lev->maxcap[p] = s->budget;
556
    lev->backup[p] = s->backup;
557
    lev->CP[p] = 0;
558
    lev->P_or_B[p] = PRIMARY;
559
 
560
    /* update the bandwidth... */
561
    if (lev->flags & CBS_FT_ENABLE_GUARANTEE) {
562
      bandwidth_t b;
563
      b = (MAX_BANDWIDTH / lev->period[p]) * (TIME)lev->maxcap[p];
564
 
565
      /* really update lev->U, checking an overflow... */
566
      if (MAX_BANDWIDTH - lev->U > b)
567
        lev->U += b;
568
      else
569
        /* The task can NOT be guaranteed (U>MAX_BANDWIDTH)...
570
           (see EDF.c) */
571
        lev->flags |= CBS_FT_FAILED_GUARANTEE;
572
    }
573
  }
574
  else {
575
    proc_table[p].wcet = (int)s->wcetB;
576
    lev->P_or_B[p] = BACKUP;
577
 
578
    /* Backup tasks are unkillable tasks! */
579
    proc_table[p].control |= NO_KILL;
580
  }
581
 
582
  return 0; /* OK, also if the task cannot be guaranteed... */
583
}
584
 
585
 
586
static void CBS_FT_task_detach(LEVEL l, PID p)
587
{
588
  /* the CBS_FT level doesn't introduce any dynamic allocated new field.
589
     we have only to reset the NO_GUARANTEE FIELD and decrement the allocated
590
     bandwidth */
591
 
592
  CBS_FT_level_des *lev = (CBS_FT_level_des *)(level_table[l]);
593
 
594
  if (lev->flags & CBS_FT_FAILED_GUARANTEE)
595
    lev->flags &= ~CBS_FT_FAILED_GUARANTEE;
596
  else
597
    lev->U -= (MAX_BANDWIDTH / lev->period[p]) * (TIME)lev->maxcap[p];
598
}
599
 
600
 
601
static int CBS_FT_task_eligible(LEVEL l, PID p)
602
{
603
  return 0; /* if the task p is chosen, it is always eligible */
604
}
605
 
606
static void CBS_FT_task_dispatch(LEVEL l, PID p, int nostop)
607
{
608
  CBS_FT_level_des *lev = (CBS_FT_level_des *)(level_table[l]);
609
  level_table[ lev->scheduling_level ]->
610
    guest_dispatch(lev->scheduling_level,p,nostop);
611
}
612
 
613
static void CBS_FT_task_epilogue(LEVEL l, PID p)
614
{
615
  CBS_FT_level_des *lev = (CBS_FT_level_des *)(level_table[l]);
616
 
617
  /* check if the budget is finished... */
618
  if (proc_table[p].avail_time <= 0) {
619
 
620
    /* A backup task cannot ever exhaust its budget! */
621
    if (lev->P_or_B[p] == BACKUP) {
622
      kern_printf("\nBACKUP wcet violation!\n");
623
      kern_raise(XWCET_VIOLATION,p);
624
      /* we kill the current activation */
625
      level_table[ lev->scheduling_level ]->
626
        guest_end(lev->scheduling_level, p);
627
      return;
628
    }
629
 
630
    /* we try to recharge the budget */
631
    CBS_FT_avail_time_check(lev, p);
632
 
633
    /* The budget must be greater than 0! */
634
    if (proc_table[p].avail_time <= 0) {
635
      kern_printf("\nBackup task starting with exhausted budget\n");
1100 pj 636
      kern_raise(XINVALID_TASK, p);
1085 pj 637
      lev->CP[p] = 0;
638
      /* we kill the current activation */
639
      level_table[ lev->scheduling_level ]->
640
        guest_end(lev->scheduling_level, p);
641
      return;
642
    }
643
  }
644
 
645
    /* the task returns into the ready queue by
646
       calling the guest_epilogue... */
647
    level_table[ lev->scheduling_level ]->
648
      guest_epilogue(lev->scheduling_level,p);
649
}
650
 
651
 
652
static void CBS_FT_task_activate(LEVEL l, PID p)
653
{
654
  CBS_FT_level_des *lev = (CBS_FT_level_des *)(level_table[l]);
655
 
656
  ll_gettime(TIME_EXACT, &proc_table[p].request_time);
657
 
658
 
659
 
660
  if (lev->P_or_B[p] == BACKUP) {
661
    kern_printf("\nTrying to activate a BACKUP task!\n");
1100 pj 662
    kern_raise(XINVALID_TASK, p);
1085 pj 663
  }
664
  else {
665
 
666
    /* If idle=1, then we have to discharge the capacities stored in
667
       the capacity queue up to the length of the idle interval */
668
    if (lev->idle == 1) {
669
      TIME interval;
670
      struct timespec delta;
671
      lev->idle = 0;
672
      SUBTIMESPEC(&proc_table[p].request_time, &lev->start_idle, &delta);
673
      /* length of the idle interval expressed in usec! */
674
      interval = TIMESPEC2NANOSEC(&delta) / 1000;
675
 
676
      /* it discharge the available capacities from the capacity queue */
677
      while (interval > 0 && lev->queue != NULL) {
678
        struct timespec dead;
679
        int             cap;
680
        c_readfirst(&dead, &cap, lev->queue);
681
        if (cap > interval) {
682
          c_writefirst(dead, cap - interval, lev->queue);
683
          interval = 0;
684
        }
685
        else {
686
          interval -= cap;
687
          c_extractfirst(&lev->queue);
688
        }      
689
      }
690
    }
691
 
692
    CBS_FT_activation(lev, p, &proc_table[p].request_time);
693
 
694
 
695
    /* Set the reactivation timer */
696
    TIMESPEC_ASSIGN(&lev->reactivation_time[p], &lev->cbs_ft_dline[p]);
697
    lev->reactivation_timer[p] = kern_event_post(&lev->reactivation_time[p],
698
                                                 CBS_FT_timer_reactivate,
699
                                                 (void *)p);
700
 
701
    //  kern_printf("act : %d %d |",lev->cbs_ft_dline[p].tv_nsec/1000,p);
702
  }
703
}
704
 
705
 
706
static void CBS_FT_task_insert(LEVEL l, PID p)
707
{
708
  printk("CBS_FT_task_insert\n");
1100 pj 709
  kern_raise(XINVALID_TASK,p);
1085 pj 710
}
711
 
712
 
713
static void CBS_FT_task_extract(LEVEL l, PID p)
714
{
715
  printk("CBS_FT_task_extract\n");
1100 pj 716
  kern_raise(XINVALID_TASK,p);
1085 pj 717
}
718
 
719
 
720
static void CBS_FT_task_endcycle(LEVEL l, PID p)
721
{
722
  CBS_FT_level_des *lev = (CBS_FT_level_des *)(level_table[l]);
723
 
724
 
725
  level_table[ lev->scheduling_level ]->
726
    guest_end(lev->scheduling_level,p);
727
 
728
 
729
  proc_table[p].status = CBS_FT_IDLE;
730
 
731
 
732
  if (lev->P_or_B[p] == PRIMARY) {
733
    if (lev->CP[p]) {
734
      JOB_TASK_MODEL job;
735
 
736
      /* We have to start the backup task  */
737
      TIMESPEC_ASSIGN(&lev->cbs_ft_dline[ lev->backup[p] ],
738
                      &lev->cbs_ft_dline[p]);
739
      proc_table[ lev->backup[p] ].avail_time = proc_table[p].avail_time;
740
      lev->CP[p] = 0;
741
 
742
      /* and, finally, we insert the backup task in the master level */
743
      job_task_default_model(job, lev->cbs_ft_dline[p]);
744
      job_task_def_yesexc(job);
745
      level_table[ lev->scheduling_level ]->
746
        guest_create(lev->scheduling_level, lev->backup[p],
747
                     (TASK_MODEL *)&job);
748
      level_table[ lev->scheduling_level ]->
749
        guest_activate(lev->scheduling_level, lev->backup[p]);
750
    }
751
    else {
752
      /* A spare capacity is inserted in the capacity queue!! */
753
      proc_table[p].avail_time += proc_table[ lev->backup[p] ].wcet;    
754
      if (proc_table[p].avail_time > 0) {
755
        c_insert(lev->cbs_ft_dline[p], proc_table[p].avail_time,
756
                 &lev->queue, p);
757
        proc_table[p].avail_time = 0;
758
      }
759
    }
760
  }
761
  else {
762
    /* this branch is for backup tasks:
763
       A spare capacity is inserted in the capacity queue!! */
764
    if (proc_table[p].avail_time > 0) {
765
      c_insert(lev->cbs_ft_dline[p], proc_table[p].avail_time,
766
               &lev->queue, p);
767
      proc_table[p].avail_time = 0;
768
    }
769
  }  
770
}
771
 
772
 
773
static void CBS_FT_task_end(LEVEL l, PID p)
774
{
775
  CBS_FT_level_des *lev = (CBS_FT_level_des *)(level_table[l]);
776
 
777
  /* A backup task cannot be killed, this behaviour can be modified
778
     in a new release */
779
  if (lev->P_or_B[p] == BACKUP) {
780
    kern_printf("\nKilling a BACKUP task!\n");
1100 pj 781
    kern_raise(XINVALID_TASK, p);
1085 pj 782
    return;
783
  }
784
 
785
  /* check if the capacity becomes negative... */
786
  /* there is a while because if the wcet is << than the system tick
787
     we need to postpone the deadline many times */
788
  while (proc_table[p].avail_time < 0) {
789
    /* the CBS_FT rule for recharging the capacity */
790
    proc_table[p].avail_time += lev->maxcap[p];
791
    ADDUSEC2TIMESPEC(lev->period[p], &lev->cbs_ft_dline[p]);
792
  }
793
 
794
  level_table[ lev->scheduling_level ]->
795
    guest_end(lev->scheduling_level,p);
796
 
797
 
798
  /* we delete the reactivation timer */
799
  event_delete(lev->reactivation_timer[p]);
800
  lev->reactivation_timer[p] = -1;
801
 
802
 
803
  /* Finally, we post the zombie event. when the end period is reached,
804
     the task descriptor and banwidth are freed */
805
  proc_table[p].status = CBS_FT_ZOMBIE;
806
  lev->reactivation_timer[p] = kern_event_post(&lev->cbs_ft_dline[p],
807
                                               CBS_FT_timer_zombie,
808
                                               (void *)p);
809
}
810
 
811
 
812
static void CBS_FT_task_sleep(LEVEL l, PID p)
813
{
814
  printk("CBS_FT_task_sleep\n");
1100 pj 815
  kern_raise(XINVALID_TASK,p);
1085 pj 816
}
817
 
818
 
819
static int CBS_FT_guest_create(LEVEL l, PID p, TASK_MODEL *m)
1100 pj 820
{ kern_raise(XINVALID_GUEST,exec_shadow); return 0; }
1085 pj 821
 
822
static void CBS_FT_guest_detach(LEVEL l, PID p)
1100 pj 823
{ kern_raise(XINVALID_GUEST,exec_shadow); }
1085 pj 824
 
825
static void CBS_FT_guest_dispatch(LEVEL l, PID p, int nostop)
1100 pj 826
{ kern_raise(XINVALID_GUEST,exec_shadow); }
1085 pj 827
 
828
static void CBS_FT_guest_epilogue(LEVEL l, PID p)
1100 pj 829
{ kern_raise(XINVALID_GUEST,exec_shadow); }
1085 pj 830
 
831
static void CBS_FT_guest_activate(LEVEL l, PID p)
1100 pj 832
{ kern_raise(XINVALID_GUEST,exec_shadow); }
1085 pj 833
 
834
static void CBS_FT_guest_insert(LEVEL l, PID p)
1100 pj 835
{ kern_raise(XINVALID_GUEST,exec_shadow); }
1085 pj 836
 
837
static void CBS_FT_guest_extract(LEVEL l, PID p)
1100 pj 838
{ kern_raise(XINVALID_GUEST,exec_shadow); }
1085 pj 839
 
840
static void CBS_FT_guest_endcycle(LEVEL l, PID p)
1100 pj 841
{ kern_raise(XINVALID_GUEST,exec_shadow); }
1085 pj 842
 
843
static void CBS_FT_guest_end(LEVEL l, PID p)
1100 pj 844
{ kern_raise(XINVALID_GUEST,exec_shadow); }
1085 pj 845
 
846
static void CBS_FT_guest_sleep(LEVEL l, PID p)
1100 pj 847
{ kern_raise(XINVALID_GUEST,exec_shadow); }
1085 pj 848
 
849
 
850
 
851
 
852
/* Registration functions */
853
 
854
/*+ Registration function:
855
    int flags                 the init flags ... see CBS.h +*/
856
void CBS_FT_register_level(int flags, LEVEL master)
857
{
858
  LEVEL l;            /* the level that we register */
859
  CBS_FT_level_des *lev;  /* for readableness only */
860
  PID i;              /* a counter */
861
 
862
  printk("CBS_FT_register_level\n");
863
 
864
  /* request an entry in the level_table */
865
  l = level_alloc_descriptor();
866
 
867
  printk("    alloco descrittore %d %d\n",l,sizeof(CBS_FT_level_des));
868
 
869
  /* alloc the space needed for the CBS_FT_level_des */
870
  lev = (CBS_FT_level_des *)kern_alloc(sizeof(CBS_FT_level_des));
871
 
872
  printk("    lev=%d\n",(int)lev);
873
 
874
  /* update the level_table with the new entry */
875
  level_table[l] = (level_des *)lev;
876
 
877
  /* fill the standard descriptor */
878
  strncpy(lev->l.level_name,  CBS_FT_LEVELNAME, MAX_LEVELNAME);
879
  lev->l.level_code               = CBS_FT_LEVEL_CODE;
880
  lev->l.level_version            = CBS_FT_LEVEL_VERSION;
881
 
882
  lev->l.level_accept_task_model  = CBS_FT_level_accept_task_model;
883
  lev->l.level_accept_guest_model = CBS_FT_level_accept_guest_model;
884
  lev->l.level_status             = CBS_FT_level_status;
885
  lev->l.level_scheduler          = CBS_FT_level_scheduler;
886
 
887
  if (flags & CBS_FT_ENABLE_GUARANTEE)
888
    lev->l.level_guarantee        = CBS_FT_level_guarantee;
889
  else
890
    lev->l.level_guarantee        = NULL;
891
 
892
  lev->l.task_create              = CBS_FT_task_create;
893
  lev->l.task_detach              = CBS_FT_task_detach;
894
  lev->l.task_eligible            = CBS_FT_task_eligible;
895
  lev->l.task_dispatch            = CBS_FT_task_dispatch;
896
  lev->l.task_epilogue            = CBS_FT_task_epilogue;
897
  lev->l.task_activate            = CBS_FT_task_activate;
898
  lev->l.task_insert              = CBS_FT_task_insert;
899
  lev->l.task_extract             = CBS_FT_task_extract;
900
  lev->l.task_endcycle            = CBS_FT_task_endcycle;
901
  lev->l.task_end                 = CBS_FT_task_end;
902
  lev->l.task_sleep               = CBS_FT_task_sleep;
903
 
904
  lev->l.guest_create             = CBS_FT_guest_create;
905
  lev->l.guest_detach             = CBS_FT_guest_detach;
906
  lev->l.guest_dispatch           = CBS_FT_guest_dispatch;
907
  lev->l.guest_epilogue           = CBS_FT_guest_epilogue;
908
  lev->l.guest_activate           = CBS_FT_guest_activate;
909
  lev->l.guest_insert             = CBS_FT_guest_insert;
910
  lev->l.guest_extract            = CBS_FT_guest_extract;
911
  lev->l.guest_endcycle           = CBS_FT_guest_endcycle;
912
  lev->l.guest_end                = CBS_FT_guest_end;
913
  lev->l.guest_sleep              = CBS_FT_guest_sleep;
914
 
915
  /* fill the CBS_FT descriptor part */
916
  for (i=0; i<MAX_PROC; i++) {
917
     NULL_TIMESPEC(&lev->cbs_ft_dline[i]);
918
     lev->period[i] = 0;
919
     NULL_TIMESPEC(&lev->reactivation_time[i]);
920
     lev->reactivation_timer[i] = -1;
921
     lev->maxcap[i] = 0;
922
     lev->backup[i] = NIL;
923
     lev->CP[i] = 0;
924
     lev->P_or_B[i] = PRIMARY;
925
  }
926
 
927
  lev->U = 0;
928
  lev->idle = 0;
929
  lev->queue = NULL;
930
 
931
  lev->scheduling_level = master;
932
 
933
  lev->flags = flags & 0x07;
934
}
935
 
936
 
937
 
938
bandwidth_t CBS_FT_usedbandwidth(LEVEL l)
939
{
940
 
941
  CBS_FT_level_des *lev = (CBS_FT_level_des *)(level_table[l]);
942
  if (lev->l.level_code    == CBS_FT_LEVEL_CODE &&
943
      lev->l.level_version == CBS_FT_LEVEL_VERSION)
944
    return lev->U;
945
  else
946
    return 0;
947
}
948
 
949
 
950
 
951
void CBS_FT_Primary_Abort()
952
{
953
  PID p;
954
  CBS_FT_level_des *lev;
955
 
956
  kern_cli();
957
  p = exec_shadow;
958
  lev = (CBS_FT_level_des *)level_table[proc_table[p].task_level];
959
  lev->CP[p] = 1;
960
  kern_sti();
961
}
962
 
963
 
964
char CBS_FT_Checkpoint()
965
{
966
  char f;
967
  PID p;
968
  CBS_FT_level_des *lev;
969
 
970
  kern_cli();
971
  p = exec_shadow;
972
  lev = (CBS_FT_level_des *)level_table[proc_table[p].task_level];
973
  f = lev->CP[p];
974
  kern_sti();
975
  return f;
976
}
977