Subversion Repositories shark

Rev

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

Rev Author Line No. Line
1089 pj 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
 ------------
1176 trimarchi 23
 CVS :        $Id: cbsstar.c,v 1.5 2003-06-18 08:13:01 trimarchi Exp $
1089 pj 24
 
25
 File:        $File$
1176 trimarchi 26
 Revision:    $Revision: 1.5 $
27
 Last update: $Date: 2003-06-18 08:13:01 $
1089 pj 28
 ------------
29
 
30
 Read CBSSTAR.h for general details.
31
 
32
 Basically, a budget can be in 2 states:
33
 - Active -> the budget queue is not empty
34
 - Idle   -> the budget queue is empty
35
 
36
 The fact that a task into a budget is inserted into the master module depends
37
 on the value of the remaining time the tasks can spend in the period.
38
 
39
 The module does handle only one oslib event, used to enforce the
40
 temporal isolation between buffers. Note that all is implemented
41
 without using the CONTROL_CAP field.
42
 
43
 Basically, for each budget there can be at most one task inserted
44
 into the master level. Its deadline is modified according to the
45
 usage of its capacity, that is, when a budget is exausted its
46
 deadline is postponed.
47
 
48
*/
49
 
50
/*
51
 * Copyright (C) 2002 Paolo Gai
52
 *
53
 * This program is free software; you can redistribute it and/or modify
54
 * it under the terms of the GNU General Public License as published by
55
 * the Free Software Foundation; either version 2 of the License, or
56
 * (at your option) any later version.
57
 *
58
 * This program is distributed in the hope that it will be useful,
59
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
60
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
61
 * GNU General Public License for more details.
62
 *
63
 * You should have received a copy of the GNU General Public License
64
 * along with this program; if not, write to the Free Software
65
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
66
 *
67
 */
68
 
69
 
70
#include "cbsstar.h"
71
#include <ll/string.h>
72
 
73
 
74
/*
75
 * DEBUG stuffs begin
76
 */
77
 
1176 trimarchi 78
#ifdef CBSSTAR_DEBUG_OLD
1089 pj 79
 
80
static __inline__ void fake_printf(char *fmt, ...) {}
81
 
82
//#define cbsstar_printf kern_printf
83
//#define cbsstar_printf2 kern_printf
84
//#define cbsstar_printf3 kern_printf
85
 
86
#define cbsstar_printf fake_printf
87
#define cbsstar_printf2 fake_printf
88
#define cbsstar_printf3 fake_printf
89
 
1176 trimarchi 90
#if 0 
91
void cbsstar_printq(IQUEUE *q)
1089 pj 92
{
93
  PID p;
94
  kern_printf("[");
95
  p = q->first;
96
  kern_printf("->%d",p);
97
  while (p != NIL) {
98
    p = proc_table[p].next;
99
    kern_printf("->%d",p);
100
  }
101
  kern_printf("]");
102
}
103
#else
104
static __inline__ void cbsstar_printq(QQUEUE *q) {}
105
#endif
106
 
1176 trimarchi 107
#if 0 
1089 pj 108
static __inline__ void cbsstar_printblob(int x) { if (x) cputc('±'); else cputc('Û'); }
109
#else
110
static __inline__ void cbsstar_printblob(int x) {}
111
#endif
112
 
113
#endif
114
 
115
/*
116
 * DEBUG stuffs end
117
 */
118
 
119
 
120
/* this structure contains the status for a single budget */
121
struct budget_struct {
122
  TIME Q;                 /* budget */
123
  TIME T;                 /* period */
1176 trimarchi 124
 
1089 pj 125
  struct timespec dline;  /* deadline */
126
  int dline_timer;        /* oslib event for budget reactivation*/
127
  int avail;              /* current budget */
128
 
129
  PID current;            /* the task currently put in execution */
130
 
1116 pj 131
  IQUEUE tasks;           /* a FIFO queue for the tasks handled
1089 pj 132
                             using the budget */
133
};
134
 
135
typedef struct {
136
  level_des l;               /* the standard level descriptor */
137
 
138
  struct budget_struct *b;   /* the budgets! */
139
  int n;                     /* the maximum index for the budgets */
140
  int freebudgets;           /* number of free budgets; starts from n */
141
 
142
  int tb[MAX_PROC];          /* link task->budget (used in guest_end) */
143
 
144
  bandwidth_t U;   /*+ the used bandwidth by the server       +*/
1176 trimarchi 145
 
146
  int cap_lev;
1089 pj 147
 
148
  LEVEL scheduling_level;
149
 
150
} CBSSTAR_level_des;
151
 
