Subversion Repositories shark

Rev

Rev 38 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 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
 ------------
353 giacomo 23
 CVS :        $Id: ss.c,v 1.5 2003-12-10 16:55:01 giacomo Exp $
2 pj 24
 
25
 File:        $File$
353 giacomo 26
 Revision:    $Revision: 1.5 $
27
 Last update: $Date: 2003-12-10 16:55:01 $
2 pj 28
 ------------
29
 
30
 This file contains the aperiodic Sporadic Server (SS).
31
 
32
 Note: in the following, server capacity and server budget are used as
33
       synonyms.
34
 
35
 When scheduling in background  the flags field has the SS_BACKGROUND bit set
36
 
37
 When scheduling a task because it is pointed by another task via shadows,
38
 the task have to be extracted from the wait queue or the master level. To
39
 check this we have to look at the activated field; it is != NIL if a task
40
 is inserted into the master level. Only a task at a time can be inserted
41
 into the master level.
42
 
43
 The capacity of the server must be updated
44
 - when scheduling a task normally
45
 - when scheduling a task because it is pointed by a shadow
46
   but not when scheduling in background.
47
 
48
 When a task is extracted from the system no scheduling has to be done
49
 until the task reenter into the system. To implement this, when a task
50
 is extracted we block the background scheduling (the scheduling with the
51
 master level is already blocked because the activated field is not
52
 reset to NIL) using the SS_BACKGROUNDBLOCK bit.
53
 
54
 nact[p] is -1 if the task set the activations to SKIP, >= 0 otherwise
55
 
56
 In contrast to classic SS scheme, the activation happens when
57
 a task does a create request while there is positive budget (instead to
58
 becomes active when there is a running task with priority higger then or
59
 equal to the server).
60
 So the replenish time is estabished on task arrival time. Replenish time
61
 is calculated as usual: activation time + server period.
62
 When the server ends its budget, becomes not active until a replenishment
63
 occurs.
64
 
65
 When a task ends its computation and there are no tasks to schedule or,
66
 again, the server budget ends, a replenish amount is posted so that, when
67
 replenish time fires, the server budget will be updated. Replenish
68
 amount is determined depending on how much time tasks have ran.
69
 Replenish amount does't takes into account periods during witch tasks
70
 handled by SS are preempted.
71
 
72
 There are two models used to handle a task is running into a critic section
73
 (owning a mutex): "nostop" model and "stop" model.
74
 Using the "nostop" model, a task that runs into a critic section is not
75
 stopped when server ends its budget. This is done so higger priority tasks
76
 waiting for mutex are not blocked for so much time to replenish time occurs.
77
 When this happens the server capacity becomes negative and the replenish
78
 amount takes into account the negative budget part.
79
 With "stop" model running task is always suspended when server budget ends.
80
 If suspended task owns a mutex shared with higger priority task, the last
81
 one cannot runs until the mutex will be released. Higger priority task
82
 must waits at least upto next replenish time, when server budget will be
83
 refulled and suspended task runs again.
84
 
85
 Using "nostop" model, SS can uses more bandwidth respect to assigned
86
 capacity (due to negative budgets). So, calculating the guarantee, the
87
 longer critic section of all tasks handled by SS must be considered.
88
 
89
 SS can be used either with EDF or RM master level.
90
 
91
 Read SS.h for further details.
92
 
93
**/
94
 
95
/*
96
 * Copyright (C) 2000 Paolo Gai
97
 *
98
 * This program is free software; you can redistribute it and/or modify
99
 * it under the terms of the GNU General Public License as published by
100
 * the Free Software Foundation; either version 2 of the License, or
101
 * (at your option) any later version.
102
 *
103
 * This program is distributed in the hope that it will be useful,
104
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
105
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
106
 * GNU General Public License for more details.
107
 *
108
 * You should have received a copy of the GNU General Public License
109
 * along with this program; if not, write to the Free Software
110
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
111
 *
112
 */
113
 
114
 
115
#include <stdlib.h>
116
#include <modules/ss.h>
117
#include <ll/stdio.h>
118
#include <ll/string.h>
119
 
120
#include <ll/sys/ll/event.h>
121
 
122
#include <kernel/const.h>
123
#include <kernel/model.h>
124
#include <kernel/model.h>
125
#include <kernel/descr.h>
126
#include <kernel/var.h>
127
#include <kernel/func.h>
128
 
353 giacomo 129
#include <tracer.h>
130
 
2 pj 131
/* For debugging purpose */
132
//#define DEBUG 1
133
 
134
/*+ Status used in the level +*/
135
#define SS_WAIT          APER_STATUS_BASE    /*+ waiting the service   +*/
136
 
137
/*+ Some useful macros +*/
138
#define BACKGROUND_ON  (lev->flags & SS_BACKGROUND)
139
 
140
extern struct event *firstevent;
141
 
