Subversion Repositories shark

Rev

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

Rev Author Line No. Line
221 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
 *   (see the web pages for full authors list)
13
 *
14
 * ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
15
 *
16
 * http://www.sssup.it
17
 * http://retis.sssup.it
18
 * http://shark.sssup.it
19
 */
20
 
21
/*
22
 * Copyright (C) 2002 Paolo Gai
23
 *
24
 * This program is free software; you can redistribute it and/or modify
25
 * it under the terms of the GNU General Public License as published by
26
 * the Free Software Foundation; either version 2 of the License, or
27
 * (at your option) any later version.
28
 *
29
 * This program is distributed in the hope that it will be useful,
30
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
32
 * GNU General Public License for more details.
33
 *
34
 * You should have received a copy of the GNU General Public License
35
 * along with this program; if not, write to the Free Software
36
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
37
 *
38
 */
39
 
40
#include "cbsstar.h"
41
 
42
/*
43
 * DEBUG stuffs begin
44
 */
45
//#define CBSSTAR_DEBUG
46
#ifdef CBSSTAR_DEBUG
47
 
48
static __inline__ void fake_printf(char *fmt, ...) {}
49
 
50
#define cbsstar_printf kern_printf
51
#define cbsstar_printf2 kern_printf
52
#define cbsstar_printf3 kern_printf
53
 
54
//#define cbsstar_printf fake_printf
55
//#define cbsstar_printf2 fake_printf
56
//#define cbsstar_printf3 fake_printf
57
 
58
#endif
59
/*
60
 * DEBUG stuffs end
61
 */
62
 
63
/* this structure contains the status for a single budget */
64
struct budget_struct {
65
  TIME Q;                 /* budget */
66
  TIME T;                 /* period */
67
 
68
  struct timespec dline;  /* deadline */
69
  int dline_timer;        /* oslib event for budget reactivation*/
70
  int avail;              /* current budget */
71
 
72
  LEVEL l;                /* Current CBSSTAR level */
73
  int loc_sched_id;       /* Local scheduler id */
74
  LEVEL loc_sched_level;  /* Local scheduler level */
75
 
76
  PID current;            /* the task currently put in execution */
77
  int flags;
78
 
79
  IQUEUE tasks;           /* a FIFO queue for the tasks handled
80
                             using the budget */
81
 
82
};
83
 
84
#define CBSSTAR_NOACTIVE 0
85
#define CBSSTAR_ACTIVE   1
86
#define CBSSTAR_INIT     2
87
 
88
typedef struct {
89
  level_des l;               /* the standard level descriptor */
90
 
91
  struct budget_struct *b;   /* the budgets! */
92
  int n;                     /* the maximum index for the budgets */
93
  int freebudgets;           /* number of free budgets; starts from n */
94
 
95
  int tb[MAX_PROC];          /* link task->budget (used in guest_end) */
96
 
97
  bandwidth_t U;   /*+ the used bandwidth by the server       +*/
98
 
99
  int cap_lev;
100
 
101
  LEVEL scheduling_level;
102
 
103
} CBSSTAR_level_des;
104
 
105
 
106
static void CBSSTAR_deadline_timer_hardreservation(void *a)
107
{
108
  struct budget_struct *b = a;
109
  PID p;
110
 
111
  #ifdef CBSSTAR_DEBUG
112
    cbsstar_printf("(CS:HrdRes:");  
113
  #endif
114
 
115
  b->dline_timer = NIL;
116
 
117
  /* we modify the deadline according to rule 4 ... */
118
  /* there is a while because if the wcet is << than the system tick
119
     we need to postpone the deadline many times */
120
 
121
  b->avail += b->Q;
122
  if (b->avail > b->Q) b->avail = b->Q;
123
 
124
  if (b->avail > 0) b->flags = CBSSTAR_ACTIVE;
125
 
126
  /* avail may be <0 because a task executed via a shadow fo many time
127
     b->current == NIL only if the prec task was finished and there
128
     was not any other task to be put in the ready queue
129
     ... we are now activating the next task */
130
  if (b->current == NIL && b->flags) {
131
      if (iq_query_first(&(b->tasks)) != NIL) {
132
        CBSSTAR_level_des *lev;
133
        JOB_TASK_MODEL job;
134
 
135
        p = iq_getfirst(&b->tasks);
136
 
137
        #ifdef CBSSTAR_DEBUG
138
          cbsstar_printf("%d",p);
139
        #endif
140
 
141
        kern_gettime(&b->dline);
142
        ADDUSEC2TIMESPEC(b->T, &b->dline);
143
 
144
        b->current = p;
145
 
146
        lev = (CBSSTAR_level_des *)(level_table[b->l]);
147
 
148
        job_task_default_model(job, b->dline);
149
        job_task_def_noexc(job);
150
        level_table[ lev->scheduling_level ]->
151
          private_insert(lev->scheduling_level, p, (TASK_MODEL *)&job);
152
 
153
        event_need_reschedule();
154
 
155
    }
234 giacomo 156
  }
221 giacomo 157
 
234 giacomo 158
  if (b->flags == CBSSTAR_NOACTIVE) {
221 giacomo 159
    kern_gettime(&b->dline);
160
    ADDUSEC2TIMESPEC(b->T, &b->dline);
161
 
162
    b->dline_timer=kern_event_post(&b->dline, CBSSTAR_deadline_timer_hardreservation, b);
163
  }
164
 
165
  #ifdef CBSSTAR_DEBUG
166
    cbsstar_printf(")");
167
  #endif
168
 
169
}
170
 
