Subversion Repositories shark

Rev

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

//=====================================================================
//       FFFFFFIII   RRRRR      SSTTTTTTT
//      FF         IIR   RR    SS
//     FF           IR        SS
//    FFFFFF         RRRR    SSSSST      
//   FF       FI       RRR  SS
//  FF         II     RRR  SS
// FF           IIIIIR    RS
//      
// Basic FSF(FIRST Scheduling Framework) contract management
// S.Ha.R.K. Implementation
//=====================================================================

#include "ll/i386/64bit.h"
#include <kernel/kern.h>
#include <modules/sem.h>
#include <modules/hartport.h>
#include <modules/cabs.h>

#include "fsf_contract.h"
#include "fsf_server.h"
#include "fsf_service_task.h"
#include "message.h"

#include <pthread.h>
#include <stdlib.h>
#include "pistar.h"


//#define FSF_DEBUG

int current_server=0;
server_elem server_list[FSF_MAX_N_SERVERS];
bandwidth_t fsf_max_bw = 0;
 
int fsf_server_level;
int shared_object_level;

PID server_task;

PORT channel[2];

int FSF_register_shared_object_module(void) {
  fsf_register_shared_object();
  return PISTAR_register_module();
}


int FSF_get_shared_object_level() {
  return shared_object_level;
}

int FSF_register_module(int server_level, bandwidth_t max_bw)
{
  printk("FSF Module\n");
  current_server=0;
  fsf_server_level = server_level;
  fsf_max_bw = max_bw;
  shared_object_level = FSF_register_shared_object_module();
 
  return 0;

}

void FSF_start_service_task(SOFT_TASK_MODEL *model) {

  // create the service task
  // create the communication channel for negotiation and renegotiation
 
  channel[1] = port_create("CHANW",sizeof(struct mess),1,STREAM,WRITE);

  channel[0] = port_create("CHANR",sizeof(struct mess),1,STREAM,READ);

  server_task = task_create("stask",service_task,model,NULL);
  if (server_task == -1) {
    cprintf("error creating service task\n");
    sys_shutdown_message("Could not create service_task");
    sys_end();
    return;
  }

  task_activate(server_task);

}


/* Convert the contract specification to
 * budget parameters
 */

int set_SERVER_budget_from_contract
  (const fsf_contract_parameters_t *contract,
   int *budget)
{

  int local_scheduler_level = 0;

   switch (contract->local_scheduler_id) {
     case FSF_SCHEDULER_POSIX:
       local_scheduler_level = POSIXSTAR_register_level(fsf_server_level,5000,32);
       break;
     case FSF_SCHEDULER_EDF:
       local_scheduler_level = EDFSTAR_register_level(fsf_server_level);
       break;
     case FSF_SCHEDULER_RM:
       local_scheduler_level = RMSTAR_register_level(fsf_server_level);
       break;
     case FSF_SCHEDULER_NONE:
       local_scheduler_level = NONESTAR_register_level(fsf_server_level);
       break;
   }    

   if (contract->d_equals_t == TRUE) {
  *budget = SERVER_setbudget(fsf_server_level,
                              TIMESPEC2USEC(&(contract->budget_min)),
                              TIMESPEC2USEC(&(contract->period_max)),
                              TIMESPEC2USEC(&(contract->period_max)),
                              local_scheduler_level,contract->local_scheduler_id);
  } else {
  *budget = SERVER_setbudget(fsf_server_level,
                              TIMESPEC2USEC(&(contract->budget_min)),
                              TIMESPEC2USEC(&(contract->period_max)),
                              TIMESPEC2USEC(&(contract->deadline)),
                              local_scheduler_level,contract->local_scheduler_id);
  }

  return 0;

}

int adjust_SERVER_budget
   (int budget, const TIME budget_actual,
    const TIME period_actual, const TIME dline_actual)
{

  SERVER_adjust_budget(fsf_server_level,
                       budget_actual,
                       period_actual,
                       dline_actual,
                       budget);

  return 0;

}

/* Admission Test function */
int add_contract(const fsf_contract_parameters_t *contract)
{
  return 0;

}

