Subversion Repositories shark

Rev

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

/*
 * Project: S.Ha.R.K.
 *
 * Coordinators:
 *   Giorgio Buttazzo    <giorgio@sssup.it>
 *   Paolo Gai           <pj@gandalf.sssup.it>
 *
 * Authors     :
 *   Paolo Gai           <pj@gandalf.sssup.it>
 *   (see the web pages for full authors list)
 *
 * ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
 *
 * http://www.sssup.it
 * http://retis.sssup.it
 * http://shark.sssup.it
 */


/*
 * Copyright (C) 2001 Paolo Gai
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */


#include "ll/i386/64bit.h"
#include "fedfstar.h"
#include <ll/stdio.h>
#include <ll/string.h>
#include <kernel/model.h>
#include <kernel/descr.h>
#include <kernel/var.h>
#include <kernel/func.h>

#include <tracer.h>

/* for iqueues */
/* #include "iqueue.h" Now iqueues are the only queue type available
   into the kernel */

#include <kernel/iqueue.h>

/* for BUDGET_TASK_MODEL */
#include "fsf_configuration_parameters.h"
#include "fsf_core.h"
#include "fsf_server.h"
#include <posix/posix/comm_message.h>


/*
 * DEBUG stuffs begin
 */


//#define FEDFSTAR_DEBUG
//#define FDB_DEBUG

#ifdef FEDFSTAR_DEBUG

static __inline__ fake_printf(char *fmt, ...) {}

//#define fedfstar_printf fake_printf
//#define fedfstar_printf2 fake_printf
//#define fedfstar_printf3 fake_printf

#define fedfstar_printf kern_printf
#define fedfstar_printf2 kern_printf
#define fedfstar_printf3 kern_printf
#endif

/*
 * DEBUG stuffs end
 */


/* Status used in the level */
#define FEDFSTAR_READY         MODULE_STATUS_BASE    /* - Ready status        */
#define FEDFSTAR_IDLE          MODULE_STATUS_BASE+4  /* to wait the deadline  */

/* flags */
#define FEDFSTAR_CHANGE_LEVEL     8
#define FEDFSTAR_FLAG_NOPREEMPT   4
#define FEDFSTAR_FLAG_NORAISEEXC  2
#define FEDFSTAR_FLAG_SPORADIC    1


/* the level redefinition for the Earliest Deadline First level */
typedef struct {
  level_des l;     /* the standard level descriptor          */

  TIME period[MAX_PROC]; /* The task periods; the deadlines are
                       stored in the priority field           */

  int deadline_timer[MAX_PROC];
                   /* The task deadline timers               */

  struct timespec deadline_timespec[MAX_PROC];

  int dline_miss[MAX_PROC]; /* Deadline miss counter */
  int wcet_miss[MAX_PROC];  /* Wcet miss counter */

  int nact[MAX_PROC];       /* Wcet miss counter */

  int flag[MAX_PROC];
                   /* used to manage the JOB_TASK_MODEL and the
                       periodicity                            */


  IQUEUE ready;     /* the ready queue                        */

  PID activated;   /* the task that has been inserted into the
                       master module */


  int budget[MAX_PROC];

  int scheduling_level;

  int cap_lev;
  struct timespec cap_lasttime;

  int new_level[MAX_PROC];
  int wcet[MAX_PROC]; /* save the wcet fields */

  int ctime[MAX_PROC]; /* last computation time */
  int cavg[MAX_PROC]; /* avg of computation time */
  int ccount[MAX_PROC]; /* number of istance */

  long long int u_predicted;
  long long int u_p_avg;
  long long int sched_error_prev;
  int nro;
  long long int delta_old;
  long long int delta_new;
 

} FEDFSTAR_level_des;

#define HISTORY_BACK 4
#define GRANULARITY  5 // in microseconds

typedef bandwidth_t inv_bandwidth_t;

static long long int tita[HISTORY_BACK][FSF_MAX_N_SERVERS];
static bandwidth_t u[HISTORY_BACK][FSF_MAX_N_SERVERS];


void init_feedbackstruct(void) {
  int i=0, j=0;
  for (i=0; i<FSF_MAX_N_SERVERS; i++)  {
    for (j=0; j<HISTORY_BACK; j++) {
      u[j][i]=0;
      tita[j][i]=0;
    }
  }
}