171
static void CBSSTAR_activation(CBSSTAR_level_des *lev,
172
                           PID p,
173
                           struct timespec *acttime)
174
{
175
  JOB_TASK_MODEL job;
176
  struct budget_struct *b = &lev->b[lev->tb[p]];
177
  /* we have to check if the deadline and the wcet are correct before
178
     activating a new task or an old task... */
179
 
180
  /* check 1: if the deadline is before than the actual scheduling time */
234 giacomo 181
  if (TIMESPEC_A_LT_B(&b->dline, acttime)) {
221 giacomo 182
    TIMESPEC_ASSIGN(&b->dline, acttime);
183
    ADDUSEC2TIMESPEC(b->T, &b->dline);
184
  }  
185
 
186
  /* and the capacity */
187
  if (b->flags == CBSSTAR_INIT) {
188
    b->avail = b->Q;
189
    b->flags = CBSSTAR_ACTIVE;
190
  }  
191
 
192
  /* record the current task inserted in the master module */
193
  b->current = p;
194
 
195
  job_task_default_model(job, b->dline);
196
  job_task_def_noexc(job);
197
  level_table[ lev->scheduling_level ]->
198
    private_insert(lev->scheduling_level, p, (TASK_MODEL *)&job);
199
 
200
}
201
 
202
static void CBSSTAR_account_capacity(CBSSTAR_level_des *lev, PID p)
203
{
204
  struct timespec ty;
205
  TIME tx;
206
  struct budget_struct *b = &lev->b[lev->tb[p]];
207
 
208
  if (lev->cap_lev != NIL && b->current == p) {
209
    kern_event_delete(lev->cap_lev);
210
    lev->cap_lev = NIL;
211
  }
212
 
213
  SUBTIMESPEC(&schedule_time, &cap_lasttime, &ty);
214
  tx = TIMESPEC2USEC(&ty);
234 giacomo 215
  b->avail -= tx;
221 giacomo 216
 
217
  #ifdef CBSSTAR_DEBUG
234 giacomo 218
    kern_printf("(CS:Cap p%d av=%d)", p, b->avail);
221 giacomo 219
  #endif
220
 
234 giacomo 221
  if (b->avail <= 0) b->flags = CBSSTAR_NOACTIVE;
221 giacomo 222
 
223
  if (TIMESPEC_A_LT_B(&b->dline, &schedule_time)) {
224
    /* we modify the deadline ... */
225
    TIMESPEC_ASSIGN(&b->dline, &schedule_time);
226
    ADDUSEC2TIMESPEC(b->T, &b->dline);
227
  }
228
 
229
  if (b->flags == CBSSTAR_NOACTIVE && b->dline_timer == NIL)  {
230
    b->dline_timer=kern_event_post(&b->dline, CBSSTAR_deadline_timer_hardreservation, b);
231
  }
232
 
233
}
234
 
235
 
236
/* The on-line guarantee is enabled only if the appropriate flag is set... */
237
static int CBSSTAR_public_guarantee(LEVEL l, bandwidth_t *freebandwidth)
238
{
239
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
240
 
241
  #ifdef CBSSTAR_DEBUG
242
    cbsstar_printf("(CS:Gua)");
243
  #endif
244
 
245
  if (*freebandwidth >= lev->U) {
246
    *freebandwidth -= lev->U;
247
    return 1;
248
  }
249
  else
250
    return 0;
251
}
252
 