void contract_to_server(const fsf_contract_parameters_t *contract, int i) {

  TIME T,Q;
#ifdef FSF_DEBUG
  int temp;
#endif

  T=TIMESPEC2USEC(&contract->period_min);
  Q=TIMESPEC2USEC(&contract->budget_max);
  mul32div32to32(MAX_BANDWIDTH,Q,T,server_list[current_server].Umax);
                                                                                         
  T=TIMESPEC2USEC(&contract->period_min);
  server_list[i].Tmin=T;
                                                                                             
  T=TIMESPEC2USEC(&contract->period_max);
  server_list[i].Tmax=T;

  Q=TIMESPEC2USEC(&contract->budget_min);
  server_list[i].Cmin=Q;
                                                                                                 
  mul32div32to32(MAX_BANDWIDTH,Q,T,server_list[i].Umin);
  server_list[i].U=server_list[i].Umin;

  if (contract->d_equals_t == TRUE) {
    server_list[i].deadline = 0;
    server_list[i].d_equals_t = TRUE;
  } else {
    server_list[i].deadline = TIMESPEC2USEC(&contract->deadline);;
    server_list[i].d_equals_t = FALSE;
  }
                                               
  server_list[i].Qs = contract->quality;
  server_list[i].Is = contract->importance;

#ifdef FSF_DEBUG
  mul32div32to32(server_list[i].Umax,100, MAX_BANDWIDTH, temp);
  kern_printf("(Umax %d)",temp);
  mul32div32to32(server_list[i].Umin,100, MAX_BANDWIDTH, temp);
  kern_printf("(Umin %d)",temp);
#endif

}

int relink_contract_to_server(const fsf_contract_parameters_t *contract,
                              fsf_server_id_t server)
{
  int i=0;
#ifdef FSF_DEBUG
  kern_printf("(Relink Server %d)",server);
#endif
  // find contract
  while(i<current_server) {
    if (server_list[i].server==server) break;
    i++;
  }

  server_list[i].server=server;
//  server_list[i].Qs=1;
   
  contract_to_server(contract, i);


 return 0;
 
}

int link_contract_to_server(const fsf_contract_parameters_t *contract,
                            fsf_server_id_t server)
{
#ifdef FSF_DEBUG
  kern_printf("(Link Server %d)",server);
#endif
 
  server_list[current_server].server=server;
  //server_list[current_server].Qs=1;
 
  contract_to_server(contract,current_server);    
 
  current_server++;
  return 0;

}

int remove_contract(fsf_server_id_t server)
{
  int i=0;
  // find the contract
  while(i<current_server) {
     if (server_list[i].server==server) break;
     i++;
  }

  // compress the array;
  while (i<(current_server-1)) {
     server_list[i].server=server_list[i+1].server;
     server_list[i].Umin=server_list[i+1].Umin;
     server_list[i].U=server_list[i+1].Umin;    
     server_list[i].Umax=server_list[i+1].Umax;
     server_list[i].Cmin=server_list[i+1].Cmin;
     server_list[i].Tmin=server_list[i+1].Tmin;
     server_list[i].Tmax=server_list[i+1].Tmax;
     server_list[i].Qs=server_list[i+1].Qs;
     server_list[i].deadline = server_list[i+1].deadline;
     server_list[i].d_equals_t = server_list[i+1].d_equals_t;
     server_list[i].Is = server_list[i+1].Is;

     i++;
  }
  current_server--;


  return 0;

}


int fsf_negotiate_contract
  (const fsf_contract_parameters_t *contract,
   fsf_server_id_t                 *server)
{
  struct mess message;

  // send response server is -1 if the operation fail
  message.type=NEGOTIATE_CONTRACT;
  memmove(&message.contract,contract, sizeof(fsf_contract_parameters_t));

  port_send(channel[1],&message,BLOCK);
 
  port_receive(channel[0], &message, BLOCK);
 
  if (message.server==-1)
    return FSF_ERR_CONTRACT_REJECTED;

  *server=message.server;
 
  return 0;

}