142
/*+ the level redefinition for the Sporadic Server +*/
143
typedef struct {
144
  level_des l;     /*+ the standard level descriptor          +*/
145
 
146
  /* The wcet are stored in the task descriptor's priority
147
     field, so no other fields are needed                      */
148
 
149
  int nact[MAX_PROC]; /*+ number of pending activations       +*/
150
 
151
  struct timespec lastdline; /*+ the last deeadline assigned to
152
                                 a SS task                    +*/
153
 
154
  int Cs;          /*+ server capacity                        +*/
155
  int availCs;     /*+ server avail time                      +*/
156
  int period;      /*+ Server period +*/
157
 
158
  bandwidth_t U;   /*+ the used bandwidth by the server       +*/
159
 
29 pj 160
  IQUEUE wait;     /*+ the wait queue of the SS               +*/
2 pj 161
  PID activated;   /*+ the task inserted in another queue     +*/
162
 
163
  int flags;       /*+ the init flags...                      +*/
164
 
165
 
166
  LEVEL scheduling_level;
167
 
168
  int replenishment[SS_MAX_REPLENISH]; /*+ contains replenish amounts +*/
169
  int rfirst,rlast;                    /*+ first and last valid replenish
170
                                            in replenish queue +*/
171
  int rcount;                           /*+ queued replenishments +*/
172
 
173
  int replenish_amount;            /*+ partial replenishments before post +*/
174
  ss_status server_active;         /*+ Is server active? +*/
175
 
176
} SS_level_des;
177
 
178
/*+ function prototypes +*/
38 pj 179
void SS_internal_status(LEVEL l);
2 pj 180
static void SS_replenish_timer(void *arg);
181
/*-------------------------------------------------------------------*/
182
 
183
/*** Utility functions ***/
184
 
185
 
186
/* These are for dinamic queue. **Disabled** */
187
#if 0
188
/* These routines are not tested, be carefull */
189
 
190
/*+ SS local memory allocator.
191
    Can be used for performance optimization.
192
    The interface is the same of kern_alloc() +*/
193
void inline * ss_alloc(DWORD b) {
194
        /* Now simply wraps to standard kernel alloc */
195
        return kern_alloc(b);
196
}
197
 
198
void ssq_inslast(LEVEL l, replenishq *elem) {
199
 
200
        SS_level_des *lev = (SS_level_des *) level_table[l];
201
 
202
        if(lev->rqueue_last == NULL) { /* empty queue */
203
                lev->rqueue_last=elem;
204
                lev->rqueue_first=elem;
205
                return;
206
        }
207
        elem->next = NULL;
208
        lev->rqueue_last->next = elem;
209
        lev->rqueue_last = elem;
210
}
211
 
212
replenishq *ssq_getfirst(LEVEL l) {
213
 
214
        SS_level_des *lev = (SS_level_des *) level_table[l];
215
        replenishq *tmp;
216
 
217
        if(lev->rqueue_first == NULL) { /* empty queue */
218
                return 0;
219
        }
220
        tmp = lev->rqueue_first;
221
        lev->rqueue_first = tmp->next;
222
        if(lev->rqueue_first == NULL) { /* no more elements */
223
                lev->rqueue_last = NULL;
224
        }
225
        tmp->next = NULL;       /* to remove dangling pointer */
226
        return tmp;
227
}
228
#endif
229
 
230
/* For queue implemented with array.
231
   SS_MAX_REPLENISH array size assumed */
232
 
233
/*+ Insert an element at tail of replenish queue
234
        LEVEL l                 module level
235
        int   amount            element to insert
236
 
237
        RETURNS:
238
 
239
          NIL   no more space for insertion +*/
240
static inline int ssq_inslast (LEVEL l, int amount) {
241
 
242
  SS_level_des *lev = (SS_level_des *)(level_table[l]);
243
 
244
  #ifdef DEBUG
245
  kern_printf("insl ");
246
  #endif
247
 
248
  if (lev->rcount == SS_MAX_REPLENISH) {
249
    return NIL; /* no more space in the queue */
250
  }
251
 
252
  lev->replenishment[lev->rlast++] = amount;
253
  lev->rlast %= SS_MAX_REPLENISH;
254
  lev->rcount++;
255
  #ifdef DEBUG
256
  printf_xy(0,0,WHITE,"%d",lev->rcount);
257
  #endif
258
 
259
  return 0;
260
}
261
 
262
/*+ Get first element from replenish queue
263
        LEVEL l         module level
264
 
265
        RETURS:
266
          extracted element
267
          NIL on empty queue +*/
268
static inline int ssq_getfirst (LEVEL l) {
269
 
270
  SS_level_des *lev = (SS_level_des *)(level_table[l]);
271
  int tmp;
272
 
273
  #ifdef DEBUG
274
  kern_printf("getf ");
275
  #endif
276
 
277
  if (lev->rcount == 0) {
278
    return NIL; /* empty queue */
279
  }
280
  tmp = lev->replenishment[lev->rfirst++];
281
  lev->rfirst %= SS_MAX_REPLENISH;
282
  lev->rcount--;
283
  #ifdef DEBUG
284
  printf_xy(0,0,WHITE,"%d",lev->rcount);
285
  #endif
286
  return tmp;
287
}
288
 