long long int FDB_sample(FEDFSTAR_level_des *lev, int sched_error, TIME server_period, TIME cavg)
{
 
  long long int temp,temp1;
  long long int delta_new=0;
  int beta_1; //Not really this value
  int gamma_1;
  int beta_2;
  int gamma_2;

#ifdef FDB_DEBUG
     kern_printf("(FDB:sample:period:%d:cavg:%d:sched_error:%d)",(int)server_period,(int)cavg, sched_error);
#endif
     
  //if (delta_old==0)
  //delta_old=1000*server_period/cavg;
  temp=1000*server_period/cavg;
  beta_1=temp*6/5;
  gamma_1=temp*(-93)/100;
  beta_2=temp/5;
  gamma_2=temp*7/100;

#ifdef FDB_DEBUG
     kern_printf("(FDB:sample:b1:%d:g1:%d:b2:%d:g2:%d:temp:%d)",beta_1,gamma_1,beta_2,gamma_2, (int)temp);
#endif

  if ((long long int)sched_error>=(long long int)server_period) {
    temp=beta_1*(long long int)sched_error/server_period;
    temp1=gamma_1*(long long int)lev->sched_error_prev/server_period;
    delta_new=lev->delta_old-temp-temp1;
  }
  else {
    temp=beta_2*(long long int)sched_error/server_period;
    temp1=gamma_2*(long long int)lev->sched_error_prev/server_period;
    delta_new=lev->delta_old-temp-temp1;
  }
 #ifdef FDB_DEBUG
     kern_printf("(FDB1:sched_error:%d:delta_new:%lld)",sched_error, delta_new);
  #endif

 lev->delta_old=delta_new;
 
 lev->sched_error_prev=sched_error;

 return(delta_new);
}


/* This function preditcs the value of the next execution time based on the history of the task.
The algorithm is known as LMS and minimizes the square error.
It has to add the blocking time if the task may be block
And to determine the bandwidth it has to add the bandwidth determine in the previous function
*/

TIME FDB_activate(FEDFSTAR_level_des *lev,fsf_server_id_t server, TIME server_period, TIME blk_time, TIME c_time, TIME c_avg, bandwidth_t bw)
{
  //Filter coefficients
  static int mu=4; //convergence factor
  static long long int pred_error=0;
  long long int u_avg;
  bandwidth_t unew;
  int i;
  TIME Q_new;
  long long int u_new;
 
  //u_avg=server_bandwidth_avg;


  lev->nro++;
  pred_error=lev->u_predicted-(long long int)u[0][server];
 

  for (i=0;i<HISTORY_BACK;i++) {
    long long int temp=0;
    temp=(pred_error*(long long int)u[i][server])/MAX_BANDWIDTH*mu;
    tita[i][server]=tita[i][server]-temp;    
  }
 
  lev->u_predicted=0;
  for (i=0;i<HISTORY_BACK;i++)
    lev->u_predicted+=((tita[i][server]*(long long int)u[i][server])/MAX_BANDWIDTH);
 
  for (i=0; i<(HISTORY_BACK-1); i++)
    u[i+1][server]=u[i][server];
 
  lev->u_p_avg=(lev->u_p_avg*(lev->nro-1)+lev->u_predicted)/lev->nro; //OK
 

  //  if (c_avg!=0)
  //  u_avg=MAX_BANDWIDTH*c_avg/server_period;
  //else
  //  u_avg=bw;

  if (lev->u_p_avg==0)
    lev->u_p_avg=bw;


#ifdef FDB_DEBUG
  kern_printf("(FDB:u_p_avg %lld)\n", lev->u_p_avg);
  kern_printf("(FDB:c_time %d)\n---------------\n",c_time);
#endif

  if (c_time!=0)  
    mul32div32to32(MAX_BANDWIDTH,c_time,server_period,u[0][server]); // last real computation value
  else u[0][server]=bw;
 
  // c_predicted+=blk_time;
 
 
 
  /* What follows is the update of the server budget based on the FDB_sample return value and the prediction function
   */

 if (lev->delta_new!=0)  
    lev->delta_new=MAX_BANDWIDTH*1000/lev->delta_new; /*1000; */
 u_new=lev->delta_new+lev->u_p_avg;
 //if (u_new<0) exit(-1);
 //if (u_new>MAX_BANDWIDTH) exit(-1);
 unew=u_new;

#ifdef FDB_DEBUG
 kern_printf("(FDB:unew %d)", unew);
#endif

 mul32div32to32(server_period,unew, MAX_BANDWIDTH, Q_new);
 

 
 //Q_new=server_period*1000/u;
#ifdef FDB_DEBUG
 kern_printf("(FDB:uavg %lld\n)", lev->u_p_avg);
#endif
#ifdef FDB_DEBUG
 kern_printf("(FDB:act_int:qnew:%ld)",Q_new);
#endif
 return(Q_new);
}


static void capacity_handler(void *l)
{
  FEDFSTAR_level_des *lev = l;
  lev->cap_lev = NIL;
  event_need_reschedule();
}