152
 
153
static void CBSSTAR_activation(CBSSTAR_level_des *lev,
154
                           PID p,
155
                           struct timespec *acttime)
156
{
157
  JOB_TASK_MODEL job;
158
  struct budget_struct *b = &lev->b[lev->tb[p]];
159
 
160
  /* we have to check if the deadline and the wcet are correct before
161
     activating a new task or an old task... */
162
 
163
  /* check 1: if the deadline is before than the actual scheduling time */
164
 
165
  /* check 2: if ( avail_time >= (cbs_dline - acttime)* (wcet/period) )
166
     (rule 7 in the CBS article!) */
167
  TIME t;
168
  struct timespec t2,t3;
169
 
170
  t = (b->T * b->avail) / b->Q;
171
  t3.tv_sec = t / 1000000;
172
  t3.tv_nsec = (t % 1000000) * 1000;
173
 
174
  SUBTIMESPEC(&b->dline, acttime, &t2);
175
 
176
  if (/* 1 */ TIMESPEC_A_LT_B(&b->dline, acttime) ||
177
      /* 2 */ TIMESPEC_A_GT_B(&t3, &t2) ) {
178
/*    if (TIMESPEC_A_LT_B(&lev->cbs_dline[p], acttime) )
179
      kern_printf("$");
180
    else
181
      kern_printf("(Ûdline%d.%d act%d.%d wcet%d per%d avail%dÛ)",
182
                  lev->cbs_dline[p].tv_sec,lev->cbs_dline[p].tv_nsec/1000,
183
                  acttime->tv_sec, acttime->tv_nsec/1000,
184
                  proc_table[p].wcet, lev->period[p], proc_table[p].avail_time);
185
*/  /* we modify the deadline ... */
186
    TIMESPEC_ASSIGN(&b->dline, acttime);
187
    ADDUSEC2TIMESPEC(b->T, &b->dline);
1176 trimarchi 188
 
1089 pj 189
    /* and the capacity */
190
    b->avail = b->Q;
191
 
1176 trimarchi 192
 
1089 pj 193
#ifdef CBSSTAR_DEBUG
194
    cbsstar_printf3("±%d±",lev->tb[p]);
195
    cbsstar_printblob(lev->tb[p]);
196
#endif
197
  }
198
 
199
  /* record the current task inserted in the master module */
200
  b->current = p;
201
 
202
#ifdef CBSSTAR_DEBUG
203
  cbsstar_printf("(C:iact p%d %ld.%ld av=%d)",p,b->dline.tv_sec,b->dline.tv_nsec/1000, b->avail);
204
#endif
1176 trimarchi 205
  //kern_printf("Pid %d, Act %d, Dd %d", p,acttime->tv_nsec/1000,(b->dline).tv_nsec/1000);
1089 pj 206
  /* and, finally, we reinsert the task in the master level */
207
  job_task_default_model(job, b->dline);
208
  job_task_def_noexc(job);
209
  level_table[ lev->scheduling_level ]->
1123 pj 210
    private_insert(lev->scheduling_level, p, (TASK_MODEL *)&job);
1089 pj 211
}
212
 
213
 
214
static void CBSSTAR_account_capacity(CBSSTAR_level_des *lev, PID p)
215
{
216
  struct timespec ty;
217
  TIME tx;
218
 
219
  SUBTIMESPEC(&schedule_time, &cap_lasttime, &ty);
220
  tx = TIMESPEC2USEC(&ty);
221
  lev->b[lev->tb[p]].avail -= tx;
222
 
223
#ifdef CBSSTAR_DEBUG
224
  cbsstar_printf2("(C:cap p%d av=%d)", p, lev->b[lev->tb[p]].avail);
225
#endif
226
}
227
 
228
 
229
/* The on-line guarantee is enabled only if the appropriate flag is set... */
1123 pj 230
static int CBSSTAR_public_guarantee(LEVEL l, bandwidth_t *freebandwidth)
1089 pj 231
{
232
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
233
 
234
#ifdef CBSSTAR_DEBUG
235
  cbsstar_printf("(C:gua)");
236
#endif
237
 
238
  if (*freebandwidth >= lev->U) {
239
    *freebandwidth -= lev->U;
240
    return 1;
241
  }
242
  else
243
    return 0;
244
}
245
 