289
/*+ Enquire for empty queue
290
        LEVEL l         module level
291
 
292
        RETURS:
293
 
294
          1     queue is empty +*/
295
static inline int ssq_isempty (LEVEL l) {
296
 
297
  SS_level_des *lev = (SS_level_des *)(level_table[l]);
298
 
299
  return !(lev->rcount);
300
 
301
//  if(lev->rcount == 0)
302
//    return 1;
303
//  return 0;
304
}
305
 
306
/*+ Set replenish amount for budget used during task execution
307
        LEVEL l         module level */
308
static inline void SS_set_ra(LEVEL l)
309
{
310
  SS_level_des *lev = (SS_level_des *)(level_table[l]);
311
 
312
  /* replenish must be set when the server is still active */
313
  if(lev->server_active == SS_SERVER_ACTIVE) {
314
    lev->server_active = SS_SERVER_NOTACTIVE;
315
    if(ssq_inslast(l, lev->replenish_amount) == NIL) {
316
      kern_printf("SS: no more space to post replenishment\n");
317
      kern_printf("You should recompile setting higher SS_MAX_REPLENISH into include/modules/ss.h\n");
38 pj 318
      SS_internal_status(l);
14 pj 319
      kern_raise(XINVALID_SS_REPLENISH,exec_shadow);
2 pj 320
      #ifdef DEBUG
321
      sys_abort(-1);
322
      exit(-1);
323
      #endif
324
    }
325
    lev->replenish_amount = 0;
326
  }
327
  else {
328
    kern_printf("SS not active when posting R.A.\n");
38 pj 329
    SS_internal_status(l);
14 pj 330
    kern_raise(XINVALID_SS_REPLENISH,exec_shadow);
2 pj 331
    #ifdef DEBUG
332
    sys_abort(-1);
333
    exit(-1);
334
    #endif
335
  }
336
}
337
/* ------------------------------------------------------------------ */
338
 
339
/* This static function activates the task pointed by lev->activated) */
340
static inline void SS_activation(SS_level_des *lev)
341
{
342
    /* those two defines are for readableness */
343
    PID   p;
344
    LEVEL m;
345
 
346
    JOB_TASK_MODEL j;          /* the guest model */
347
//    struct timespec ty;
348
 
349
    #ifdef DEBUG
350
    kern_printf("SS_acti ");
351
    #endif
352
 
353
    p = lev->activated;
354
    m = lev->scheduling_level;
355
 
356
#if 0
357
    /* if server is active, replenish time already set */
358
    if (lev->server_active == SS_SERVER_NOTACTIVE) {
359
       lev->server_active = SS_SERVER_ACTIVE;
360
       /* set replenish time */
361
       TIMESPEC_ASSIGN(&ty, &proc_table[p].request_time);
362
       ADDUSEC2TIMESPEC(lev->period, &ty);
363
       TIMESPEC_ASSIGN(&lev->lastdline, &ty);
364
       #ifdef DEBUG
365
       kern_printf("RT:%d.%d ",ty.tv_sec,ty.tv_nsec);
366
       #endif
367
       kern_event_post(&ty, SS_replenish_timer, (void *) l);
368
    }
369
#endif
370
 
371
    job_task_default_model(j,lev->lastdline);
372
    job_task_def_period(j,lev->period);
38 pj 373
    level_table[m]->private_insert(m,p,(TASK_MODEL *)&j);
2 pj 374
 
375
    #ifdef DEBUG
376
    kern_printf("PID:%p lastdl:%d.%d ",p,lev->lastdline.tv_sec,lev->lastdline.tv_nsec);
377
    #endif
378
}
379
 
380
/*+
381
    Before call capacity_timer, update server capacity
382
    and replenish amount.
383
+*/
384
static void SS_capacity_timer(void *arg) {
385
 
386
        LEVEL l = (LEVEL)arg;
387
        SS_level_des *lev = (SS_level_des *)(level_table[l]);
388
        struct timespec ty;
389
        int tx;
390
 
391
        #ifdef DEBUG
392
        kern_printf("SS_captim ");
393
        #endif
394
 
395
        /* set replenish amount */
396
        /* task was running while budget ends */
397
        lev->server_active = SS_SERVER_NOTACTIVE;
398
        SUBTIMESPEC(&schedule_time, &cap_lasttime, &ty);
399
        tx = TIMESPEC2USEC(&ty);
400
        lev->availCs -= tx;
401
        if(ssq_inslast(l, tx+lev->replenish_amount) == NIL) {
402
           kern_printf("SS: no more space to post replenishment\n");
403
           kern_printf("    You should recompile setting higher SS_MAX_REPLENISH into include/modules/ss.h\n");
38 pj 404
           SS_internal_status(l);
14 pj 405
           kern_raise(XINVALID_SS_REPLENISH,exec_shadow);
2 pj 406
           #ifdef DEBUG
407
           sys_abort(-1);
408
           exit(-1);
409
           #endif
410
        }
411
        lev->replenish_amount = 0;
412
        capacity_timer(NULL);
413
}
414
 