static void FEDFSTAR_check_preemption(FEDFSTAR_level_des *lev)
{
  PID first=NIL;

  #ifdef FEDFSTAR_DEBUG
    edfstar_printf("(E:chk)");
  #endif
  /* check if the task is preempteble or not */
  if (lev->activated != NIL && lev->flag[lev->activated] & FEDFSTAR_FLAG_NOPREEMPT) return;

  if ((first = iq_query_first(&lev->ready)) != lev->activated) {
    if (lev->activated != NIL)
      level_table[ lev->scheduling_level ]->
        private_extract(lev->scheduling_level, lev->activated);

    lev->activated = first;

    if (first != NIL) {
      BUDGET_TASK_MODEL b;
      budget_task_default_model(b, lev->budget[first]);

      level_table[ lev->scheduling_level ]->
        private_insert(lev->scheduling_level, first, (TASK_MODEL *)&b);
    }
  }
}

static void FEDFSTAR_timer_deadline(void *par);

static void FEDFSTAR_internal_activate(FEDFSTAR_level_des *lev, PID p,
                                      struct timespec *t)
{
  TIME Q, D, T;
  int budget;
  bandwidth_t bw;

  #ifdef FEDFSTAR_DEBUG
    edfstar_printf("(E:iact)");
  #endif

  ADDUSEC2TIMESPEC(lev->period[p], t);

  *iq_query_timespec(p, &lev->ready) = *t;
  lev->deadline_timespec[p] = *t;

  /* Insert task in the correct position */
  proc_table[p].status = FEDFSTAR_READY;
  iq_timespec_insert(p,&lev->ready);
  proc_table[p].control &= ~CONTROL_CAP;

  budget=lev->budget[p];
  SERVER_getbudgetinfo(lev->scheduling_level, &Q, &T, &D, budget);

  mul32div32to32(MAX_BANDWIDTH, Q, T, bw);

  Q=FDB_activate(lev, budget, T, 0, lev->ctime[p],lev->cavg[p], bw);
 
  SERVER_adjust_budget(lev->scheduling_level, Q, T, D, budget);


  /* check for preemption */
  FEDFSTAR_check_preemption(lev);
}

static void FEDFSTAR_timer_deadline(void *par)
{
  PID p = (PID) par;
  FEDFSTAR_level_des *lev;

  lev = (FEDFSTAR_level_des *)level_table[proc_table[p].task_level];
  lev->deadline_timer[p] = NIL;  

  switch (proc_table[p].status) {
    case FEDFSTAR_IDLE:
      /* set the request time */
      if (!(lev->flag[p] & FEDFSTAR_FLAG_SPORADIC))
        FEDFSTAR_internal_activate(lev,p,iq_query_timespec(p, &lev->ready));

      event_need_reschedule();
      break;

    default:
      #ifdef FEDFSTAR_DEBUG
        kern_printf("(E:Dl:%d)",p);
      #endif
      /* else, a deadline miss occurred!!! */
      lev->dline_miss[p]++;
      TRACER_LOGEVENT(FTrace_EVT_task_deadline_miss,proc_table[p].context,proc_table[p].task_level);

      /* the task is into another state */
      if (!(lev->flag[p] & FEDFSTAR_FLAG_SPORADIC)) {
        lev->nact[p]++;
        ADDUSEC2TIMESPEC(lev->period[p], &lev->deadline_timespec[p]);
      }
  }

  /* Set the deadline timer */
  if (!(lev->flag[p] & FEDFSTAR_FLAG_SPORADIC))
    lev->deadline_timer[p] = kern_event_post(&lev->deadline_timespec[p],
                                             FEDFSTAR_timer_deadline,
                                             (void *)p);

}

static int FEDFSTAR_private_change_level(LEVEL l, PID p)
{

  FEDFSTAR_level_des *lev = (FEDFSTAR_level_des *)(level_table[l]);

  /* Change task level */
  if (lev->flag[p] & FEDFSTAR_CHANGE_LEVEL) {
   
#ifdef FEDFSTAR_DEBUG
    edfstar_printf("(E:clev)");
#endif
 
    STD_command_message msg;
   
    proc_table[p].status = SLEEP;
    lev->flag[p] &= ~ FEDFSTAR_CHANGE_LEVEL;
   
    level_table[lev->scheduling_level]->private_extract(lev->scheduling_level,p);
    iq_extract(p,&lev->ready);
   
    if (lev->deadline_timer[p] != -1)
      kern_event_delete(lev->deadline_timer[p]);
    lev->deadline_timer[p]=NIL;
   
    FEDFSTAR_check_preemption(lev);
   
    lev->nact[p] = 0;
    lev->budget[p] = -1;
    proc_table[p].task_level = lev->new_level[p];
   
    /* Send change level command to local scheduler */

    msg.command = STD_ACTIVATE_TASK;
    msg.param = NULL;

    level_table[ lev->new_level[p] ]->public_message(lev->new_level[p],p,&msg);
   
    return 1;

  }

  return 0;

}


