Subversion Repositories shark

Rev

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