415
static void SS_replenish_timer(void *arg)
416
{
417
  LEVEL l = (LEVEL)arg;
418
  SS_level_des *lev = (SS_level_des *)(level_table[l]);
419
  struct timespec ty;
420
  int amount;
421
 
422
    #ifdef DEBUG
423
    kern_printf("SS_reptim ");
424
    #endif
425
 
426
  /* availCs may be <0 because a task executed via a shadow for many time
427
     lev->activated == NIL only if the prec task was finished and there
428
     was not any other task to be put in the ready queue
429
     ... we are now activating the next task */
430
  if ((amount = ssq_getfirst(l)) != NIL) {
431
    lev->availCs += amount;
432
    #ifdef DEBUG
433
    kern_printf("AvaCs=%d ",lev->availCs);
434
    #endif
435
    if (lev->availCs > lev->Cs) {
436
      /* This should not be possible. I do so for robustness. */
437
      lev->availCs = lev->Cs;
438
      #ifdef DEBUG
439
      kern_printf("SS warning: budget higher then server capacity. Set to Cs.");
440
      #endif
441
    }
442
    if (lev->availCs <= 0) {
443
      /* we can be here if nostop model is used */
444
      #ifdef DEBUG
445
      kern_printf("WARNING: SS has non positive capacity after replenish.");
446
      #endif
447
      /* if there isn't pending replenishment and server
448
         is not active we must refull somehow.
449
         Otherwise SS remains not active forever */
450
      if(ssq_isempty(l) && lev->server_active == SS_SERVER_NOTACTIVE) {
451
        lev->availCs = lev->Cs;
452
        kern_printf("SS was full replenished due to irreversible non positive budget!!!\n");
453
        kern_printf("You should review your time extimation for critical sections ;)\n");
454
      }
455
    }
456
  }
457
  else {
458
    /* replenish queue is empty */
459
    kern_printf("Replenish Timer fires but no Replenish Amount defined\n");
38 pj 460
    SS_internal_status(l);
14 pj 461
    kern_raise(XINVALID_SS_REPLENISH,exec_shadow);
2 pj 462
    #ifdef DEBUG
463
    sys_abort(-1);
464
    exit(-1);
465
    #endif
466
  }
467
 
468
  if (lev->availCs > 0 && lev->activated == NIL) {
29 pj 469
    if (iq_query_first(&lev->wait) != NIL) {
470
      lev->activated = iq_getfirst(&lev->wait);
2 pj 471
      /* if server is active, replenish time already set */
472
      if (lev->server_active == SS_SERVER_NOTACTIVE) {
473
         lev->server_active = SS_SERVER_ACTIVE;
474
         /* set replenish time */
38 pj 475
         kern_gettime(&ty);
2 pj 476
         ADDUSEC2TIMESPEC(lev->period, &ty);
477
         TIMESPEC_ASSIGN(&lev->lastdline, &ty);
478
         #ifdef DEBUG
479
         kern_printf("RT:%d.%d ",ty.tv_sec,ty.tv_nsec);
480
         #endif
481
         kern_event_post(&ty, SS_replenish_timer, (void *) l);
482
      }
483
      SS_activation(lev);
484
      event_need_reschedule();
485
    }
486
  }
487
}
488
 
489
static char *SS_status_to_a(WORD status)
490
{
491
  if (status < MODULE_STATUS_BASE)
38 pj 492
    return "Unavailable"; //status_to_a(status);
2 pj 493
 
494
  switch (status) {
495
    case SS_WAIT         : return "SS_Wait";
496
    default              : return "SS_Unknown";
497
  }
498
}
499
 
500
 
501
/*-------------------------------------------------------------------*/
502
 
503
/*** Level functions ***/
504
 
38 pj 505
void SS_internal_status(LEVEL l)
2 pj 506
{
507
  SS_level_des *lev = (SS_level_des *)(level_table[l]);
29 pj 508
  PID p = iq_query_first(&lev->wait);
2 pj 509
 
510
  kern_printf("On-line guarantee : %s\n",
511
    (lev->flags & SS_ENABLE_GUARANTEE_EDF ||
512
     lev->flags & SS_ENABLE_GUARANTEE_RM  )?"On":"Off");
513
 
514
  kern_printf("Used Bandwidth    : %u/%u\n",lev->U,MAX_BANDWIDTH);
515
  kern_printf("Period            : %d\n",lev->period);
516
  kern_printf("Capacity          : %d\n",lev->Cs);
517
  kern_printf("Avail capacity    : %d\n",lev->availCs);
518
  kern_printf("Server is %sactive\n",
519
     (lev->server_active == SS_SERVER_NOTACTIVE ? "not ":""));
520
  kern_printf("Pending RAs       : %d\n",lev->rcount);
521
 
522
  if (lev->activated != NIL)
523
    kern_printf("Activated: Pid: %d Name: %10s Dl: %ld.%ld Nact: %d Stat: %s\n",
524
                lev->activated,
525
                proc_table[lev->activated].name,
29 pj 526
                iq_query_timespec(lev->activated,&lev->wait)->tv_sec,
527
                iq_query_timespec(lev->activated,&lev->wait)->tv_nsec,
2 pj 528
                lev->nact[lev->activated],
529
                SS_status_to_a(proc_table[lev->activated].status));
530
 
531
  while (p != NIL) {
532
    kern_printf("Pid: %d\tName: %10s\tStatus: %s\n",
533
                p,
534
                proc_table[p].name,
535
                SS_status_to_a(proc_table[p].status));
29 pj 536
    p = iq_query_next(p, &lev->wait);
2 pj 537
  }
538
}
539
 