static void FEDFSTAR_timer_guest_deadline(void *par)
{
  PID p = (PID) par;

  #ifdef FEDFSTAR_DEBUG
    edfstar_printf("(E:gdl)");
  #endif

  kern_raise(XDEADLINE_MISS,p);
}

static int FEDFSTAR_public_create(LEVEL l, PID p, TASK_MODEL *m)
{
  FEDFSTAR_level_des *lev = (FEDFSTAR_level_des *)(level_table[l]);

  /* if the FEDFSTAR_task_create is called, then the pclass must be a
     valid pclass. */

  HARD_TASK_MODEL *h;

  if (m->pclass != HARD_PCLASS) return -1;
  if (m->level != 0 && m->level != l) return -1;
  h = (HARD_TASK_MODEL *)m;
  if (!h->wcet || !h->mit) return -1;
  /* now we know that m is a valid model */

  #ifdef FEDFSTAR_DEBUG
    edfstar_printf("(E:Crt)");
  #endif

  lev->period[p] = h->mit;

  lev->flag[p] = 0;

  if (h->periodicity == APERIODIC)
       lev->flag[p] |= FEDFSTAR_FLAG_SPORADIC;

  lev->deadline_timer[p] = -1;
  lev->dline_miss[p]     = 0;
  lev->wcet_miss[p]      = 0;
  lev->nact[p]           = 0;

  /* Enable wcet check */
  proc_table[p].avail_time = h->wcet;
  proc_table[p].wcet       = h->wcet;
  proc_table[p].status     = SLEEP;

  return 0; /* OK, also if the task cannot be guaranteed... */
}


static void FEDFSTAR_account_capacity(FEDFSTAR_level_des *lev, PID p)
{
  struct timespec ty;
  TIME tx;


  SUBTIMESPEC(&schedule_time, &lev->cap_lasttime, &ty);
  tx = TIMESPEC2USEC(&ty);

  proc_table[p].avail_time -= tx;
}

static int FEDFSTAR_public_eligible(LEVEL l, PID p)
{
  FEDFSTAR_level_des *lev = (FEDFSTAR_level_des *)(level_table[l]);

  #ifdef FEDFSTAR_DEBUG
    edfstar_printf2("(E:eli:%d)",p);
  #endif

  return level_table[ lev->scheduling_level ]->
    private_eligible(lev->scheduling_level,p);

}

static void FEDFSTAR_public_dispatch(LEVEL l, PID p, int nostop)
{
  FEDFSTAR_level_des *lev = (FEDFSTAR_level_des *)(level_table[l]);
  struct timespec ty;

  #ifdef FEDFSTAR_DEBUG
    edfstar_printf("(E:dis)");
  #endif
 
  if (!nostop || proc_table[exec].task_level==l) {
      TIMESPEC_ASSIGN(&ty, &schedule_time);
      TIMESPEC_ASSIGN(&lev->cap_lasttime, &schedule_time);

      /* ...and finally, we have to post a capacity event on exec task because the shadow_task consume
       *      *        capacity on exe task always */

      if (proc_table[exec].avail_time > 0) {
        ADDUSEC2TIMESPEC(proc_table[exec].avail_time ,&ty);
        lev->cap_lev = kern_event_post(&ty,capacity_handler, lev);
      }
      level_table[lev->scheduling_level]->private_dispatch(lev->scheduling_level, p, nostop);
  }
  else
      level_table[proc_table[exec].task_level]->public_dispatch(proc_table[exec].task_level, p, nostop);

}

static void FEDFSTAR_public_epilogue(LEVEL l, PID p)
{
  FEDFSTAR_level_des *lev = (FEDFSTAR_level_des *)(level_table[l]);

  #ifdef FEDFSTAR_DEBUG
    edfstar_printf("(E:epi ");
  #endif

  if (lev->cap_lev!=NIL) {
       kern_event_delete(lev->cap_lev);
       lev->cap_lev=NIL;
  }

 
  if ( proc_table[exec].task_level==l ) {
   
     if (proc_table[exec].avail_time > 0) FEDFSTAR_account_capacity(lev,exec);

     if (FEDFSTAR_private_change_level(l, p)) return;

     /* check if the wcet is finished... */
     if (proc_table[exec].avail_time < 0) {
        /* wcet finished: disable wcet event and count wcet miss */

       #ifdef FEDFSTAR_DEBUG
         edfstar_printf2("W%d",p);
       #endif
        //proc_table[p].control &= ~CONTROL_CAP;
        lev->wcet_miss[exec]++;
        proc_table[exec].avail_time = 0;
        TRACER_LOGEVENT(FTrace_EVT_task_wcet_violation,proc_table[exec].context,proc_table[exec].task_level);
     }

     #ifdef FEDFSTAR_DEBUG
       edfstar_printf(")");
     #endif

     level_table[ lev->scheduling_level ]->
       private_epilogue(lev->scheduling_level,p);

      proc_table[exec].status = FEDFSTAR_READY;
    } else
        level_table[proc_table[exec].task_level]->public_epilogue(proc_table[exec].task_level,p);

}