int fsf_create_thread
  (fsf_server_id_t    server,
   pthread_t         *thread,
   pthread_attr_t    *attr,
   fsf_thread_code_t  thread_code,
   void              *arg,
   void              *local_scheduler_arg)
{

  int local_scheduler_level,scheduler_id;

  /* Check if server and thread exsist */
  if (server == NIL)
    return FSF_ERR_INVALID_SERVER;

  local_scheduler_level = SERVER_get_local_scheduler_level_from_budget(fsf_server_level,server);
  scheduler_id = SERVER_get_local_scheduler_id_from_budget(fsf_server_level,server);

  /* Check if thread is already bind */
  switch (scheduler_id) {
    case FSF_SCHEDULER_POSIX:

      nrt_task_def_arg(*(NRT_TASK_MODEL *)(local_scheduler_arg),arg);
      nrt_task_def_level(*(NRT_TASK_MODEL *)(local_scheduler_arg),local_scheduler_level);

      *thread = task_create("POSIXSTAR", thread_code, local_scheduler_arg, NULL);
      if (*thread == NIL) {
        #ifdef FSF_DEBUG
          kern_printf("(FSF:Error creating thread)");
        #endif
        return FSF_ERR_CREATE_THREAD;
      }

      POSIXSTAR_setbudget(local_scheduler_level, *thread, (int)(server));

    break;
    case FSF_SCHEDULER_EDF:

      hard_task_def_arg(*(HARD_TASK_MODEL *)(local_scheduler_arg),arg);
      hard_task_def_level(*(HARD_TASK_MODEL *)(local_scheduler_arg),local_scheduler_level);

      *thread = task_create("EDFSTAR", thread_code, local_scheduler_arg, NULL);
      if (*thread == NIL)
        return FSF_ERR_CREATE_THREAD;

      EDFSTAR_setbudget(local_scheduler_level, *thread, (int)(server));

      break;

    case FSF_SCHEDULER_RM:

      hard_task_def_arg(*(HARD_TASK_MODEL *)(local_scheduler_arg),arg);
      hard_task_def_level(*(HARD_TASK_MODEL *)(local_scheduler_arg),local_scheduler_level);

      *thread = task_create("RMSTAR", thread_code, local_scheduler_arg, NULL);
      if (*thread == NIL)
        return FSF_ERR_CREATE_THREAD;

      RMSTAR_setbudget(local_scheduler_level, *thread, (int)(server));

      break;
    case FSF_SCHEDULER_NONE:
                                                                                                                             
      hard_task_def_arg(*(HARD_TASK_MODEL *)(local_scheduler_arg),arg);
      hard_task_def_level(*(HARD_TASK_MODEL *)(local_scheduler_arg),local_scheduler_level);
                                                                                                                             
      *thread = task_create("NONESTAR", thread_code, local_scheduler_arg, NULL);
      if (*thread == NIL)
        return FSF_ERR_CREATE_THREAD;
                                                                                                                             
      NONESTAR_setbudget(local_scheduler_level, *thread, (int)(server));
                                                                                                                             
      break;
 
    default:
      return FSF_ERR_INVALID_SERVER;
      break;
  }
 
  #ifdef FSF_DEBUG
    kern_printf("(FSF:Insert thread = %d to Server = %d)",*thread,server);
  #endif

  return 0;
 
}

int  fsf_settask_nopreemptive
  (fsf_server_id_t *server,
   pthread_t       thread)
{
  int local_scheduler_level, scheduler_id;

  local_scheduler_level = SERVER_get_local_scheduler_level_from_pid(fsf_server_level,thread);
  scheduler_id = SERVER_get_local_scheduler_id_from_pid(fsf_server_level, thread);

  switch (scheduler_id) {
    case FSF_SCHEDULER_POSIX:
      POSIXSTAR_set_nopreemtive_current(local_scheduler_level);
      return 1;
      break;
    case FSF_SCHEDULER_EDF:
      EDFSTAR_set_nopreemtive_current(local_scheduler_level);
      return 1;
      break;
    case FSF_SCHEDULER_RM:
      RMSTAR_set_nopreemtive_current(local_scheduler_level);
      return 1;
      break;
    case FSF_SCHEDULER_NONE:
      break;
    default:
      return -1;
  }
  return -1;
}