38 pj 540
static PID SS_public_schedulerbackground(LEVEL l)
2 pj 541
{
542
  /* the SS catch the background time to exec aperiodic activities */
543
  SS_level_des *lev = (SS_level_des *)(level_table[l]);
544
 
545
  #ifdef DEBUG
546
  kern_printf("SS_levschbg ");
547
  #endif
548
 
549
  lev->flags |= SS_BACKGROUND;
550
 
551
  if (lev->flags & SS_BACKGROUND_BLOCK)
552
    return NIL;
553
  else
29 pj 554
    return iq_query_first(&lev->wait);
2 pj 555
}
556
 
557
/* The on-line guarantee is enabled only if the appropriate flag is set... */
38 pj 558
static int SS_public_guaranteeEDF(LEVEL l, bandwidth_t *freebandwidth)
2 pj 559
{
560
  SS_level_des *lev = (SS_level_des *)(level_table[l]);
561
 
562
  #ifdef DEBUG
563
  kern_printf("SS_levguarEDF ");
564
  #endif
565
 
566
  if (*freebandwidth >= lev->U) {
567
    *freebandwidth -= lev->U;
568
    return 1;
569
  }
570
  else
571
    return 0;
572
}
573
 
38 pj 574
static int SS_public_guaranteeRM(LEVEL l, bandwidth_t *freebandwidth)
2 pj 575
{
576
  SS_level_des *lev = (SS_level_des *)(level_table[l]);
577
 
578
  #ifdef DEBUG
579
  kern_printf("SS_levguarRM ");
580
  #endif
581
 
582
  if (*freebandwidth > lev->U + RM_MINFREEBANDWIDTH) {
583
    *freebandwidth -= lev->U;
584
    return 1;
585
  }
586
  else
587
    return 0;
588
}
589
 
590
/*-------------------------------------------------------------------*/
591
 
592
/***  Task functions  ***/
593
 
594
 
38 pj 595
static int SS_public_create(LEVEL l, PID p, TASK_MODEL *m)
2 pj 596
{
597
  SS_level_des *lev = (SS_level_des *)(level_table[l]);
38 pj 598
  SOFT_TASK_MODEL *s;
2 pj 599
 
600
  #ifdef DEBUG
601
  kern_printf("SS_taskcre ");
602
  #endif
603
 
38 pj 604
  if (m->pclass != SOFT_PCLASS) return -1;
605
  if (m->level != 0 && m->level != l) return -1;
606
  s = (SOFT_TASK_MODEL *)m;
607
  if (s->periodicity != APERIODIC) return -1;
608
 
609
  s = (SOFT_TASK_MODEL *)m;
610
 
2 pj 611
  if (s->arrivals == SAVE_ARRIVALS)
612
    lev->nact[p] = 0;
613
  else
614
    lev->nact[p] = -1;
615
 
616
  return 0; /* OK, also if the task cannot be guaranteed */
617
}
618
 
38 pj 619
static void SS_public_dispatch(LEVEL l, PID p, int nostop)
2 pj 620
{
621
  SS_level_des *lev = (SS_level_des *)(level_table[l]);
622
  struct timespec ty;
623
 
624
  #ifdef DEBUG
625
  kern_printf("SS_tdi ");
626
  #endif
627
 
628
  TIMESPEC_ASSIGN(&ty, &schedule_time);
629
  /* set replenish time */
630
  if(!BACKGROUND_ON) {
631
     if(lev->server_active == SS_SERVER_NOTACTIVE) {
632
        lev->server_active = SS_SERVER_ACTIVE;
633
        ADDUSEC2TIMESPEC(lev->period,&ty);
634
        TIMESPEC_ASSIGN(&lev->lastdline, &ty);
635
        #ifdef DEBUG
636
        kern_printf("tdiPID:%d RT:%d.%d ",p,ty.tv_sec,ty.tv_nsec);
637
        #endif
638
        kern_event_post(&ty, SS_replenish_timer,(void *) l);
639
     }
640
  }
641
 
642
  #ifdef DEBUG
643
  if (nostop) kern_printf("NOSTOP!!! ");
644
  #endif
645
 
646
  /* there is at least one task ready inserted in an RM or similar level.
647
     Note that we can't check the status because the scheduler sets it
648
     to exe before calling task_dispatch.
649
     We have to check lev->activated != p instead */
650
  if (lev->activated != p) {
29 pj 651
    iq_extract(p, &lev->wait);
2 pj 652
    #ifdef DEBUG
653
    kern_printf("extr task:%d ",p);
654
    #endif
655
  }
656
  else {
657
    #ifdef DEBUG
658
    if (nostop) kern_printf("(gd status=%d)",proc_table[p].status);
659
    #endif
660
    level_table[lev->scheduling_level]->
38 pj 661
       private_dispatch(lev->scheduling_level,p,nostop);
2 pj 662
  }
663
 
664
  /* set capacity timer */
665
  if (!nostop && !BACKGROUND_ON) {
666
    TIMESPEC_ASSIGN(&ty, &schedule_time);
667
//    kern_printf("ty:%d.%d ",ty.tv_sec,ty.tv_nsec);
668
    ADDUSEC2TIMESPEC((lev->availCs<=0 ? 0:lev->availCs),&ty);
669
//    kern_printf("avCs:%d ty:%d.%d ",lev->availCs,ty.tv_sec,ty.tv_nsec);
670
    /* stop the task if budget ends */
671
    #ifdef DEBUG
672
    kern_printf("PID:%d ST=%d.%d  ",p,ty.tv_sec,ty.tv_nsec);
673
    #endif
674
    cap_timer = kern_event_post(&ty, SS_capacity_timer,(void *) l);
675
  }
676
}
677
 
