Subversion Repositories shark

Rev

Rev 502 | 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
 ------------
657 anton 23
 CVS :        $Id: ss.c,v 1.8 2004-05-17 15:03:53 anton Exp $
2 pj 24
 
25
 File:        $File$
657 anton 26
 Revision:    $Revision: 1.8 $
27
 Last update: $Date: 2004-05-17 15:03:53 $
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
 
657 anton 754
static void SS_public_activate(LEVEL l, PID p, struct timespec *t)
2 pj 755
{
756
        SS_level_des *lev = (SS_level_des *)(level_table[l]);
757
 
758
        #ifdef DEBUG
759
        kern_printf("SS_tacti ");
760
        #endif
761
 
762
        if (lev->activated == p || proc_table[p].status == SS_WAIT) {
763
                if (lev->nact[p] != -1) lev->nact[p]++;
764
        }
765
        else if (proc_table[p].status == SLEEP) {
766
                if (lev->activated == NIL && lev->availCs > 0) {
767
                  if(!BACKGROUND_ON) {
768
                    /* if server is active, replenish time already set */
769
                    if (lev->server_active == SS_SERVER_NOTACTIVE) {
770
                      lev->server_active = SS_SERVER_ACTIVE;
771
                      /* set replenish time */
657 anton 772
                      ADDUSEC2TIMESPEC(lev->period, t);
773
                      TIMESPEC_ASSIGN(&lev->lastdline, t);
2 pj 774
                      #ifdef DEBUG
657 anton 775
                      kern_printf("RT=%d.%d ",t->tv_sec,t->tv_nsec);
2 pj 776
                      #endif
657 anton 777
                      kern_event_post(t, SS_replenish_timer, (void *) l);
2 pj 778
                    }
779
                  }
780
                  lev->activated = p;
781
                  SS_activation(lev);
782
                }
783
                else {
29 pj 784
                        iq_insertlast(p, &lev->wait);
2 pj 785
                        proc_table[p].status = SS_WAIT;
786
                }
787
        }
788
        else {
789
                kern_printf("SS_REJ%d %d %d %d ",
790
                            p,
791
                            proc_table[p].status,
792
                            lev->activated,
793
                            lev->wait.first);
794
                return;
795
        }
796
}
797
 
38 pj 798
static void SS_public_unblock(LEVEL l, PID p)
2 pj 799
{
800
  SS_level_des *lev = (SS_level_des *)(level_table[l]);
801
 
802
  #ifdef DEBUG
803
  kern_printf("SS_tins ");
804
  #endif
805
  lev->flags &= ~SS_BACKGROUND_BLOCK;
806
 
807
  lev->activated = NIL;
808
 
809
  /* when we reinsert the task into the system, the server capacity
810
     is always 0 because nobody executes with the SS before... */
29 pj 811
  iq_insertfirst(p, &lev->wait);
2 pj 812
  proc_table[p].status = SS_WAIT;
813
}
814
 
38 pj 815
static void SS_public_block(LEVEL l, PID p)
2 pj 816
{
817
  SS_level_des *lev = (SS_level_des *)(level_table[l]);
818
 
819
  #ifdef DEBUG
820
  kern_printf("SS_textr ");
821
  #endif
822
 
823
  /* set replenish amount */
824
  if(!(BACKGROUND_ON)) {
825
    SS_set_ra(l);
826
  }  
827
 
828
  /* clear the server capacity */
829
  lev->availCs = 0;
830
 
831
  lev->flags |= SS_BACKGROUND_BLOCK;
832
 
833
  if (lev->activated == p)
38 pj 834
    level_table[lev->scheduling_level]->private_extract(lev->scheduling_level,p);
2 pj 835
}
836
 
38 pj 837
static int SS_public_message(LEVEL l, PID p, void *m)
2 pj 838
{
839
  SS_level_des *lev = (SS_level_des *)(level_table[l]);
840
  struct timespec ty;
841
  int tx;
842
 
843
  #ifdef DEBUG
844
  kern_printf("SS_tendcy ");
845
  #endif
846
 
847
  /* update the server capacity */
848
  if (BACKGROUND_ON)
849
    lev->flags &= ~SS_BACKGROUND;
850
  else {
851
    SUBTIMESPEC(&schedule_time, &cap_lasttime, &ty);
852
    tx = TIMESPEC2USEC(&ty);
853
    lev->availCs -= tx;
854
    lev->replenish_amount += tx;
855
    #ifdef DEBUG
856
    kern_printf("PID:%d RA=%d ",lev->replenish_amount);
857
    #endif
858
  }
859
 
860
  if (lev->activated == p)
38 pj 861
    level_table[lev->scheduling_level]->private_extract(lev->scheduling_level,p);
2 pj 862
  else
29 pj 863
    iq_extract(p, &lev->wait);
2 pj 864
 
865
  if (lev->nact[p] > 0) {
866
    lev->nact[p]--;
29 pj 867
    iq_insertlast(p, &lev->wait);
2 pj 868
    proc_table[p].status = SS_WAIT;
869
  }
870
  else {
871
    proc_table[p].status = SLEEP;
872
  }
873
 
29 pj 874
  lev->activated = iq_getfirst(&lev->wait);
2 pj 875
  if (lev->activated != NIL) {
876
    SS_activation(lev);
877
  }
878
  else {
879
    /* No more task to schedule; set replenish amount */
880
    if(!(BACKGROUND_ON)) {
881
      SS_set_ra(l);
882
    }
883
  }
38 pj 884
 
885
  jet_update_endcycle(); /* Update the Jet data... */
502 giacomo 886
  TRACER_LOGEVENT(FTrace_EVT_task_end_cycle,(unsigned short int)proc_table[p].context,(unsigned int)l);
38 pj 887
 
888
  return 0;
2 pj 889
}
890
 