1123 pj 246
static int CBSSTAR_private_eligible(LEVEL l, PID p)
1089 pj 247
{
248
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
249
  struct budget_struct *b = &lev->b[lev->tb[p]];
250
  JOB_TASK_MODEL job;
251
 
252
#ifdef CBSSTAR_DEBUG
253
  cbsstar_printf("(C:eli %d",p);
254
#endif
255
 
256
  /* we have to check if the deadline and the wcet are correct...
257
     if the CBSSTAR level schedules in background with respect to others
258
     levels, there can be the case in witch a task is scheduled by
259
     schedule_time > CBSSTAR_deadline; in this case (not covered in the
260
     article because if there is only the standard scheduling policy
261
     this never apply) we reassign the deadline */
262
 
1176 trimarchi 263
  if (  TIMESPEC_A_LT_B(&b->dline, &schedule_time) ) {
1089 pj 264
    /* we kill the current activation */
265
    level_table[ lev->scheduling_level ]->
1123 pj 266
      private_extract(lev->scheduling_level, p);
1089 pj 267
 
268
    /* we modify the deadline ... */
269
    TIMESPEC_ASSIGN(&b->dline, &schedule_time);
270
    ADDUSEC2TIMESPEC(b->T, &b->dline);
271
 
272
    /* and the capacity */
273
    b->avail = b->Q;
274
 
275
#ifdef CBSSTAR_DEBUG
276
    cbsstar_printf2(" %ld.%ld av=%d)",b->dline.tv_sec,b->dline.tv_nsec/1000, b->Q);
277
    cbsstar_printf3("±%d±",lev->tb[p]);
278
    cbsstar_printblob(lev->tb[p]);
279
#endif
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 ]->
1123 pj 284
      private_insert(lev->scheduling_level, p, (TASK_MODEL *)&job);
1089 pj 285
 
286
    return -1;
287
  }
288
#ifdef CBSSTAR_DEBUG
289
  cbsstar_printf(")");
290
#endif
291
 
292
  return 0;
293
}
294
 
1176 trimarchi 295
 
1123 pj 296
static void CBSSTAR_private_insert(LEVEL l, PID p, TASK_MODEL *m)
1089 pj 297
{
298
  /* A task has been activated for some reason. Basically, the task is
299
  inserted in the queue if the queue is empty, otherwise the task is
300
  inserted into the master module, and an oslib event is posted. */
301
 
302
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
1123 pj 303
  BUDGET_TASK_MODEL *budget;
1089 pj 304
 
1123 pj 305
  if (m->pclass != BUDGET_PCLASS ||
306
      (m->level != 0 && m->level != l)) {
307
    kern_raise(XINVALID_TASK, p);
308
    return;
309
  }
310
  budget = (BUDGET_TASK_MODEL *)m;
311
 
1089 pj 312
#ifdef CBSSTAR_DEBUG
313
  cbsstar_printf("(C:gcr %d b%d", p, budget->b);
314
#endif
315
 
316
  lev->tb[p] = budget->b;
317
 
318
  if (lev->b[budget->b].current == NIL) {
319
    /* This is the first task in the budget,
320
       the task have to be inserted into the master module */
321
    struct timespec t;
1123 pj 322
    kern_gettime(&t);
1089 pj 323
    CBSSTAR_activation(lev,p,&t);
324
  } else {
325
    /* The budget is not empty, another task is already into the
326
       master module, so the task is inserted at the end of the budget
327
       queue */
1116 pj 328
    iq_insertlast(p,&lev->b[budget->b].tasks);
1089 pj 329
#ifdef CBSSTAR_DEBUG
330
    cbsstar_printf(" ilast");
331
    cbsstar_printq(&lev->b[budget->b].tasks);
332
#endif
333
  }
334
#ifdef CBSSTAR_DEBUG
335
  cbsstar_printf(")");
336
#endif
337
}
338
 