38 pj 678
static void SS_public_epilogue(LEVEL l, PID p) {
2 pj 679
 
680
  SS_level_des *lev = (SS_level_des *)(level_table[l]);
681
  struct timespec ty;
682
  int tx;
683
 
684
  #ifdef DEBUG
685
  kern_printf("SS_tep ");
686
  #endif
687
 
688
  /* update the server capacity */
689
  if (BACKGROUND_ON)
690
    lev->flags &= ~SS_BACKGROUND;
691
  else {
692
    SUBTIMESPEC(&schedule_time, &cap_lasttime, &ty);
693
//    kern_printf("ty:%d.%d ",ty.tv_sec,ty.tv_nsec);
694
    tx = TIMESPEC2USEC(&ty);
695
    lev->availCs -= tx;
696
//    kern_printf("avCs:%d ty:%d.%d ",lev->availCs,ty.tv_sec,ty.tv_nsec);
697
    lev->replenish_amount += tx;
698
    #ifdef DEBUG
699
    kern_printf("RA:%d ",lev->replenish_amount);
700
    #endif
701
  }
702
 
703
  /* check if the server capacity is finished... */
704
  if (lev->availCs <= 0) {
705
    /* The server slice has finished... do the task_end!!!
706
       A first version of the module used the task_endcycle, but it was
707
       not conceptually correct because the task didn't stop because it
708
       finished all the work, but because the server didn't have budget!
709
       So, if the task_endcycle is called, the task remain into the
710
       master level, and we can't wake him up if, for example, another
711
       task point the shadow to it!!! */
712
 
713
    /* set replenish amount */
714
    if(!(BACKGROUND_ON)) {
715
      if(lev->server_active == SS_SERVER_ACTIVE) {
716
        lev->server_active = SS_SERVER_NOTACTIVE;
717
        if(ssq_inslast(l, lev->replenish_amount) == NIL) {
718
          kern_printf("SS: no more space to post replenishment\n");
719
          kern_printf("You should recompile setting higher SS_MAX_REPLENISH into include/modules/ss.h\n");
38 pj 720
          SS_internal_status(l);
14 pj 721
          kern_raise(XINVALID_SS_REPLENISH,exec_shadow);
2 pj 722
          #ifdef DEBUG
723
          sys_abort(-1);
724
          exit(-1);
725
          #endif
726
        }
727
        lev->replenish_amount = 0;
728
      }
729
    }
730
 
731
    if (lev->activated == p)
38 pj 732
      level_table[lev->scheduling_level]->private_extract(lev->scheduling_level,p);
2 pj 733
 
29 pj 734
    iq_insertfirst(p, &lev->wait);
2 pj 735
    proc_table[p].status = SS_WAIT;
736
    lev->activated = NIL;
737
  }
738
  else {
739
    /* The task has been preempted.
740
       It returns into the ready queue or to the
38 pj 741
       wait queue by calling the private_epilogue... */
2 pj 742
 
743
    if (lev->activated == p) {  /* goes into ready queue */
744
      level_table[ lev->scheduling_level ]->
38 pj 745
        private_epilogue(lev->scheduling_level,p);
2 pj 746
    }
747
    else {                      /* goes into wait queue */
29 pj 748
      iq_insertfirst(p, &lev->wait);
2 pj 749
      proc_table[p].status = SS_WAIT;
750
    }
751
  }
752
}
753
 