int  fsf_settask_preemptive
  (fsf_server_id_t *server,
   pthread_t       thread)
{
  int local_scheduler_level, scheduler_id;

  local_scheduler_level = SERVER_get_local_scheduler_level_from_pid(fsf_server_level,thread);
  scheduler_id = SERVER_get_local_scheduler_id_from_pid(fsf_server_level, thread);

  switch (scheduler_id) {
    case FSF_SCHEDULER_POSIX:
      POSIXSTAR_unset_nopreemtive_current(local_scheduler_level);
      return 1;
      break;
    case FSF_SCHEDULER_EDF:
      EDFSTAR_unset_nopreemtive_current(local_scheduler_level);
      return 1;
      break;
    case FSF_SCHEDULER_RM:
      RMSTAR_unset_nopreemtive_current(local_scheduler_level);
      return 1;
      break;
    case FSF_SCHEDULER_NONE:
      break;
    default:
      return -1;
  }

  return -1;

}


int fsf_get_server
  (fsf_server_id_t *server,
   pthread_t       thread)
{
  int local_scheduler_level, scheduler_id;

  local_scheduler_level = SERVER_get_local_scheduler_level_from_pid(fsf_server_level,thread);
  scheduler_id = SERVER_get_local_scheduler_id_from_pid(fsf_server_level, thread);
 
  switch (scheduler_id) {
    case FSF_SCHEDULER_POSIX:  
      *server = POSIXSTAR_getbudget(local_scheduler_level,thread);
      return 0;
    case FSF_SCHEDULER_EDF:
      *server = EDFSTAR_getbudget(local_scheduler_level,thread);
      return 0;
    case FSF_SCHEDULER_RM:
      *server = RMSTAR_getbudget(local_scheduler_level,thread);
      return 0;
    case FSF_SCHEDULER_NONE:
      *server = NONESTAR_getbudget(local_scheduler_level,thread);
      return 0;
    default:
      return -1;
  }

  return -1;

}

int fsf_get_server_level(void)
{

  return fsf_server_level;

}

int fsf_cancel_contract
  (fsf_server_id_t *server)
{

  int local_scheduler_level, scheduler_id;
  SYS_FLAGS f;
  TIME T,Q;
  int i=0;

  #ifdef FSF_DEBUG
    kern_printf("(Remove server %d)",*server);
  #endif

  /* Check server id */
  if (*server < 0)
    return FSF_ERR_INVALID_SERVER;

  local_scheduler_level = SERVER_get_local_scheduler_level_from_budget(fsf_server_level,*server);
  scheduler_id = SERVER_get_local_scheduler_id_from_budget(fsf_server_level,*server);

  switch (scheduler_id) {
    case FSF_SCHEDULER_POSIX:
 
      /* Check if some thread use the server */
      if(POSIXSTAR_budget_has_thread(local_scheduler_level,*server))
        return FSF_ERR_SERVER_USED;
 
      break;
    case FSF_SCHEDULER_EDF:
      /* Check if some thread use the server */
      if(EDFSTAR_budget_has_thread(local_scheduler_level,*server))
        return FSF_ERR_SERVER_USED;
      break;

    case FSF_SCHEDULER_RM:
      /* Check if some thread use the server */
      if(RMSTAR_budget_has_thread(local_scheduler_level,*server))
        return FSF_ERR_SERVER_USED;

      break;

    case FSF_SCHEDULER_NONE:
      /* Check if some thread use the server */
      if(NONESTAR_budget_has_thread(local_scheduler_level,*server))
        return FSF_ERR_SERVER_USED;
                                                                                                                             
      break;

  }

  SERVER_removebudget(fsf_server_level,*server);

  level_free_descriptor(local_scheduler_level);
       
  remove_contract(*server);
                                             
  f=kern_fsave();              
  if (recalculate_contract(fsf_max_bw)==-1)  {
       kern_frestore(f);
       return FSF_ERR_CREATE_SERVER;
  }
#ifdef  FSF_DEBUG
  kern_printf("(Adjust budget)");
#endif    
  for (i=0; i<current_server; i++) {
    mul32div32to32(MAX_BANDWIDTH,server_list[i].Cmin,server_list[i].U,T);
    if (T > server_list[i].Tmin ) {
      server_list[i].actual_budget = server_list[i].Cmin;
      server_list[i].actual_period = T;
      #ifdef FSF_DEBUG
        kern_printf("(1 - Q %ld T %ld)", server_list[i].actual_budget, server_list[i].actual_period);
      #endif
     
      if (server_list[i].d_equals_t == TRUE)
        adjust_SERVER_budget(server_list[i].server,server_list[i].Cmin, T, T);
      else
        adjust_SERVER_budget(server_list[i].server,server_list[i].Cmin, T, server_list[i].deadline);

    } else {
      mul32div32to32(server_list[i].Tmin,server_list[i].U,MAX_BANDWIDTH,Q);
      server_list[i].actual_budget = Q;
      server_list[i].actual_period = server_list[i].Tmin;
      #ifdef FSF_DEBUG
         kern_printf("(2 - Q %ld T %ld)", server_list[i].actual_budget, server_list[i].actual_period);
      #endif
     
      if (server_list[i].d_equals_t == TRUE)
        adjust_SERVER_budget(server_list[i].server,Q, server_list[i].Tmin, server_list[i].Tmin);
      else
        adjust_SERVER_budget(server_list[i].server,Q, server_list[i].Tmin, server_list[i].deadline);

    }
    server_list[i].U=server_list[i].Umin;
   
  }                                          


  *server = -1;
  kern_frestore(f);

  return 0;
 
}