1123 pj 339
static void CBSSTAR_private_extract(LEVEL l, PID p)
1089 pj 340
{
341
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
342
 
343
#ifdef CBSSTAR_DEBUG
344
  cbsstar_printf("(C:gend p%d c%d av=%d)", p, lev->b[lev->tb[p]].current, lev->b[lev->tb[p]].avail);
345
  cbsstar_printq(&lev->b[lev->tb[p]].tasks);
346
#endif
347
 
348
  /* a task is removed from execution for some reasons. It must be
349
     that it is the first in its budget queue (only the first task in
350
     a budget queue is put into execution!) */
351
  CBSSTAR_account_capacity(lev,p);
352
 
353
  /* remove the task from execution (or from the ready queue) */
354
  if (lev->b[lev->tb[p]].current == p) {
355
    /* remove the task from the master module */
356
    level_table[ lev->scheduling_level ]->
1123 pj 357
      private_extract(lev->scheduling_level, p);
1089 pj 358
 
359
#ifdef CBSSTAR_DEBUG
360
    cbsstar_printq(&lev->b[lev->tb[p]].tasks);
361
#endif
362
 
363
    /* check if the buffer has someone else to schedule */
1116 pj 364
    if (iq_query_first(&lev->b[lev->tb[p]].tasks) == NIL) {
1089 pj 365
      /* the buffer has no tasks! */
366
      lev->b[lev->tb[p]].current = NIL;
367
    }
368
    else {
369
      /* if so, insert the new task into the master module */
370
      PID n;
371
      struct timespec t;
372
 
1123 pj 373
      kern_gettime(&t);
1116 pj 374
      n = iq_getfirst(&lev->b[lev->tb[p]].tasks);
1089 pj 375
#ifdef CBSSTAR_DEBUG
376
      cbsstar_printf("{p%d n%d}",p,n);
377
#endif
378
      CBSSTAR_activation(lev,n,&t);  // it modifies b[lev->tb[p]].current
379
    }
380
  }
381
  else
1116 pj 382
    iq_extract(p, &lev->b[lev->tb[p]].tasks);
1089 pj 383
}
384
 
1176 trimarchi 385
static void capacity_handler()
386
{
387
  //kern_printf("!");
388
  event_need_reschedule();
389
 
390
}
391
 
392
 
1123 pj 393
static void CBSSTAR_private_dispatch(LEVEL l, PID p, int nostop)
1089 pj 394
{
395
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
396
  struct timespec ty;
397
 
398
#ifdef CBSSTAR_DEBUG
399
  cbsstar_printf("(C:gdisp p%d c%d av=%d)", p, lev->b[lev->tb[p]].current, lev->b[lev->tb[p]].avail);
400
  cbsstar_printq(&lev->b[lev->tb[p]].tasks);
401
#endif
402
 
403
  /* the current task (that is the only one inserted in the master module
404
     for the corresponding budget) is dispatched. Note that the current
405
     task is not inserted in any FIFO queue, so the task does not have to
406
     be extracted! */
407
 
408
  /* ... then, we dispatch it to the master level */
409
  level_table[ lev->scheduling_level ]->
1123 pj 410
    private_dispatch(lev->scheduling_level,p,nostop);
1089 pj 411
 
412
  /* ...and finally, we have to post a capacity event */
413
  if (!nostop) {
414
    TIMESPEC_ASSIGN(&ty, &schedule_time);
415
    ADDUSEC2TIMESPEC(lev->b[lev->tb[p]].avail,&ty);
1176 trimarchi 416
    lev->cap_lev = kern_event_post(&ty, capacity_handler, NULL);
417
  }
1089 pj 418
}
419
 
1123 pj 420
static void CBSSTAR_private_epilogue(LEVEL l, PID p)
1089 pj 421
{
422
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
423
  struct budget_struct *b = &lev->b[lev->tb[p]];
424
 
1176 trimarchi 425
  #ifdef CBSSTAR_DEBUG
1089 pj 426
  cbsstar_printf("(C:gepi %d",p);
1176 trimarchi 427
  #endif
1089 pj 428
 
429
  CBSSTAR_account_capacity(lev,p);
430
 
1176 trimarchi 431
  if (lev->cap_lev!=NIL)
432
    kern_event_delete(lev->cap_lev);
433
  lev->cap_lev=NIL;
434
 
1089 pj 435
  /* we have to check if the capacity is still available */
436
  if (b->avail > 0) {
437
    /* there is capacity available, maybe it is simply a preemption;
438
       the task have to return to the ready queue */
439
    level_table[ lev->scheduling_level ]->
1123 pj 440
      private_epilogue(lev->scheduling_level,p);
1176 trimarchi 441
    #ifdef CBSSTAR_DEBUG
442
    cbsstar_printf(" *av=%d", b->avail);
443
    #endif
1089 pj 444
  } else {
1176 trimarchi 445
 
1089 pj 446
    /* The capacity is exausted; the deadline have to be postponed and
447
       the task have to be reinserted in the master module */
448
    JOB_TASK_MODEL job;
449
 
450
    /* we kill the current activation */
451
    level_table[ lev->scheduling_level ]->
1123 pj 452
      private_extract(lev->scheduling_level, p);
1089 pj 453
 
454
    /* we modify the deadline according to rule 4 ... */
455
    /* there is a while because if the wcet is << than the system tick
456
       we need to postpone the deadline many times */
457
    while (b->avail <= 0) {
458
      ADDUSEC2TIMESPEC(b->T, &b->dline);
459
      b->avail += b->Q;
1176 trimarchi 460
      #ifdef CBSSTAR_DEBUG
461
      cbsstar_printf("±%d±",b->avail);
462
      #endif
1089 pj 463
    }
464
 
1176 trimarchi 465
    #ifdef CBSSTAR_DEBUG
466
    kern_printf(" %ld.%ld av=%d",b->dline.tv_sec,b->dline.tv_nsec/1000, b->avail);
467
    #endif
1089 pj 468
 
469
    /* and, finally, we reinsert the task in the master level */
470
    job_task_default_model(job, b->dline);
471
    job_task_def_noexc(job);
472
    level_table[ lev->scheduling_level ]->
1123 pj 473
      private_insert(lev->scheduling_level, p, (TASK_MODEL *)&job);
1089 pj 474
  }
475
#ifdef CBSSTAR_DEBUG
476
  cbsstar_printf(")");
477
#endif
1176 trimarchi 478
 
1089 pj 479
}
480
 