38 pj 754
static void SS_public_activate(LEVEL l, PID p)
2 pj 755
{
756
        SS_level_des *lev = (SS_level_des *)(level_table[l]);
757
        struct timespec ty;
758
 
759
        #ifdef DEBUG
760
        kern_printf("SS_tacti ");
761
        #endif
762
 
763
        if (lev->activated == p || proc_table[p].status == SS_WAIT) {
764
                if (lev->nact[p] != -1) lev->nact[p]++;
765
        }
766
        else if (proc_table[p].status == SLEEP) {
767
                if (lev->activated == NIL && lev->availCs > 0) {
768
                  if(!BACKGROUND_ON) {
769
                    /* if server is active, replenish time already set */
770
                    if (lev->server_active == SS_SERVER_NOTACTIVE) {
771
                      lev->server_active = SS_SERVER_ACTIVE;
772
                      /* set replenish time */
38 pj 773
                      kern_gettime(&ty);
2 pj 774
                      ADDUSEC2TIMESPEC(lev->period, &ty);
775
                      TIMESPEC_ASSIGN(&lev->lastdline, &ty);
776
                      #ifdef DEBUG
777
                      kern_printf("RT=%d.%d ",ty.tv_sec,ty.tv_nsec);
778
                      #endif
779
                      kern_event_post(&ty, SS_replenish_timer, (void *) l);
780
                    }
781
                  }
782
                  lev->activated = p;
783
                  SS_activation(lev);
784
                }
785
                else {
29 pj 786
                        iq_insertlast(p, &lev->wait);
2 pj 787
                        proc_table[p].status = SS_WAIT;
788
                }
789
        }
790
        else {
791
                kern_printf("SS_REJ%d %d %d %d ",
792
                            p,
793
                            proc_table[p].status,
794
                            lev->activated,
795
                            lev->wait.first);
796
                return;
797
        }
798
}
799
 
38 pj 800
static void SS_public_unblock(LEVEL l, PID p)
2 pj 801
{
802
  SS_level_des *lev = (SS_level_des *)(level_table[l]);
803
 
804
  #ifdef DEBUG
805
  kern_printf("SS_tins ");
806
  #endif
807
  lev->flags &= ~SS_BACKGROUND_BLOCK;
808
 
809
  lev->activated = NIL;
810
 
811
  /* when we reinsert the task into the system, the server capacity
812
     is always 0 because nobody executes with the SS before... */
29 pj 813
  iq_insertfirst(p, &lev->wait);
2 pj 814
  proc_table[p].status = SS_WAIT;
815
}
816
 
38 pj 817
static void SS_public_block(LEVEL l, PID p)
2 pj 818
{
819
  SS_level_des *lev = (SS_level_des *)(level_table[l]);
820
 
821
  #ifdef DEBUG
822
  kern_printf("SS_textr ");
823
  #endif
824
 
825
  /* set replenish amount */
826
  if(!(BACKGROUND_ON)) {
827
    SS_set_ra(l);
828
  }  
829
 
830
  /* clear the server capacity */
831
  lev->availCs = 0;
832
 
833
  lev->flags |= SS_BACKGROUND_BLOCK;
834
 
835
  if (lev->activated == p)
38 pj 836
    level_table[lev->scheduling_level]->private_extract(lev->scheduling_level,p);
2 pj 837
}
838
 
38 pj 839
static int SS_public_message(LEVEL l, PID p, void *m)
2 pj 840
{
841
  SS_level_des *lev = (SS_level_des *)(level_table[l]);
842
  struct timespec ty;
843
  int tx;
844
 
845
  #ifdef DEBUG
846
  kern_printf("SS_tendcy ");
847
  #endif
848
 
849
  /* update the server capacity */
850
  if (BACKGROUND_ON)
851
    lev->flags &= ~SS_BACKGROUND;
852
  else {
853
    SUBTIMESPEC(&schedule_time, &cap_lasttime, &ty);
854
    tx = TIMESPEC2USEC(&ty);
855
    lev->availCs -= tx;
856
    lev->replenish_amount += tx;
857
    #ifdef DEBUG
858
    kern_printf("PID:%d RA=%d ",lev->replenish_amount);
859
    #endif
860
  }
861
 
862
  if (lev->activated == p)
38 pj 863
    level_table[lev->scheduling_level]->private_extract(lev->scheduling_level,p);
2 pj 864
  else
29 pj 865
    iq_extract(p, &lev->wait);
2 pj 866
 
867
  if (lev->nact[p] > 0) {
868
    lev->nact[p]--;
29 pj 869
    iq_insertlast(p, &lev->wait);
2 pj 870
    proc_table[p].status = SS_WAIT;
871
  }
872
  else {
873
    proc_table[p].status = SLEEP;
874
  }
875
 
29 pj 876
  lev->activated = iq_getfirst(&lev->wait);
2 pj 877
  if (lev->activated != NIL) {
878
    SS_activation(lev);
879
  }
880
  else {
881
    /* No more task to schedule; set replenish amount */
882
    if(!(BACKGROUND_ON)) {
883
      SS_set_ra(l);
884
    }
885
  }
38 pj 886
 
887
  jet_update_endcycle(); /* Update the Jet data... */
353 giacomo 888
  TRACER_LOGEVENT(FTrace_EVT_task_end_cycle,3,p,l);
38 pj 889
 
890
  return 0;
2 pj 891
}
892
 