static void FEDFSTAR_public_activate(LEVEL l, PID p, struct timespec *o)
{
  FEDFSTAR_level_des *lev = (FEDFSTAR_level_des *)(level_table[l]);
  struct timespec t;

  #ifdef FEDFSTAR_DEBUG
    edfstar_printf("(E:act:%d)",p);
  #endif

  /* Test if we are trying to activate a non sleeping task    */
  /* save activation (only if needed... */
  if (proc_table[p].status != SLEEP) {
    /* a periodic task cannot be activated when it is already active */
    /* but aperiodic task can be reactivate before */
    if (lev->flag[p] & FEDFSTAR_FLAG_SPORADIC) {
        if (proc_table[p].status != FEDFSTAR_IDLE) {
          lev->nact[p]++;
          //kern_printf("(Inc nact %d)",p);
          //kern_printf("(%d STATUS %d %ds %dns)", p, proc_table[p].status, o->tv_sec, o->tv_nsec/1000);
          return;
        }
    } else {
      return;
      //kern_raise(XACTIVATION,p);
    }
  }

  kern_gettime(&t);

  FEDFSTAR_internal_activate(lev,p, &t);

  /* Set the deadline timer */
  lev->deadline_timer[p] = kern_event_post(&lev->deadline_timespec[p],
                                           FEDFSTAR_timer_deadline,
                                           (void *)p);

}

static void FEDFSTAR_public_unblock(LEVEL l, PID p)
{
  FEDFSTAR_level_des *lev = (FEDFSTAR_level_des *)(level_table[l]);

  #ifdef FEDFSTAR_DEBUG
    edfstar_printf("(E:ins)");
  #endif

  /* Insert task in the correct position */
  proc_table[p].status = FEDFSTAR_READY;
  iq_timespec_insert(p,&lev->ready);

  /* and check for preemption! */
  FEDFSTAR_check_preemption(lev);

}

static void FEDFSTAR_public_block(LEVEL l, PID p)
{

  FEDFSTAR_level_des *lev = (FEDFSTAR_level_des *)(level_table[l]);

  #ifdef FEDFSTAR_DEBUG
   edfstar_printf("(E:ext)");
  #endif

  /* the task is blocked on a synchronization primitive. we have to
     remove it from the master module -and- from the local queue! */

  iq_extract(p,&lev->ready);

  /* and finally, a preemption check! (it will also call guest_end) */
  FEDFSTAR_check_preemption(lev);
}