481
 
482
/* Registration functions */
483
 
484
/*+ Registration function:
485
    int flags                 the init flags ... see CBSSTAR.h +*/
486
LEVEL CBSSTAR_register_level(int n, LEVEL master)
487
{
488
  LEVEL l;            /* the level that we register */
489
  CBSSTAR_level_des *lev;  /* for readableness only */
490
  PID i;              /* a counter */
491
 
492
#ifdef CBSSTAR_DEBUG
493
  cbsstar_printf("CBSSTAR_register_level\n");
494
#endif
495
 
496
  /* request an entry in the level_table */
1123 pj 497
  l = level_alloc_descriptor(sizeof(CBSSTAR_level_des));
1089 pj 498
 
1123 pj 499
  lev = (CBSSTAR_level_des *)level_table[l];
1089 pj 500
 
1123 pj 501
  printk("    lev=%d\n",(int)lev);
1089 pj 502
 
503
  /* fill the standard descriptor */
1123 pj 504
  lev->l.private_insert   = CBSSTAR_private_insert;
505
  lev->l.private_extract  = CBSSTAR_private_extract;
506
  lev->l.private_eligible = CBSSTAR_private_eligible;
507
  lev->l.private_dispatch = CBSSTAR_private_dispatch;
508
  lev->l.private_epilogue = CBSSTAR_private_epilogue;
1089 pj 509
 
1123 pj 510
  lev->l.public_guarantee = CBSSTAR_public_guarantee;
1089 pj 511
 
512
  /* fill the CBSSTAR descriptor part */
513
  lev->b = (struct budget_struct *)kern_alloc(sizeof(struct budget_struct)*n);
514
 
515
  for (i=0; i<n; i++) {
516
    lev->b[i].Q = 0;
517
    lev->b[i].T = 0;
518
    NULL_TIMESPEC(&lev->b[i].dline);
519
    lev->b[i].dline_timer = 0;
520
    lev->b[i].avail = 0;
521
    lev->b[i].current = -1;
1116 pj 522
    iq_init(&lev->b[i].tasks, &freedesc, 0);
1089 pj 523
  }
524
 
525
  lev->n = n;
526
  lev->freebudgets = 0;
527
  for (i=0; i<MAX_PROC; i++)
528
    lev->tb[i] = NIL;
529
 
530
  lev->U = 0;
1176 trimarchi 531
  lev->cap_lev=NIL;
1089 pj 532
  lev->scheduling_level = master;
533
 
534
  return l;
535
}
536
 
537
int CBSSTAR_setbudget(LEVEL l, TIME Q, TIME T)
538
{
539
  CBSSTAR_level_des *lev = (CBSSTAR_level_des *)(level_table[l]);
540
 
541
#ifdef CBSSTAR_DEBUG
542
  cbsstar_printf("(C:sbud)");
543
#endif
544
 
1123 pj 545
  if (lev->freebudgets != lev->n) {
546
    bandwidth_t b;
547
    b = (MAX_BANDWIDTH / T) * Q;
548
 
549
    /* really update lev->U, checking an overflow... */
550
    if (Q< T && MAX_BANDWIDTH - lev->U > b) {
551
      int r = lev->freebudgets;  // the return value
1089 pj 552
 
1123 pj 553
      lev->U += b;
554
      lev->freebudgets++;
555
 
556
      lev->b[r].Q = Q;
557
      lev->b[r].T = T;
558
 
559
      return r;
1089 pj 560
    }
561
    else
1123 pj 562
      return -2;
1089 pj 563
  }
564
  else
1123 pj 565
    return -1;
1089 pj 566
}