253
static void capacity_handler(void *l)
254
{
255
 
256
  CBSSTAR_level_des *lev = l;
257
  lev->cap_lev = NIL;
258
  event_need_reschedule();
259
 
260
}
261
 
262
static int CBSSTAR_private_eligible(LEVEL l, PID p)
263
{
264
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
265
  struct budget_struct *b = &lev->b[lev->tb[p]];
266
  JOB_TASK_MODEL job;
267
 
268
  /* we have to check if the deadline and the wcet are correct...
269
     if the CBSSTAR level schedules in background with respect to others
270
     levels, there can be the case in witch a task is scheduled by
271
     schedule_time > CBSSTAR_deadline; in this case (not covered in the
272
     article because if there is only the standard scheduling policy
273
     this never apply) we reassign the deadline */
274
  if (b->current == p) {
275
    if ( TIMESPEC_A_LT_B(&b->dline, &schedule_time)) {
276
      if (lev->cap_lev!=NIL) {
277
        kern_event_delete(lev->cap_lev);
278
        lev->cap_lev=NIL;
279
      }
280
 
281
      /* we kill the current activation */
282
      level_table[ lev->scheduling_level ]->
283
        private_extract(lev->scheduling_level, p);
284
      /* we modify the deadline ... */
285
      TIMESPEC_ASSIGN(&b->dline, &schedule_time);
286
      ADDUSEC2TIMESPEC(b->T, &b->dline);
287
 
288
      /* and the capacity */
289
      b->avail = b->Q;
290
      b->flags = CBSSTAR_ACTIVE;
291
 
292
      if (b->dline_timer!=NIL)  {
293
        kern_event_delete(b->dline_timer);
294
        b->dline_timer=NIL;
295
      }
296
 
297
      /* and, finally, we reinsert the task in the master level */
298
      job_task_default_model(job, b->dline);
299
      job_task_def_noexc(job);
300
      level_table[ lev->scheduling_level ]->
301
        private_insert(lev->scheduling_level, p, (TASK_MODEL *)&job);
302
 
303
      return -1;
304
 
305
    }  
306
  }
307
 
308
  return 0;
309
 
310
}
311
 
312
static void CBSSTAR_private_insert(LEVEL l, PID p, TASK_MODEL *m)
313
{
314
  /* A task has been activated for some reason. Basically, the task is
315
  inserted in the queue if the queue is empty, otherwise the task is
316
  inserted into the master module, and an oslib event is posted. */
317
 
318
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
319
  BUDGET_TASK_MODEL *budget;
320
 
321
  if (m->pclass != BUDGET_PCLASS ||
322
      (m->level != 0 && m->level != l)) {
323
    kern_raise(XINVALID_TASK, p);
324
    return;
325
  }
326
  budget = (BUDGET_TASK_MODEL *)m;
327
 
328
  #ifdef CBSSTAR_DEBUG
329
    cbsstar_printf("(CS:PriIns:%d:%d", p, budget->b);
330
  #endif
331
 
332
  if (budget->b == -1)
333
    return;
334
 
335
  lev->tb[p] = budget->b;
336
 
337
  if (lev->b[budget->b].current == NIL && lev->b[budget->b].flags ) {
338
    /* This is the first task in the budget,
339
       the task have to be inserted into the master module */
340
    struct timespec t;
341
    kern_gettime(&t);
342
    CBSSTAR_activation(lev,p,&t);
343
  } else {
344
    /* The budget is not empty, another task is already into the
345
       master module, so the task is inserted at the end of the budget
346
       queue */
347
    iq_insertlast(p,&lev->b[budget->b].tasks);
348
  }
349
 
350
  #ifdef CBSSTAR_DEBUG
351
    cbsstar_printf(")");
352
  #endif
353
 
354
}
355
 