static int FEDFSTAR_public_message(LEVEL l, PID p, void *m)
{

  FEDFSTAR_level_des *lev = (FEDFSTAR_level_des *)(level_table[l]);
  struct timespec temp;
  STD_command_message *msg;
  HARD_TASK_MODEL *h;
  TIME Q, D, T;
  struct timespec t,diff;
  int sched_error_act;
  int budget;
 
  #ifdef FEDFSTAR_DEBUG
    edfstar_printf("(E:ecy ");
  #endif

  switch ((long)(m)) {

    /* Task EndCycle */
    case (long)(NULL):

      if (FEDFSTAR_private_change_level(l,p)) return 0;
   
      sched_error_act=0;
      /* Get the server deadline */
      budget=FEDFSTAR_getbudget(l,p);
      SERVER_getbudgetinfo(lev->scheduling_level, &Q, &T, &D, budget);
      SERVER_getdeadline(lev->scheduling_level, budget, &t);
      /* Get the task deadline */
      temp = *iq_query_timespec(p, &lev->ready);
#ifdef FDB_DEBUG
      kern_printf("(dt sec %ld, us %ld)", temp.tv_sec, temp.tv_nsec/1000);
      kern_printf("(ds sec %ld, us %ld)", t.tv_sec, t.tv_nsec/1000);
#endif
      if (/* 1 */ TIMESPEC_A_LT_B(&t,&temp)) {   
        SUBTIMESPEC(&temp, &t, &diff);
        sched_error_act=-TIMESPEC2USEC(&diff);
      }
      else {
        SUBTIMESPEC(&t, &temp, &diff);
        sched_error_act=TIMESPEC2USEC(&diff);
      }
     
      if (proc_table[p].avail_time > 0) FEDFSTAR_account_capacity(lev,p);

       /* we call guest_end directly here because the same task may
         be reinserted in the queue before calling the preemption check! */

       level_table[ lev->scheduling_level ]->
         private_extract(lev->scheduling_level,p);
       lev->activated = NIL;

       iq_extract(p,&lev->ready);

 
       
       lev->ctime[p]=proc_table[p].wcet-proc_table[p].avail_time;

       lev->cavg[p]=(lev->ctime[p]+(lev->cavg[p])*(lev->ccount[p]))/(lev->ccount[p]+1);      
       
       lev->ccount[p]=(lev->ccount[p]%INT_MAX)+1;
       
       lev->delta_new=FDB_sample(lev,sched_error_act, T, lev->cavg[p]);

       /* we reset the capacity counters... */
       proc_table[p].avail_time = proc_table[p].wcet;

       if (lev->nact[p] > 0) {
   
         #ifdef FEDFSTAR_DEBUG
           kern_printf("E%d",p);
         #endif
     
         /* Pending activation: reactivate the thread!!! */
         lev->nact[p]--;
     
         /* see also FEDFSTAR_timer_deadline */
         kern_gettime(&temp);
     
         FEDFSTAR_internal_activate(lev,p, &temp);
     
         /* check if the deadline has already expired */
         temp = *iq_query_timespec(p, &lev->ready);
         if (TIMESPEC_A_LT_B(&temp, &schedule_time)) {
           /* count the deadline miss */
           lev->dline_miss[p]++;
           kern_event_delete(lev->deadline_timer[p]);
           lev->deadline_timer[p] = NIL;
         }

       } else {

         #ifdef FEDFSTAR_DEBUG
           edfstar_printf("e%d",p);
         #endif
     
         /* the task has terminated his job before it consume the wcet. All OK! */
         if (lev->flag[p] & FEDFSTAR_FLAG_SPORADIC)
                proc_table[p].status = SLEEP;
         else
                proc_table[p].status = FEDFSTAR_IDLE;
         
         if (lev->flag[p] & FEDFSTAR_FLAG_SPORADIC && lev->deadline_timer[p] != NIL) {
           kern_event_delete(lev->deadline_timer[p]);
           lev->deadline_timer[p] = NIL;
         }
     
         /* and finally, a preemption check! */
         FEDFSTAR_check_preemption(lev);
     
         /* when the deadline timer fire, it recognize the situation and set
           correctly all the stuffs (like reactivation, etc... ) */

       }

    #ifdef FEDFSTAR_DEBUG
      edfstar_printf(")");
    #endif

    TRACER_LOGEVENT(FTrace_EVT_task_end_cycle,proc_table[p].context,proc_table[p].task_level);
    jet_update_endcycle(); /* Update the Jet data... */
    break;

  default:
    msg = (STD_command_message *)m;
 
#ifdef FEDFSTAR_DEBUG
    edfstar_printf("(E:MSG %d)",msg->command);
#endif  
 
    switch(msg->command) {
    case STD_SET_NEW_MODEL:
      /* if the FEDFSTAR_task_create is called, then the pclass must be a
         valid pclass. */

      h=(HARD_TASK_MODEL *)(msg->param);
   
      /* now we know that m is a valid model */
      lev->wcet[p] = h->wcet;
      lev->period[p] = h->mit;

#ifdef FEDFSTAR_DEBUG      
      kern_printf("(EDF:NM p%d w%d m%d)", p, h->wcet, h->mit);
#endif      
      lev->flag[p] = 0;
      lev->deadline_timer[p] = -1;
      lev->dline_miss[p]     = 0;
      lev->wcet_miss[p]      = 0;
      lev->nact[p]           = 0;

      break;

    case STD_SET_NEW_LEVEL:
     
      lev->flag[p] |= FEDFSTAR_CHANGE_LEVEL;
      lev->new_level[p] = (int)(msg->param);

      break;

    case STD_ACTIVATE_TASK:
#ifdef FEDFSTAR_DEBUG
      kern_printf("(EDF:SA)");
#endif      
      /* Enable wcet check */
      proc_table[p].avail_time = lev->wcet[p];
      proc_table[p].wcet       = lev->wcet[p];
      proc_table[p].control &= ~CONTROL_CAP;
     
      FEDFSTAR_public_activate(l, p,NULL);
     
      break;

     
    }

    break;
     
  }
  return 0;
}