38 pj 891
static void SS_public_end(LEVEL l, PID p)
2 pj 892
{
893
  SS_level_des *lev = (SS_level_des *)(level_table[l]);
894
  struct timespec ty;
895
  int tx;
896
 
897
  #ifdef DEBUG
898
  kern_printf("SS_tend ");
899
  #endif
900
 
901
  /* update the server capacity */
902
  if (BACKGROUND_ON)
903
    lev->flags &= ~SS_BACKGROUND;
904
  else {
905
    SUBTIMESPEC(&schedule_time, &cap_lasttime, &ty);
906
    tx = TIMESPEC2USEC(&ty);
907
    lev->availCs -= tx;
908
    lev->replenish_amount += tx;
909
    #ifdef DEBUG
910
    kern_printf("PID:%d RA=%d ",p,lev->replenish_amount);
911
    #endif
912
  }
913
 
914
  if (lev->activated == p)
38 pj 915
    level_table[lev->scheduling_level]->private_extract(lev->scheduling_level,p);
2 pj 916
 
917
  proc_table[p].status = FREE;
29 pj 918
  iq_insertfirst(p,&freedesc);
2 pj 919
 
29 pj 920
  lev->activated = iq_getfirst(&lev->wait);
2 pj 921
  if (lev->activated != NIL) {
922
    SS_activation(lev);
923
  }
924
  else {
925
    if(!(BACKGROUND_ON)){
926
      /* No more task to schedule; set replenish amount */
927
      SS_set_ra(l);
928
    }
929
  }
930
}
931
 
932
/*-------------------------------------------------------------------*/
933
 
934
/*** Registration functions ***/
935
 
936
 
937
/*+ Registration function:
938
    int flags                 the init flags ... see SS.h +*/
38 pj 939
LEVEL SS_register_level(int flags, LEVEL master, int Cs, int per)
2 pj 940
{
941
  LEVEL l;            /* the level that we register */
942
  SS_level_des *lev;  /* for readableness only */
943
  PID i;              /* a counter */
944
 
945
  /* request an entry in the level_table */
38 pj 946
  l = level_alloc_descriptor(sizeof(SS_level_des));
2 pj 947
 
385 giacomo 948
  printk("SS_register_level\n");
949
 
38 pj 950
  lev = (SS_level_des *)level_table[l];
2 pj 951
 
952
  /* fill the standard descriptor */
953
 
954
  if (flags & SS_ENABLE_BACKGROUND)
38 pj 955
    lev->l.public_scheduler = SS_public_schedulerbackground;
2 pj 956
 
957
  if (flags & SS_ENABLE_GUARANTEE_EDF)
38 pj 958
    lev->l.public_guarantee = SS_public_guaranteeEDF;
2 pj 959
  else if (flags & SS_ENABLE_GUARANTEE_RM)
38 pj 960
    lev->l.public_guarantee = SS_public_guaranteeRM;
2 pj 961
  else
38 pj 962
    lev->l.public_guarantee = NULL;
2 pj 963
 
38 pj 964
  lev->l.public_create    = SS_public_create;
965
  lev->l.public_end       = SS_public_end;
966
  lev->l.public_dispatch  = SS_public_dispatch;
967
  lev->l.public_epilogue  = SS_public_epilogue;
968
  lev->l.public_activate  = SS_public_activate;
969
  lev->l.public_unblock   = SS_public_unblock;
970
  lev->l.public_block     = SS_public_block;
971
  lev->l.public_message   = SS_public_message;
2 pj 972
 
973
  /* fill the SS descriptor part */
974
 
975
  for (i=0; i<MAX_PROC; i++)
976
     lev->nact[i] = -1;
977
 
978
  lev->Cs = Cs;
979
  lev->availCs = Cs;
980
 
981
  lev->period = per;
982
 
29 pj 983
  iq_init(&lev->wait, &freedesc, 0);
2 pj 984
  lev->activated = NIL;
985
 
986
  lev->U = (MAX_BANDWIDTH / per) * Cs;
987
 
988
  lev->scheduling_level = master;
989
 
990
  lev->flags = flags & 0x07;
991
 
992
  /* This is superfluos. I do it for robustness */
993
  for (i=0;i<SS_MAX_REPLENISH;lev->replenishment[i++]=0);
994
 
995
  /* Initialize replenishment stuff */
996
  lev->rfirst=0;
997
  lev->rlast=0;
998
  lev->rcount=0;
999
  lev->replenish_amount=0;
1000
  lev->server_active=SS_SERVER_NOTACTIVE;
38 pj 1001
 
1002
  return l;
2 pj 1003
}
1004
 
1005
bandwidth_t SS_usedbandwidth(LEVEL l)
1006
{
1007
  SS_level_des *lev = (SS_level_des *)(level_table[l]);
38 pj 1008
 
1009
  return lev->U;
2 pj 1010
}
1011
 
1012
int SS_availCs(LEVEL l) {
1013
  SS_level_des *lev = (SS_level_des *)(level_table[l]);
38 pj 1014
 
1015
  return lev->availCs;
2 pj 1016
}