Subversion Repositories shark

Rev

Rev 234 | Rev 241 | 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
  }
237 giacomo 157
 
158
  kern_gettime(&b->dline);
159
  ADDUSEC2TIMESPEC(b->T, &b->dline);
221 giacomo 160
    b->dline_timer=kern_event_post(&b->dline, CBSSTAR_deadline_timer_hardreservation, b);
161
 
237 giacomo 162
 
221 giacomo 163
  #ifdef CBSSTAR_DEBUG
164
    cbsstar_printf(")");
165
  #endif
166
 
167
}
168
 
169
static void CBSSTAR_activation(CBSSTAR_level_des *lev,
237 giacomo 170
                           PID p)
221 giacomo 171
{
172
  JOB_TASK_MODEL job;
173
  struct budget_struct *b = &lev->b[lev->tb[p]];
174
  /* we have to check if the deadline and the wcet are correct before
175
     activating a new task or an old task... */
176
 
177
  /* and the capacity */
178
  if (b->flags == CBSSTAR_INIT) {
179
    b->avail = b->Q;
180
    b->flags = CBSSTAR_ACTIVE;
237 giacomo 181
  }
221 giacomo 182
 
237 giacomo 183
 
221 giacomo 184
  /* record the current task inserted in the master module */
185
  b->current = p;
186
 
187
  job_task_default_model(job, b->dline);
188
  job_task_def_noexc(job);
189
  level_table[ lev->scheduling_level ]->
190
    private_insert(lev->scheduling_level, p, (TASK_MODEL *)&job);
191
 
192
}
193
 
194
static void CBSSTAR_account_capacity(CBSSTAR_level_des *lev, PID p)
195
{
196
  struct timespec ty;
197
  TIME tx;
198
  struct budget_struct *b = &lev->b[lev->tb[p]];
199
 
200
  if (lev->cap_lev != NIL && b->current == p) {
201
    kern_event_delete(lev->cap_lev);
202
    lev->cap_lev = NIL;
203
  }
204
 
205
  SUBTIMESPEC(&schedule_time, &cap_lasttime, &ty);
206
  tx = TIMESPEC2USEC(&ty);
234 giacomo 207
  b->avail -= tx;
221 giacomo 208
 
209
  #ifdef CBSSTAR_DEBUG
234 giacomo 210
    kern_printf("(CS:Cap p%d av=%d)", p, b->avail);
221 giacomo 211
  #endif
212
 
234 giacomo 213
  if (b->avail <= 0) b->flags = CBSSTAR_NOACTIVE;
221 giacomo 214
 
215
 
216
}
217
 
218
 
219
/* The on-line guarantee is enabled only if the appropriate flag is set... */
220
static int CBSSTAR_public_guarantee(LEVEL l, bandwidth_t *freebandwidth)
221
{
222
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
223
 
224
  #ifdef CBSSTAR_DEBUG
225
    cbsstar_printf("(CS:Gua)");
226
  #endif
227
 
228
  if (*freebandwidth >= lev->U) {
229
    *freebandwidth -= lev->U;
230
    return 1;
231
  }
232
  else
233
    return 0;
234
}
235
 
236
static void capacity_handler(void *l)
237
{
238
 
239
  CBSSTAR_level_des *lev = l;
240
  lev->cap_lev = NIL;
241
  event_need_reschedule();
242
 
243
}
244
 