static void FEDFSTAR_public_end(LEVEL l, PID p)
{
  FEDFSTAR_level_des *lev = (FEDFSTAR_level_des *)(level_table[l]);

  #ifdef FEDFSTAR_DEBUG
    edfstar_printf("(E:end)");
  #endif

  iq_extract(p,&lev->ready);
  level_table[ lev->scheduling_level ]->
    private_extract(lev->scheduling_level, p);


  /* we finally put the task in the ready queue */
  proc_table[p].status = FREE;
 
  iq_insertfirst(p,&freedesc);
  lev->activated=NIL;
 
  if (lev->deadline_timer[p] != -1) {
    kern_event_delete(lev->deadline_timer[p]);
    lev->deadline_timer[p] = NIL;
  }

  /* and finally, a preemption check! (it will also call guest_end) */
  FEDFSTAR_check_preemption(lev);
}

/* Guest Functions
   These functions manages a JOB_TASK_MODEL, that is used to put
   a guest task in the FEDFSTAR ready queue. */


static void FEDFSTAR_private_insert(LEVEL l, PID p, TASK_MODEL *m)
{
  FEDFSTAR_level_des *lev = (FEDFSTAR_level_des *)(level_table[l]);
  JOB_TASK_MODEL *job;

  if (m->pclass != JOB_PCLASS || (m->level != 0 && m->level != l) ) {
    kern_raise(XINVALID_TASK, p);
    return;
  }

  job = (JOB_TASK_MODEL *)m;

  /* if the FEDFSTAR_guest_create is called, then the pclass must be a
     valid pclass. */


  *iq_query_timespec(p, &lev->ready) = job->deadline;
 
  lev->deadline_timer[p] = -1;
  lev->dline_miss[p]     = 0;
  lev->wcet_miss[p]      = 0;
  lev->nact[p]           = 0;

  if (job->noraiseexc)
    lev->flag[p] |= FEDFSTAR_FLAG_NORAISEEXC;
  else {
    lev->flag[p] &= ~FEDFSTAR_FLAG_NORAISEEXC;
    lev->deadline_timer[p] = kern_event_post(iq_query_timespec(p, &lev->ready),
                                             FEDFSTAR_timer_guest_deadline,
                                             (void *)p);
  }

  lev->period[p] = job->period;

  /* Insert task in the correct position */
  iq_timespec_insert(p,&lev->ready);
  proc_table[p].status = FEDFSTAR_READY;

  /* check for preemption */
  FEDFSTAR_check_preemption(lev);

  /* there is no bandwidth guarantee at this level, it is performed
     by the level that inserts guest tasks... */

}

static void FEDFSTAR_private_dispatch(LEVEL l, PID p, int nostop)
{
  FEDFSTAR_level_des *lev = (FEDFSTAR_level_des *)(level_table[l]);

  level_table[ lev->scheduling_level ]->
    private_dispatch(lev->scheduling_level,p,nostop);
}

static void FEDFSTAR_private_epilogue(LEVEL l, PID p)
{
  FEDFSTAR_level_des *lev = (FEDFSTAR_level_des *)(level_table[l]);

  /* the task has been preempted. it returns into the ready queue... */
  level_table[ lev->scheduling_level ]->
    private_epilogue(lev->scheduling_level,p);

  proc_table[p].status = FEDFSTAR_READY;
}

static void FEDFSTAR_private_extract(LEVEL l, PID p)
{
  FEDFSTAR_level_des *lev = (FEDFSTAR_level_des *)(level_table[l]);

#ifdef FEDFSTAR_DEBUG
  kern_printf("FEDFSTAR_guest_end: dline timer %d\n",lev->deadline_timer[p]);
#endif

  iq_extract(p, &lev->ready);

  /* we remove the deadline timer, because the slice is finished */
  if (lev->deadline_timer[p] != NIL) {
#ifdef FEDFSTAR_DEBUG
    kern_printf("FEDFSTAR_guest_end: dline timer %d\n",lev->deadline_timer[p]);
#endif
    kern_event_delete(lev->deadline_timer[p]);
    lev->deadline_timer[p] = NIL;
  }

  /* and finally, a preemption check! (it will also call guest_end() */
  FEDFSTAR_check_preemption(lev);
}

/* Registration functions */

/* Registration function:
    int flags                 the init flags ... see FEDFSTAR.h */