38 pj 893
static void SS_public_end(LEVEL l, PID p)
2 pj 894
{
895
  SS_level_des *lev = (SS_level_des *)(level_table[l]);
896
  struct timespec ty;
897
  int tx;
898
 
899
  #ifdef DEBUG
900
  kern_printf("SS_tend ");
901
  #endif
902
 
903
  /* update the server capacity */
904
  if (BACKGROUND_ON)
905
    lev->flags &= ~SS_BACKGROUND;
906
  else {
907
    SUBTIMESPEC(&schedule_time, &cap_lasttime, &ty);
908
    tx = TIMESPEC2USEC(&ty);
909
    lev->availCs -= tx;
910
    lev->replenish_amount += tx;
911
    #ifdef DEBUG
912
    kern_printf("PID:%d RA=%d ",p,lev->replenish_amount);
913
    #endif
914
  }
915
 
916
  if (lev->activated == p)
38 pj 917
    level_table[lev->scheduling_level]->private_extract(lev->scheduling_level,p);
2 pj 918
 
919
  proc_table[p].status = FREE;
29 pj 920
  iq_insertfirst(p,&freedesc);
2 pj 921
 
29 pj 922
  lev->activated = iq_getfirst(&lev->wait);
2 pj 923
  if (lev->activated != NIL) {
924
    SS_activation(lev);
925
  }
926
  else {
927
    if(!(BACKGROUND_ON)){
928
      /* No more task to schedule; set replenish amount */
929
      SS_set_ra(l);
930
    }
931
  }
932
}
933
 
934
/*-------------------------------------------------------------------*/
935
 
936
/*** Registration functions ***/
937
 
938
 
939
/*+ Registration function:
940
    int flags                 the init flags ... see SS.h +*/
38 pj 941
LEVEL SS_register_level(int flags, LEVEL master, int Cs, int per)
2 pj 942
{
943
  LEVEL l;            /* the level that we register */
944
  SS_level_des *lev;  /* for readableness only */
945
  PID i;              /* a counter */
946
 
947
  /* request an entry in the level_table */
38 pj 948
  l = level_alloc_descriptor(sizeof(SS_level_des));
2 pj 949
 
38 pj 950
  lev = (SS_level_des *)level_table[l];
2 pj 951
 
38 pj 952
  printk("    lev=%d\n",(int)lev);
2 pj 953
 
954
  /* fill the standard descriptor */
955
 
956
  if (flags & SS_ENABLE_BACKGROUND)
38 pj 957
    lev->l.public_scheduler = SS_public_schedulerbackground;
2 pj 958
 
959
  if (flags & SS_ENABLE_GUARANTEE_EDF)
38 pj 960
    lev->l.public_guarantee = SS_public_guaranteeEDF;
2 pj 961
  else if (flags & SS_ENABLE_GUARANTEE_RM)
38 pj 962
    lev->l.public_guarantee = SS_public_guaranteeRM;
2 pj 963
  else
38 pj 964
    lev->l.public_guarantee = NULL;
2 pj 965
 
38 pj 966
  lev->l.public_create    = SS_public_create;
967
  lev->l.public_end       = SS_public_end;
968
  lev->l.public_dispatch  = SS_public_dispatch;
969
  lev->l.public_epilogue  = SS_public_epilogue;
970
  lev->l.public_activate  = SS_public_activate;
971
  lev->l.public_unblock   = SS_public_unblock;
972
  lev->l.public_block     = SS_public_block;
973
  lev->l.public_message   = SS_public_message;
2 pj 974
 
975
  /* fill the SS descriptor part */
976
 
977
  for (i=0; i<MAX_PROC; i++)
978
     lev->nact[i] = -1;
979
 
980
  lev->Cs = Cs;
981
  lev->availCs = Cs;
982
 
983
  lev->period = per;
984
 
29 pj 985
  iq_init(&lev->wait, &freedesc, 0);
2 pj 986
  lev->activated = NIL;
987
 
988
  lev->U = (MAX_BANDWIDTH / per) * Cs;
989
 
990
  lev->scheduling_level = master;
991
 
992
  lev->flags = flags & 0x07;
993
 
994
  /* This is superfluos. I do it for robustness */
995
  for (i=0;i<SS_MAX_REPLENISH;lev->replenishment[i++]=0);
996
 
997
  /* Initialize replenishment stuff */
998
  lev->rfirst=0;
999
  lev->rlast=0;
1000
  lev->rcount=0;
1001
  lev->replenish_amount=0;
1002
  lev->server_active=SS_SERVER_NOTACTIVE;
38 pj 1003
 
1004
  return l;
2 pj 1005
}
1006
 
1007
bandwidth_t SS_usedbandwidth(LEVEL l)
1008
{
1009
  SS_level_des *lev = (SS_level_des *)(level_table[l]);
38 pj 1010
 
1011
  return lev->U;
2 pj 1012
}
1013
 
1014
int SS_availCs(LEVEL l) {
1015
  SS_level_des *lev = (SS_level_des *)(level_table[l]);
38 pj 1016
 
1017
  return lev->availCs;
2 pj 1018
}