245
static int CBSSTAR_private_eligible(LEVEL l, PID p)
246
{
247
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
248
  struct budget_struct *b = &lev->b[lev->tb[p]];
249
  JOB_TASK_MODEL job;
250
 
251
  /* we have to check if the deadline and the wcet are correct...
252
     if the CBSSTAR level schedules in background with respect to others
253
     levels, there can be the case in witch a task is scheduled by
254
     schedule_time > CBSSTAR_deadline; in this case (not covered in the
255
     article because if there is only the standard scheduling policy
256
     this never apply) we reassign the deadline */
257
  if (b->current == p) {
258
    if ( TIMESPEC_A_LT_B(&b->dline, &schedule_time)) {
259
      if (lev->cap_lev!=NIL) {
260
        kern_event_delete(lev->cap_lev);
261
        lev->cap_lev=NIL;
262
      }
263
 
264
      /* we kill the current activation */
265
      level_table[ lev->scheduling_level ]->
266
        private_extract(lev->scheduling_level, p);
267
      /* we modify the deadline ... */
268
      TIMESPEC_ASSIGN(&b->dline, &schedule_time);
269
      ADDUSEC2TIMESPEC(b->T, &b->dline);
270
 
271
      /* and the capacity */
272
      b->avail = b->Q;
273
      b->flags = CBSSTAR_ACTIVE;
274
 
275
      if (b->dline_timer!=NIL)  {
276
        kern_event_delete(b->dline_timer);
277
        b->dline_timer=NIL;
278
      }
279
 
280
      /* and, finally, we reinsert the task in the master level */
281
      job_task_default_model(job, b->dline);
282
      job_task_def_noexc(job);
283
      level_table[ lev->scheduling_level ]->
284
        private_insert(lev->scheduling_level, p, (TASK_MODEL *)&job);
285
 
286
      return -1;
287
 
288
    }  
289
  }
290
 
291
  return 0;
292
 
293
}
294
 
295
static void CBSSTAR_private_insert(LEVEL l, PID p, TASK_MODEL *m)
296
{
297
  /* A task has been activated for some reason. Basically, the task is
298
  inserted in the queue if the queue is empty, otherwise the task is
299
  inserted into the master module, and an oslib event is posted. */
300
 
301
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
302
  BUDGET_TASK_MODEL *budget;
303
 
304
  if (m->pclass != BUDGET_PCLASS ||
305
      (m->level != 0 && m->level != l)) {
306
    kern_raise(XINVALID_TASK, p);
307
    return;
308
  }
309
  budget = (BUDGET_TASK_MODEL *)m;
310
 
311
  #ifdef CBSSTAR_DEBUG
312
    cbsstar_printf("(CS:PriIns:%d:%d", p, budget->b);
313
  #endif
314
 
315
  if (budget->b == -1)
316
    return;
317
 
318
  lev->tb[p] = budget->b;
319
 
237 giacomo 320
 
321
  kern_gettime(&lev->b[budget->b].dline);
322
  ADDUSEC2TIMESPEC(lev->b[budget->b].T,&lev->b[budget->b].dline);
323
 
221 giacomo 324
  if (lev->b[budget->b].current == NIL && lev->b[budget->b].flags ) {
325
    /* This is the first task in the budget,
326
       the task have to be inserted into the master module */
237 giacomo 327
    CBSSTAR_activation(lev,p);
221 giacomo 328
  } else {
329
    /* The budget is not empty, another task is already into the
330
       master module, so the task is inserted at the end of the budget
331
       queue */
332
    iq_insertlast(p,&lev->b[budget->b].tasks);
333
  }
334
 
237 giacomo 335
  if (lev->b[budget->b].dline_timer == NIL)  {
336
    lev->b[budget->b].dline_timer = kern_event_post(&lev->b[budget->b].dline, CBSSTAR_deadline_timer_hardreservation, &lev->b[budget->b]);
337
  }
338
 
339
 
221 giacomo 340
  #ifdef CBSSTAR_DEBUG
341
    cbsstar_printf(")");
342
  #endif
343
 
344
}
345
 
346
static void CBSSTAR_private_extract(LEVEL l, PID p)
347
{
348
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
349
 
350
  #ifdef CBSSTAR_DEBUG
351
    kern_printf("(CS:Ext:%d)", p);
352
  #endif
353
 
354
  /* a task is removed from execution for some reasons. It must be
355
     that it is the first in its budget queue (only the first task in
356
     a budget queue is put into execution!) */
357
 
358
  /* remove the task from execution (or from the ready queue) */
359
  if (lev->b[lev->tb[p]].current == p) {
360
 
237 giacomo 361
    CBSSTAR_account_capacity(lev,p);
362
 
221 giacomo 363
    /* remove the task from the master module */
364
    level_table[ lev->scheduling_level ]->
365
      private_extract(lev->scheduling_level, p);
366
 
367
    /* check if the buffer has someone else to schedule */
368
    if (iq_query_first(&lev->b[lev->tb[p]].tasks) == NIL) {
369
      /* the buffer has no tasks! */
370
      lev->b[lev->tb[p]].current = NIL;
371
    }
372
    else if (lev->b[lev->tb[p]].flags) {
373
      /* if so, insert the new task into the master module */
374
      PID n;
237 giacomo 375
 
376
      n = iq_getfirst(&lev->b[lev->tb[p]].tasks);
377
      CBSSTAR_activation(lev,n);
221 giacomo 378
 
379
    }
380
    else
381
      lev->b[lev->tb[p]].current=NIL;
382
 
383
  }
384
  else  {
385
    iq_extract(p, &lev->b[lev->tb[p]].tasks);
386
  }
387
}
388
 