LEVEL FEDFSTAR_register_level(int master)
{
  LEVEL l;            /* the level that we register */
  FEDFSTAR_level_des *lev;  /* for readableness only */
  PID i;              /* a counter */

#ifdef FEDFSTAR_DEBUG
  printk("FEDFSTAR_register_level\n");
#endif

  /* request an entry in the level_table */
  l = level_alloc_descriptor(sizeof(FEDFSTAR_level_des));

  lev = (FEDFSTAR_level_des *)level_table[l];

  /* fill the standard descriptor */
  lev->l.private_insert   = FEDFSTAR_private_insert;
  lev->l.private_extract  = FEDFSTAR_private_extract;
  lev->l.private_dispatch = FEDFSTAR_private_dispatch;
  lev->l.private_epilogue = FEDFSTAR_private_epilogue;

  lev->l.public_guarantee = NULL;
  lev->l.public_eligible  = FEDFSTAR_public_eligible;
  lev->l.public_create    = FEDFSTAR_public_create;
  lev->l.public_end       = FEDFSTAR_public_end;
  lev->l.public_dispatch  = FEDFSTAR_public_dispatch;
  lev->l.public_epilogue  = FEDFSTAR_public_epilogue;
  lev->l.public_activate  = FEDFSTAR_public_activate;
  lev->l.public_unblock   = FEDFSTAR_public_unblock;
  lev->l.public_block     = FEDFSTAR_public_block;
  lev->l.public_message   = FEDFSTAR_public_message;

  /* fill the FEDFSTAR descriptor part */
  for(i=0; i<MAX_PROC; i++) {
    lev->period[i]         = 0;
    lev->deadline_timer[i] = -1;
    lev->flag[i]           = 0;
    lev->dline_miss[i]     = 0;
    lev->wcet_miss[i]      = 0;
    lev->nact[i]           = 0;
    lev->budget[i]         = NIL;
    lev->new_level[i]      = -1;
    lev->ctime[i]          = 0;
    lev->cavg[i]           = 0;
    lev->ccount[i]         = 0;
  }

  lev->u_predicted=0;
  lev->u_p_avg=0;
  lev->nro=0;
  lev->sched_error_prev=0;
  lev->delta_old=0;
  lev->delta_new=0;

  iq_init(&lev->ready, NULL, IQUEUE_NO_PRIORITY);
  lev->activated = NIL;

  lev->scheduling_level = master;
  lev->cap_lev = NIL;
  NULL_TIMESPEC(&lev->cap_lasttime);

  return l;
}

int FEDFSTAR_get_dline_miss(PID p)
{
  LEVEL l = proc_table[p].task_level;
  FEDFSTAR_level_des *lev = (FEDFSTAR_level_des *)(level_table[l]);
 
  return lev->dline_miss[p];
}

int FEDFSTAR_get_wcet_miss(PID p)
{
  LEVEL l = proc_table[p].task_level;
  FEDFSTAR_level_des *lev = (FEDFSTAR_level_des *)(level_table[l]);

  return lev->wcet_miss[p];
}

int FEDFSTAR_get_nact(PID p)
{
  LEVEL l = proc_table[p].task_level;
  FEDFSTAR_level_des *lev = (FEDFSTAR_level_des *)(level_table[l]);

  return lev->nact[p];
}

int FEDFSTAR_reset_dline_miss(PID p)
{
  LEVEL l = proc_table[p].task_level;
  FEDFSTAR_level_des *lev = (FEDFSTAR_level_des *)(level_table[l]);

  lev->dline_miss[p] = 0;
  return 0;
}

int FEDFSTAR_reset_wcet_miss(PID p)
{
  LEVEL l = proc_table[p].task_level;
  FEDFSTAR_level_des *lev = (FEDFSTAR_level_des *)(level_table[l]);

  lev->wcet_miss[p] = 0;
  return 0;
}

int FEDFSTAR_setbudget(LEVEL l, PID p, int budget)
{

  FEDFSTAR_level_des *lev = (FEDFSTAR_level_des *)(level_table[l]);
 
  lev->budget[p] = budget;

  return 0;

}

int FEDFSTAR_getbudget(LEVEL l, PID p)
{

  FEDFSTAR_level_des *lev = (FEDFSTAR_level_des *)(level_table[l]);

  return lev->budget[p];

}

void FEDFSTAR_set_nopreemtive_current(LEVEL l) {
 
  FEDFSTAR_level_des *lev = (FEDFSTAR_level_des *)(level_table[l]);
 
  lev->flag[lev->activated]|=FEDFSTAR_FLAG_NOPREEMPT;
}

void FEDFSTAR_unset_nopreemtive_current(LEVEL l) {

  FEDFSTAR_level_des *lev = (FEDFSTAR_level_des *)(level_table[l]);

  lev->flag[lev->activated]&=~FEDFSTAR_FLAG_NOPREEMPT;
}
 
int FEDFSTAR_budget_has_thread(LEVEL l, int budget)
{

  FEDFSTAR_level_des *lev = (FEDFSTAR_level_des *)(level_table[l]);
  int i;

  for(i = 0; i< MAX_PROC; i++)
    if (lev->budget[i] == budget) return 1;

  return 0;

}