356
static void CBSSTAR_private_extract(LEVEL l, PID p)
357
{
358
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
359
 
360
  #ifdef CBSSTAR_DEBUG
361
    kern_printf("(CS:Ext:%d)", p);
362
  #endif
363
 
364
  /* a task is removed from execution for some reasons. It must be
365
     that it is the first in its budget queue (only the first task in
366
     a budget queue is put into execution!) */
367
 
368
  /* remove the task from execution (or from the ready queue) */
369
  if (lev->b[lev->tb[p]].current == p) {
370
 
371
   CBSSTAR_account_capacity(lev,p);
372
    /* remove the task from the master module */
373
    level_table[ lev->scheduling_level ]->
374
      private_extract(lev->scheduling_level, p);
375
 
376
    /* check if the buffer has someone else to schedule */
377
    if (iq_query_first(&lev->b[lev->tb[p]].tasks) == NIL) {
378
      /* the buffer has no tasks! */
379
      lev->b[lev->tb[p]].current = NIL;
380
    }
381
    else if (lev->b[lev->tb[p]].flags) {
382
      /* if so, insert the new task into the master module */
383
      PID n;
384
      struct timespec t;
385
 
386
      kern_gettime(&t);
387
      n = iq_getfirst(&lev->b[lev->tb[p]].tasks);
388
      CBSSTAR_activation(lev,n,&t);  // it modifies b[lev->tb[p]].current
389
    }
390
    else
391
      lev->b[lev->tb[p]].current=NIL;
392
 
393
  }
394
  else  {
395
    iq_extract(p, &lev->b[lev->tb[p]].tasks);
396
  }
397
}
398
 
399
static void CBSSTAR_private_dispatch(LEVEL l, PID p, int nostop)
400
{
401
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
402
  struct timespec ty;
403
 
404
  #ifdef CBSSTAR_DEBUG
405
    kern_printf("(CS:Dsp:%d)", p);
406
  #endif
407
 
408
  /* the current task (that is the only one inserted in the master module
409
     for the corresponding budget) is dispatched. Note that the current
410
     task is not inserted in any FIFO queue, so the task does not have to
411
     be extracted! */
412
 
413
  /* ... then, we dispatch it to the master level */
414
  level_table[ lev->scheduling_level ]->
415
    private_dispatch(lev->scheduling_level,p,nostop);
416
 
417
  /* ...and finally, we have to post a capacity event */
418
  if (!nostop) {
419
    TIMESPEC_ASSIGN(&ty, &schedule_time);
420
    ADDUSEC2TIMESPEC(lev->b[lev->tb[p]].avail,&ty);
421
    lev->cap_lev = kern_event_post(&ty,capacity_handler, lev);
422
  }
423
 
424
}
425
 
426
static void CBSSTAR_private_epilogue(LEVEL l, PID p)
427
{
428
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
429
  struct budget_struct *b = &lev->b[lev->tb[p]];
430
 
431
  #ifdef CBSSTAR_DEBUG
432
    kern_printf("(CS:Epi:%d)",p);
433
  #endif
434
 
435
  if (p==b->current)  {
436
 
437
    CBSSTAR_account_capacity(lev,p);
438
 
439
    // L'evento di capacità va cancellato perchè sarà ripristinato nella successiva dispatch
440
    /* we have to check if the capacity is still available */
441
    if (b->flags)  {
442
      /* there is capacity available, maybe it is simply a preemption;
443
         the task have to return to the ready queue */
444
      level_table[ lev->scheduling_level ]->
445
        private_epilogue(lev->scheduling_level,p);
446
 
447
    } else {
448
      /* we kill the current activation */
449
      level_table[ lev->scheduling_level ]->
450
        private_extract(lev->scheduling_level, p);    
451
 
452
      iq_insertfirst(p, &b->tasks);
453
      b->current = NIL;
454
 
455
    }
456
 
457
  }
458
 
459
}
460
 
461
/* Registration functions }*/
462
 
463
/*+ Registration function:
464
    int flags                 the init flags ... see CBSSTAR.h +*/
465
LEVEL CBSSTAR_register_level(int n, LEVEL master)
466
{
467
  LEVEL l;            /* the level that we register */
468
  CBSSTAR_level_des *lev;  /* for readableness only */
469
  PID i;              /* a counter */
470
 
471
  kern_printf("CBSSTAR_register_level\n");
472
 
473
  /* request an entry in the level_table */
474
  l = level_alloc_descriptor(sizeof(CBSSTAR_level_des));
475
 
476
  lev = (CBSSTAR_level_des *)level_table[l];
477
 
478
  /* fill the standard descriptor */
479
  lev->l.private_insert   = CBSSTAR_private_insert;
480
  lev->l.private_extract  = CBSSTAR_private_extract;
481
  lev->l.private_eligible = CBSSTAR_private_eligible;
482
  lev->l.private_dispatch = CBSSTAR_private_dispatch;
483
  lev->l.private_epilogue = CBSSTAR_private_epilogue;
484
 
485
  lev->l.public_guarantee = CBSSTAR_public_guarantee;
486
 
487
  /* fill the CBSSTAR descriptor part */
488
  lev->b = (struct budget_struct *)kern_alloc(sizeof(struct budget_struct)*n);
489
 
490
  for (i=0; i<n; i++) {
491
    lev->b[i].Q = 0;
492
    lev->b[i].T = 0;
493
    NULL_TIMESPEC(&lev->b[i].dline);
494
    lev->b[i].dline_timer = NIL;
495
    lev->b[i].avail = 0;
496
    lev->b[i].current = -1;
497
    lev->b[i].flags = CBSSTAR_INIT;
498
    lev->b[i].l=l;
499
    iq_init(&lev->b[i].tasks, &freedesc, 0);
500
  }
501
 
502
  lev->n = n;
503
  lev->freebudgets = 0;
504
 
505
  for (i=0; i<MAX_PROC; i++)
506
    lev->tb[i] = NIL;
507
 
508
  lev->U = 0;
509
  lev->cap_lev = NIL;
510
  lev->scheduling_level = master;
511
 
512
  return l;
513
 
514
}
515
 