389
static void CBSSTAR_private_dispatch(LEVEL l, PID p, int nostop)
390
{
391
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
392
  struct timespec ty;
393
 
394
  #ifdef CBSSTAR_DEBUG
395
    kern_printf("(CS:Dsp:%d)", p);
396
  #endif
397
 
398
  /* the current task (that is the only one inserted in the master module
399
     for the corresponding budget) is dispatched. Note that the current
400
     task is not inserted in any FIFO queue, so the task does not have to
401
     be extracted! */
402
 
403
  /* ... then, we dispatch it to the master level */
404
  level_table[ lev->scheduling_level ]->
405
    private_dispatch(lev->scheduling_level,p,nostop);
406
 
407
  /* ...and finally, we have to post a capacity event */
408
  if (!nostop) {
409
    TIMESPEC_ASSIGN(&ty, &schedule_time);
410
    ADDUSEC2TIMESPEC(lev->b[lev->tb[p]].avail,&ty);
411
    lev->cap_lev = kern_event_post(&ty,capacity_handler, lev);
412
  }
413
 
414
}
415
 
416
static void CBSSTAR_private_epilogue(LEVEL l, PID p)
417
{
418
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
419
  struct budget_struct *b = &lev->b[lev->tb[p]];
420
 
421
  #ifdef CBSSTAR_DEBUG
422
    kern_printf("(CS:Epi:%d)",p);
423
  #endif
424
 
425
  if (p==b->current)  {
426
 
427
    CBSSTAR_account_capacity(lev,p);
428
 
429
    // L'evento di capacità va cancellato perchè sarà ripristinato nella successiva dispatch
430
    /* we have to check if the capacity is still available */
431
    if (b->flags)  {
432
      /* there is capacity available, maybe it is simply a preemption;
433
         the task have to return to the ready queue */
434
      level_table[ lev->scheduling_level ]->
435
        private_epilogue(lev->scheduling_level,p);
436
 
437
    } else {
438
      /* we kill the current activation */
439
      level_table[ lev->scheduling_level ]->
440
        private_extract(lev->scheduling_level, p);    
441
 
442
      iq_insertfirst(p, &b->tasks);
443
      b->current = NIL;
444
 
445
    }
446
 
447
  }
448
 
449
}
450
 
451
/* Registration functions }*/
452
 
453
/*+ Registration function:
454
    int flags                 the init flags ... see CBSSTAR.h +*/
455
LEVEL CBSSTAR_register_level(int n, LEVEL master)
456
{
457
  LEVEL l;            /* the level that we register */
458
  CBSSTAR_level_des *lev;  /* for readableness only */
459
  PID i;              /* a counter */
460
 
461
  kern_printf("CBSSTAR_register_level\n");
462
 
463
  /* request an entry in the level_table */
464
  l = level_alloc_descriptor(sizeof(CBSSTAR_level_des));
465
 
466
  lev = (CBSSTAR_level_des *)level_table[l];
467
 
468
  /* fill the standard descriptor */
469
  lev->l.private_insert   = CBSSTAR_private_insert;
470
  lev->l.private_extract  = CBSSTAR_private_extract;
471
  lev->l.private_eligible = CBSSTAR_private_eligible;
472
  lev->l.private_dispatch = CBSSTAR_private_dispatch;
473
  lev->l.private_epilogue = CBSSTAR_private_epilogue;
474
 
475
  lev->l.public_guarantee = CBSSTAR_public_guarantee;
476
 
477
  /* fill the CBSSTAR descriptor part */
478
  lev->b = (struct budget_struct *)kern_alloc(sizeof(struct budget_struct)*n);
479
 
480
  for (i=0; i<n; i++) {
481
    lev->b[i].Q = 0;
482
    lev->b[i].T = 0;
483
    NULL_TIMESPEC(&lev->b[i].dline);
484
    lev->b[i].dline_timer = NIL;
485
    lev->b[i].avail = 0;
486
    lev->b[i].current = -1;
487
    lev->b[i].flags = CBSSTAR_INIT;
488
    lev->b[i].l=l;
489
    iq_init(&lev->b[i].tasks, &freedesc, 0);
490
  }
491
 
492
  lev->n = n;
493
  lev->freebudgets = 0;
494
 
495
  for (i=0; i<MAX_PROC; i++)
496
    lev->tb[i] = NIL;
497
 
498
  lev->U = 0;
499
  lev->cap_lev = NIL;
500
  lev->scheduling_level = master;
501
 
502
  return l;
503
 
504
}
505
 