int recalculate_contract(bandwidth_t U) {
  bandwidth_t current_bandwidth;
  unsigned int temp_U;
  int        Qt;
  int isok=0;
  int i=0;
  int target_importance=1;
 
  #ifdef FSF_DEBUG
    int temp;
 
    kern_printf("(Recalculate contract)");
  #endif

  /* The current bandwidth is the min bandwidth */
  //current_bandwidth=SERVER_return_bandwidth(fsf_server_level);
  #ifdef FSF_DEBUG
     kern_printf("(nserver %d)", current_server);
  #endif  
 
  do  {
    current_bandwidth=0;
    Qt=0;
    for (i=0; i<current_server; i++) {
      if (server_list[i].Is==target_importance
          && server_list[i].U<server_list[i].Umax && server_list[i].Qs>0)
         Qt+=server_list[i].Qs;
       current_bandwidth+=server_list[i].U;
    #ifdef FSF_DEBUG
       kern_printf("(Qs %d, Qt %d, Is %d)", server_list[i].Qs, Qt,server_list[i].Is);
    #endif
    }

    #ifdef FSF_DEBUG
    kern_printf("(Total Quality %d)", Qt);
    #endif
    isok=1;
    for (i=0; i<current_server; i++) {
      if (server_list[i].Is==target_importance && server_list[i].U<server_list[i].Umax && server_list[i].Qs>0) {
        temp_U=server_list[i].U;
        server_list[i].U=U-current_bandwidth;
        mul32div32to32(server_list[i].U, server_list[i].Qs, Qt, server_list[i].U);
        temp_U+=server_list[i].U;
       
        if (temp_U<=server_list[i].Umin) {
           server_list[i].U=server_list[i].Umin;
        } else if (temp_U>server_list[i].Umax)  {
           server_list[i].U=server_list[i].Umax;
           isok=0;
        } else server_list[i].U=temp_U;
       
#ifdef FSF_DEBUG
        mul32div32to32(server_list[i].U,100, MAX_BANDWIDTH, temp);
        kern_printf("(Server %d bw %d)", server_list[i].server, temp);
#endif
      }
    }  
    target_importance++;
  } while (!isok && target_importance<6);
 
 return 0;
}
       
int fsf_renegotiate_contract
  (const fsf_contract_parameters_t *new_contract,
   fsf_server_id_t server)
{
 
  struct mess message;

  // send response server is -1 if the operation fail
  message.type=RENEGOTIATE_CONTRACT;
  memmove(&message.contract,new_contract, sizeof(fsf_contract_parameters_t));
  message.server = server;

  port_send(channel[1],&message,BLOCK);

  port_receive(channel[0], &message, BLOCK);

  if (message.server==-1) return FSF_ERR_CONTRACT_REJECTED;
 
   return 0;
}

void print_server_list()
{

  int i;
 
  kern_printf("Server List\n");
 
  for(i=0;i<current_server;i++) {

    kern_printf("[%d] Q:%d T:%d D:%d [DeT = %d]\n",server_list[i].server,(int)server_list[i].actual_budget,(int)server_list[i].actual_period,(int)server_list[i].deadline,(int)server_list[i].d_equals_t);

  }

}


int fsf_get_remain_budget(fsf_server_id_t server) {

  return SERVER_get_remain_capacity(fsf_server_level, server);
}