516
int CBSSTAR_setbudget(LEVEL l, TIME Q, TIME T, LEVEL local_scheduler_level, int scheduler_id)
517
{
518
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
519
  int r;
520
 
521
  #ifdef CBSSTAR_DEBUG
522
    cbsstar_printf("(CS:SetBud)");
523
  #endif
524
 
525
  for (r = 0; r < lev->n; r++)
526
    if (lev->b[r].Q == 0) break;
527
 
528
  if (r != lev->n) {
529
    bandwidth_t b;
530
    b = (MAX_BANDWIDTH / T) * Q;
531
 
532
    /* really update lev->U, checking an overflow... */
533
    if (Q< T && MAX_BANDWIDTH - lev->U > b) {
534
 
535
      lev->U += b;
536
      lev->freebudgets++;
537
 
538
      lev->b[r].Q = Q;
539
      lev->b[r].T = T;
540
 
541
      lev->b[r].loc_sched_id = scheduler_id;
542
      lev->b[r].loc_sched_level = local_scheduler_level;
543
 
544
      return r;
545
    }
546
    else
547
      return -2;
548
  }
549
  else
550
    return -1;
551
}
552
 
553
int CBSSTAR_removebudget(LEVEL l, int budget)
554
{
555
 
556
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
557
 
558
  bandwidth_t b;
559
 
560
  b = (MAX_BANDWIDTH / lev->b[budget].T) * lev->b[budget].Q;
561
 
562
  lev->U -= b;
563
 
564
  lev->b[budget].Q = 0;
565
  lev->b[budget].T = 0;
566
  NULL_TIMESPEC(&lev->b[budget].dline);
567
  lev->b[budget].dline_timer = NIL;
568
  lev->b[budget].avail = 0;
569
  lev->b[budget].current = -1;
570
  lev->b[budget].flags = CBSSTAR_INIT;
571
  iq_init(&lev->b[budget].tasks, &freedesc, 0);
572
 
573
  return 0;
574
 
575
}
576
 
577
int CBSSTAR_adjust_budget(LEVEL l, TIME Q, TIME T, int budget)
578
{
579
 
580
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
581
 
582
  lev->b[budget].Q = Q;
583
  lev->b[budget].T = T;
584
 
585
  return 0;
586
 
587
}
588
 
589
int CBSSTAR_getbudgetinfo(LEVEL l, TIME *Q, TIME *T, int budget)
590
{
591
 
592
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
593
 
594
  *Q = lev->b[budget].Q;
595
  *T = lev->b[budget].T;
596
 
597
  return 0;
598
 
599
}
600
 
601
int CBSSTAR_is_active(LEVEL l, int budget)
602
{
603
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
604
 
605
  return lev->b[budget].flags;
606
 
607
}
608
 
609
int CBSSTAR_get_local_scheduler_level_from_budget(LEVEL l, int budget)
610
{
611
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
612
 
613
  return lev->b[budget].loc_sched_level;
614
 
615
}
616
 
617
int CBSSTAR_get_local_scheduler_level_from_pid(LEVEL l, PID p)
618
{
619
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
620
 
621
  return lev->b[lev->tb[p]].loc_sched_level;
622
 
623
}
624
 
625
int CBSSTAR_get_local_scheduler_id_from_budget(LEVEL l, int budget)
626
{
627
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
628
 
629
  return lev->b[budget].loc_sched_id;
630
 
631
}
632
 
633
int CBSSTAR_get_local_scheduler_id_from_pid(LEVEL l, PID p)
634
{
635
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
636
 
637
  return lev->b[lev->tb[p]].loc_sched_id;
638
 
639
}
640