506
int CBSSTAR_setbudget(LEVEL l, TIME Q, TIME T, LEVEL local_scheduler_level, int scheduler_id)
507
{
508
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
509
  int r;
510
 
511
  #ifdef CBSSTAR_DEBUG
512
    cbsstar_printf("(CS:SetBud)");
513
  #endif
514
 
515
  for (r = 0; r < lev->n; r++)
516
    if (lev->b[r].Q == 0) break;
517
 
518
  if (r != lev->n) {
519
    bandwidth_t b;
520
    b = (MAX_BANDWIDTH / T) * Q;
521
 
522
    /* really update lev->U, checking an overflow... */
523
    if (Q< T && MAX_BANDWIDTH - lev->U > b) {
524
 
525
      lev->U += b;
526
      lev->freebudgets++;
527
 
528
      lev->b[r].Q = Q;
529
      lev->b[r].T = T;
530
 
531
      lev->b[r].loc_sched_id = scheduler_id;
532
      lev->b[r].loc_sched_level = local_scheduler_level;
533
 
534
      return r;
535
    }
536
    else
537
      return -2;
538
  }
539
  else
540
    return -1;
541
}
542
 
543
int CBSSTAR_removebudget(LEVEL l, int budget)
544
{
545
 
546
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
547
 
548
  bandwidth_t b;
549
 
550
  b = (MAX_BANDWIDTH / lev->b[budget].T) * lev->b[budget].Q;
551
 
552
  lev->U -= b;
553
 
554
  lev->b[budget].Q = 0;
555
  lev->b[budget].T = 0;
556
  NULL_TIMESPEC(&lev->b[budget].dline);
557
  lev->b[budget].dline_timer = NIL;
558
  lev->b[budget].avail = 0;
559
  lev->b[budget].current = -1;
560
  lev->b[budget].flags = CBSSTAR_INIT;
561
  iq_init(&lev->b[budget].tasks, &freedesc, 0);
562
 
563
  return 0;
564
 
565
}
566
 
567
int CBSSTAR_adjust_budget(LEVEL l, TIME Q, TIME T, int budget)
568
{
569
 
570
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
571
 
572
  lev->b[budget].Q = Q;
573
  lev->b[budget].T = T;
574
 
575
  return 0;
576
 
577
}
578
 
579
int CBSSTAR_getbudgetinfo(LEVEL l, TIME *Q, TIME *T, int budget)
580
{
581
 
582
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
583
 
584
  *Q = lev->b[budget].Q;
585
  *T = lev->b[budget].T;
586
 
587
  return 0;
588
 
589
}
590
 
591
int CBSSTAR_is_active(LEVEL l, int budget)
592
{
593
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
594
 
595
  return lev->b[budget].flags;
596
 
597
}
598
 
599
int CBSSTAR_get_local_scheduler_level_from_budget(LEVEL l, int budget)
600
{
601
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
602
 
603
  return lev->b[budget].loc_sched_level;
604
 
605
}
606
 
607
int CBSSTAR_get_local_scheduler_level_from_pid(LEVEL l, PID p)
608
{
609
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
610
 
611
  return lev->b[lev->tb[p]].loc_sched_level;
612
 
613
}
614
 
615
int CBSSTAR_get_local_scheduler_id_from_budget(LEVEL l, int budget)
616
{
617
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
618
 
619
  return lev->b[budget].loc_sched_id;
620
 
621
}
622
 
623
int CBSSTAR_get_local_scheduler_id_from_pid(LEVEL l, PID p)
624
{
625
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
626
 
627
  return lev->b[lev->tb[p]].loc_sched_id;
628
 
629
}
630