/*
 * Copyright (C) 2002 Luca Abeni
 * This is Free Software; see GPL.txt for details
 */

#include <linux/config.h>
#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
#define MODVERSIONS
#endif
#ifdef MODVERSIONS
#include <linux/modversions.h>
#endif
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <time.h>

#include <dispatch.h>
#include <cbs.h>
#ifdef __CBS_TRACE__
#include <trace.h>
#endif

#ifdef __GRUB_PWR__
#include "pxa250-power.h"
#endif

static unsigned long long int last_update_time = 0;
static struct cbs_struct *exec = NULL;
static struct list_head ready_list;

static struct t_data_struct enforce;

extern spinlock_t generic_scheduler_lock __cacheline_aligned;

int cbs_change_budg(struct task_struct *task, unsigned long int new_budget)
{
	int flags;
	spin_lock_irqsave(&generic_scheduler_lock, flags);
	if (task->private_data != NULL) {
 		struct cbs_struct * cbs_param = (struct cbs_struct*)(task->private_data);
		cbs_param->max_budget_clock = us2clock(new_budget);
		cbs_param->max_budget = new_budget;
	} else {
		printk("Error: changing budget to a non cbs task");
		spin_unlock_irqrestore(&generic_scheduler_lock, flags);
		return -1;
	}
	spin_unlock_irqrestore(&generic_scheduler_lock, flags);
	return 0;
}

int cbs_change_period(struct task_struct *task, unsigned long int new_period)
{
        int flags; 
        spin_lock_irqsave(&generic_scheduler_lock, flags);
        if (task->private_data != NULL) {
		struct cbs_struct * cbs_param = (struct cbs_struct*)(task->private_data);
                cbs_param->period_clock = us2clock(new_period);
                cbs_param->period = new_period;
        } else {
                printk("Error: changing period to a non cbs task");
                spin_unlock_irqrestore(&generic_scheduler_lock, flags);
                return -1;
        }
        spin_unlock_irqrestore(&generic_scheduler_lock, flags);
        return 0;
}

		




#ifdef __GRUB__
static long int U = 0; /* Global bandwidth*/
#ifdef __GRUB_EXTRA_BANDWIDTH__
static long long int remaining = 0; /* Remaining bandwidth */
#endif
#endif

static int sched_caller = 0;

static inline void cbs_idle_cpu(int cpu)
{
#ifdef __MULTITASK__
  struct task_struct *t;
  struct list_head *h;
  int iter = 0;
#endif

#ifdef __MULTITASK__
  if (exec != NULL) {
    iter++;
    if (!list_empty(&exec->tasks)) {
      list_for_each(h, &exec->tasks) {
        t = (list_entry(h, struct task_list, others))->task;
        if (t->pid == 0) {
          sched_error("CBS ERROR!!! (idling) Idle is in queue? (iteration %d)\n", iter);
          sched_error("%p --- %p --- %d\n", list_entry(h, struct task_list, others),
		      (list_entry(h, struct task_list, others))->task,
		      t->pid);
        } else {
	  if (t->state == TASK_RUNNING) {
            stop(t);
	  }
        }
      }
    } 
  }
#else /* __MULTITASK__ */
  if (exec != NULL) {
    stop(exec->task);
  }
#endif /* __MULTITASK__ */
  
  idle_cpu(cpu);
}

static inline void cbs_dispatch(struct cbs_struct *c, unsigned long long int time, int p)
{
  struct task_struct *t;
#ifdef __MULTITASK__
  struct list_head *h;
#endif
  
#ifdef __CBS_TRACE__
  trace_dispatch(c, time);
#endif

#ifdef __MULTITASK__
  if (exec != NULL) {
    if (!list_empty(&exec->tasks)) {
      list_for_each(h, &exec->tasks) {
        int iter = 0;

        iter++;
        t = (list_entry(h, struct task_list, others))->task;
        if (t->pid == 0) {
          sched_error("CBS ERROR!!! (descheduling) Idle is in queue? (iteration %d)\n", iter);
          sched_error("%p --- %p --- %d\n", list_entry(h, struct task_list, others),
		      (list_entry(h, struct task_list, others))->task,
		      t->pid);
        } else {

	  if (t->state == TASK_RUNNING) {

            stop(t);
	  }
        }
      }
    }
  }

  
  if (!list_empty(&c->tasks)) {
    list_for_each(h, &c->tasks) {
      int iter = 0;

      iter++;
      t = (list_entry(h, struct task_list, others))->task;
      if (t->pid == 0) {
        sched_error("CBS ERROR!!! Idle is in queue? (iteration %d)\n", iter);
        sched_error("%p --- %p --- %d\n", list_entry(h, struct task_list, others),
		      (list_entry(h, struct task_list, others))->task,
		      t->pid);
      } else {


	if (t->state == TASK_RUNNING) {
          dispatch(t, p);
	} else {

	}
      }
    }
  } else {
    printk("WTF??? No tasks in CBS Queue!\n");
  }

#else /* __MULTITASK__ */
  t = c->task;

  if (exec != NULL) {
    stop(exec->task);
  }
  dispatch(t, p);
#endif /* __MULTITASK__ */
}

static int update_used_time(struct cbs_struct *cbs, unsigned long long int time)
{
  unsigned long int consumed_time;


  sched_stop_timer(&enforce);

#ifdef __GRUB__
  consumed_time = (unsigned long int) llimd((time - last_update_time),U,fix_point);

#else /* CBS */
  consumed_time = time - last_update_time;
#endif
  if (consumed_time < 0)
    sched_error("[%llu]ERROR: consumed time < 0\n",time);
   
    if ((cbs->c) < consumed_time) {

    cbs->c = cbs->max_budget_clock;
    cbs->deadline += cbs->period_clock;
#ifdef __CBS_TRACE__
  trace_dl_postpone(cbs, time,
		  cbs->deadline - cbs->period_clock, cbs->deadline);
#endif

    return 1;
  }
  
  cbs->c -= consumed_time;
  

  last_update_time = time;
  return 0;
}

/* Returns 1 if the task is inserted at the beginning of the ready queue,
 * Returns 0 otherwise
 */
int edf_list_add(struct cbs_struct *t, int type)
{
  struct list_head *p;
  int done;


  if (ready_list.next == &ready_list) {
    list_add(&(t->rlist), &ready_list);
    
    return 1;
  } else {
    p = ready_list.next;
    done = 0;
    while (!done) {
      if (p == &ready_list) {
	done = 1;
      } else {
	if (list_entry(p, struct cbs_struct, rlist)->deadline > t->deadline) {
	  done = 1;
	} else {
          p = p->next;
	}
      }
    }
    list_add_tail(&(t->rlist), p);
  }


  if (&(t->rlist) == ready_list.next) {
    return 1;
  }

  return 0;
}

static int update_priorities(struct cbs_struct *cbs)
{
  if (cbs->rlist.next == NULL) {
    sched_error("CBS ERROR!!! Update priority on a task that is not in ready queue!!!\n");
    return 1;
  }
	      /* This can be null if we are invoked by deactivate() */
  list_del(&(cbs->rlist));
  return edf_list_add(cbs, 0);
}

void cbs_schedule(unsigned long long int time)
{


  if (exec == NULL) {
    if (current->private_data != NULL) {
      struct cbs_struct *c;

      c = current->private_data;
      if (c->new_task) {
	c->new_task = 0;
      } else {

      }
    }
  } else {
    if ((current->private_data != NULL) && (current->private_data != exec)) {

    }
  }


  if (list_empty(&ready_list)) {

#ifdef __GRUB_EXTRA_BANDWIDTH__
    remaining = 0;
#endif
    cbs_idle_cpu(0);
    exec = NULL;

  } else {
    struct cbs_struct *new_exec;
    new_exec = list_entry(ready_list.next, struct cbs_struct, rlist);
#ifdef __GRUB__
#ifdef __GRUB_EXTRA_BANDWIDTH__
    new_exec->c += remaining;
    //sched_print("%lld	%lld	%ld\n",new_exec->c,remaining,U);
    remaining = 0;
#endif
    if (U == 0) {
      sched_error("GRUB ERROR(cbs_schedule): U = 0!!!\n");
      U = 1;
    }

    sched_set_timer(llimd(new_exec->c,fix_point,U), &enforce);
#else /* CBS */   
    sched_set_timer(new_exec->c, &enforce);
#endif
    
    cbs_dispatch(new_exec, time, 0);
    exec = new_exec;
  } 
}

#ifndef __SLEEP__

static void cbs_postpone(unsigned long long int time, void *dummy)
{
  struct cbs_struct *t;


  if (exec == NULL) {
    sched_error("CBS ERROR!!! Postpone Deadline with Exec == NULL!!!\n");
  } else {
#ifndef __MULTITASK__
    if (current != exec->task) {
      sched_warning("CBS WARNING: current (%d) != Exec (%d)!!!\n",
		      current->pid, exec->task->pid);
    }
#endif
  }
  t = current->private_data;
  if (t == NULL) {
    
    t = exec;
    if (t == NULL) {
      sched_print("I am completely screwed up... Returning :(\n");
      printk("I am completely screwed up... Returning :(\n");

      return;
    }
  }
  if (t != exec) {


    /* Ok, let's try to play safe...
     * This is what probably happened:
     * - The executing task blocked, and its CBS became inactive...
     * - A new CBS was selected, and was put in exec...
     * 		---> Its depletion timer was set in a very strict time
     * - ... But the depletion timer fired __BEFORE__ returning to user space
     * - hence, current is still the blocked task
     *   	---> Setting t = exec is OK!!!
     */
    t = exec;
    if (t == NULL) {
      sched_print("I am completely screwed up... Returning :(\n");
      printk("I am completely screwed up... Returning :(\n");
    
      return;
    }
  }


  t->deadline += t->period_clock;
  t->c = t->max_budget_clock;
#ifdef __CBS_TRACE__
  trace_dl_postpone(t, time, t->deadline - t->period_clock, t->deadline);
#endif

  last_update_time = time;

  if (update_priorities(t) == 0) {
    sched_caller = 1;
    cbs_schedule(time);
    sched_caller = 0;
  } else {

#ifdef __GRUB__
    if (U == 0) {
      sched_error("GRUB ERROR(cbs_postpone): U = 0!!!\n");
      U = 1;
    }

    sched_set_timer(llimd(t->c,fix_point,U), &enforce);
#else /* CBS */
    sched_set_timer(t->c, &enforce);
#endif
  }

}


#else /* __SLEEP__ */
/* This function starts when the timer enforce fires */
static void cbs_sleep_postpone(unsigned long long int time, void *dummy)
{
  struct cbs_struct *t;
  unsigned long long int old_deadline;
  if (exec == NULL) {
    sched_error("CBS ERROR!!! Postpone Deadline with Exec == NULL!!!\n");
  } else {
#ifndef __MULTITASK__
    if (current != exec->task) {
      sched_warning("CBS WARNING: current (%d) != Exec (%d)!!!\n",
		      current->pid, exec->task->pid);
    }
#endif
  }
  t = current->private_data;
  if (t == NULL) {

    
    t = exec;
    if (t == NULL) {
      sched_print("I am completely screwed up... Returning :(\n");
      printk("I am completely screwed up... Returning :(\n");

      return;
    }
  }
  if (t != exec) {


    /* Ok, let's try to play safe...
     * This is what probably happened:
     * - The executing task blocked, and its CBS became inactive...
     * - A new CBS was selected, and was put in exec...
     * 		---> Its depletion timer was set in a very strict time
     * - ... But the depletion timer fired __BEFORE__ returning to user space
     * - hence, current is still the blocked task
     *   	---> Setting t = exec is OK!!!
     */
    t = exec;
    if (t == NULL) {
      sched_print("I am completely screwed up... Returning :(\n");
      printk("I am completely screwed up... Returning :(\n");
    
      return;
    }
  }
 
  if (t==NULL)
    sched_error("ERROR: Hard Postpone with t == NULL\n");

  old_deadline = t->deadline;
  t->deadline += t->period_clock;

  t->c = t->max_budget_clock;
  last_update_time = time;
  if (old_deadline < time) {

    if (update_priorities(t) == 0) {

      sched_caller = 1;
      cbs_schedule(time);
      sched_caller = 0;
    } else {
#ifdef __GRUB__
      if (U == 0) {
        sched_error("GRUB ERROR: U = 0!!!\n");
        U = 1;
      }

      sched_set_timer(llimd(t->c,fix_point,U), &enforce);
#else /* CBS */

      sched_set_timer(t->c, &enforce);
#endif
    }
  } else {	    

    list_del(&(t->rlist)); /* Remove the server from the list */
    sched_set_timer(old_deadline - time, &(t->reactive));
    sched_caller = 5;
    cbs_schedule(time);
    sched_caller = 0;
  }

}
#endif /* __SLEEP__ */

  
/*
 * Exported functions
 */

#if !defined __GRUB__
/* cbs_activate for CBS */
int cbs_activate(struct cbs_struct *t, unsigned long long r)
{
  int res;
#ifdef __CBS_GET_ERROR__
  struct arrival_list *arrival;
#endif
  
#ifdef __MULTITASK__

  if (t->activations++ != 0) {

    if (t == exec) {
      return 2;
    }
    return 0;
  }

#endif


  
#ifdef __CBS_TRACE__
  trace_activation(t, r);
#endif
  /* CBS test: c > (d - r) * U ---> New deadline */
  if ((t->c > llimd(t->deadline - r, t->max_budget_clock, t->period_clock)) ||
		  (t->deadline < r)) {
    /* Generate new deadline */
    t->deadline = r + t->period_clock;
    t->c = t->max_budget_clock;

#ifdef __CBS_TRACE__
  trace_dl_assign(t, r, t->deadline);
#endif
  }

  
  res = 0;
  if (edf_list_add(t, 1)) {

    if (exec) {
      if (update_used_time(exec, r)) {
        update_priorities(exec);
      }
    }
    last_update_time = r;
 
    sched_caller = 2;
    cbs_schedule(r);
    sched_caller = 0;
  
    res = 1;
  }


  return res;
}
#else
/* cbs_activate for GRUB */
int cbs_activate(struct cbs_struct *t, unsigned long long r)
{
  long int U_old = U;
  int res = 0;


#ifdef __MULTITASK__

  if (t->activations++ != 0) {

    if (t == exec) {
      return 2;
    }
    return 0;
  }
#endif


  
#ifdef __CBS_TRACE__
  trace_activation(t, r);
#endif
   if (t->state == 3 || t->state == 0) {
      /* Server was Inactive */

      U += llimd(t->max_budget,fix_point,t->period);
#ifdef __GRUB_PWR__
      pwr_up(U);
#endif
      /* Generate new deadline */
      t->deadline = r + t->period_clock;
      t->c = t->max_budget_clock;


      if (U > fix_point) {
        sched_error("GRUB ERROR: U=%ld > 1\n",U);
	U = fix_point;
      }
   
      /* Change the execution time for exec */
      if (exec != NULL && exec !=t) {
	unsigned long int consumed_time;
	sched_stop_timer(&enforce);

	if (r >= last_update_time) {
	  consumed_time = (unsigned long int) llimd ((r - last_update_time), U_old, fix_point);
	  if ((exec->c) < consumed_time) {
            exec->c = exec->max_budget_clock;
	    exec->deadline += exec->period_clock;
	  }
	  exec->c -= consumed_time;
	}
	last_update_time = r;

	sched_set_timer(llimd(exec->c, fix_point, U), &enforce);
      }	
   
   } else if (t->state == 2) {
      /* Server was ActiveNonContending */

      /* Since Vi = deadline-(c/bandwidth) we just postpone deadline of (period-(c/bandwidth)) */
      t->deadline += (unsigned long long int) ((t->period_clock) - llimd(t->c,t->period,t->max_budget));
      t->c = t->max_budget_clock;  
      sched_stop_timer(&(t->inactive));

    }
    t->state = 1; /* Server becomes ActiveContending */

#ifdef __CBS_TRACE__
  trace_dl_assign(t, r, t->deadline);
#endif

  if (edf_list_add(t, 1)) {

    if (exec) {
      if (update_used_time(exec, r)) {
        update_priorities(exec);
      }
    }
    last_update_time = r;

    sched_caller = 2;
    cbs_schedule(r);
    sched_caller = 0;
  
    res = 1;
  }


  return res;
}
#endif

int cbs_deactivate(struct cbs_struct *t, unsigned long long int time)
{
#ifdef __GRUB__
  long long int inactive_time;
  unsigned long long int virtual_time;
#endif


#ifdef __MULTITASK__

  if (t->activations-- > 1) {

    return 0;
  }
#endif

#ifdef __GRUB__
  virtual_time = t->deadline - llimd(t->c, t->period, t->max_budget);
  if (virtual_time > time) {
    /* Server becomes ActiveNonContending */
    t->state = 2; 
    /* The server will become inactive in (d-time)-(c/Ui) */
    inactive_time = t->deadline - time - llimd(t->c, t->period, t->max_budget);
    if (inactive_time <= 0) {
      inactive_time = 1;
    }
    sched_set_timer(inactive_time, &(t->inactive));

  } else {
   /* Server becomes Inactive */
   //sched_print("Direct to inactive\n");

   /* U-=Ui */
   U-=llimd(t->max_budget,fix_point,t->period);
#ifdef __GRUB_PWR__
   pwr_down(U);
#endif

   if (U < 0) {
     sched_error("GRUB ERROR(cbs_deactivate): U =%ld< 0\n",U);
     U = 0;
   }
#ifdef __GRUB_EXTRA_BANDWIDTH__
   remaining = t->c; 
#endif
   t->state= 3; /* Server becomes inactive */
 }
#endif
  
#ifdef __CBS_TRACE__
  trace_deactivation(t, time);
#endif
  list_del(&(t->rlist));
  t->rlist.next = NULL;
  t->rlist.prev = NULL;
  if (exec) {
    update_used_time(exec, time);
  } else {
    sched_error("CBS ERROR!!! Deactivate with Exec == NULL???\n");
  }
  last_update_time = time;
 
  
  sched_caller = 3;
  cbs_schedule(time);
  sched_caller = 0;


  return 1;
}


#ifdef __GRUB__

/* This function starts when a Server becomes inactive */
static void grub_inactive(unsigned long long int time, void* v)
{   
   long int U_old = U;	
   struct cbs_struct* t;	
   if (v == NULL)
     sched_error("GRUB ERROR: parameter of grub_inactive is NULL\n");
   t = (struct cbs_struct*) v;
   
   if (t->state == 2) {
      /* U-=Ui */
      U-=llimd(t->max_budget,fix_point,t->period);
#ifdef __GRUB_PWR__
      pwr_down(U);
#endif
      if (U < 0) {
        sched_error("GRUB ERROR(grub_inactive): U =%ld< 0\n",U);
        U = 0;
      }
      t->state= 3; /* Server becomes inactive */
  
      /* Change the execution time for exec */ 
     if (exec != NULL && exec!= t) {
       unsigned long int consumed_time;
       sched_stop_timer(&enforce);
       if (time >= last_update_time) {
         consumed_time = (unsigned long int) llimd ((time - last_update_time), U_old, fix_point);
         if ((exec->c) < consumed_time) {
           exec->c = exec->max_budget_clock;
           exec->deadline += exec->period_clock;
         }
         exec->c -= consumed_time;
       }
       last_update_time = time;
       sched_set_timer(llimd(exec->c, fix_point, U), &enforce);
     }
   }
}
#endif


#ifdef __SLEEP__
/* This function starts when a Server rebecomes active after being blocked 
 * (when the timer reactive fires) 
 * */
static void cbs_sleep_reactivate(unsigned long long int time, void* v)
{
  struct cbs_struct* t;
  if (v== NULL)
    sched_error("CBS ERROR: parameter of cbs_sleep_reactivate is NULL\n");

  t = (struct cbs_struct*) v;
  if (edf_list_add(t, 0)) {
    /* We need a context switch */
    if (exec) {
      /* Stop the executing server */
      if (update_used_time(exec, time)) {
        update_priorities(exec);
      }
    }
    last_update_time = time;
    sched_caller=6;
    cbs_schedule(time);
    sched_caller=0;
  }

}
#endif


struct cbs_struct *cbs_create(struct task_struct *task, int period, int max_budget)
{
  struct cbs_struct *p;
#ifdef __MULTITASK__
  struct task_list *task_list_entry;
#endif


  
  p = kmalloc(sizeof(struct cbs_struct), GFP_ATOMIC);
  if (p == NULL) {
    return NULL;
  }

  p->rlist.next = NULL;
  p->rlist.prev = NULL;

  p->c = 0;
  p->deadline = 0;
  p->period = period;
  p->max_budget = max_budget;
  p->period_clock = us2clock(p->period);
  p->max_budget_clock = us2clock(p->max_budget);

#ifdef __GRUB__
  (p->inactive).callback = grub_inactive;
  (p->inactive).param=p;
  sched_init_timer(&(p->inactive));
  p->state = 0; /* field state initialized with a not significant value (for debugging) */
#endif

#ifdef __SLEEP__
  (p->reactive).callback = cbs_sleep_reactivate;
  (p->reactive).param=p;
  sched_init_timer(&(p->reactive));
#endif


#ifdef __MULTITASK__
  task_list_entry = kmalloc(sizeof(struct task_list), GFP_ATOMIC);
  if (task_list_entry == NULL) {
    kfree(p);
    return NULL;
  }
  INIT_LIST_HEAD(&p->tasks);
  list_add(&task_list_entry->others, &p->tasks);
  task_list_entry->task = task;
  p->activations = 0;
#else
  p->task = task;
#endif
  p->new_task = 1;

#ifdef __CBS_TRACE__
  trace_creation(p, sched_read_clock());
#endif

  return p;
}

#ifdef __MULTITASK__
struct cbs_struct *cbs_add(struct task_struct *task, struct cbs_struct *cbs)
{
  struct task_list *task_list_entry;


  
  task_list_entry = kmalloc(sizeof(struct task_list), GFP_ATOMIC);
  if (task_list_entry == NULL) {
    return NULL;
  }
  list_add(&task_list_entry->others, &cbs->tasks);
  task_list_entry->task = task;
  task->policy = SCHED_RR;


  return cbs;
}

int cbs_remove(struct task_struct *task, struct cbs_struct *cbs)
{
  struct list_head *h, *h1;


  h1 = NULL;
  list_for_each(h, &cbs->tasks) {
    if ((list_entry(h, struct task_list, others))->task == task) {
      h1 = h;
    }
  }
  if (h1 == NULL) {
    sched_error("CBS ERROR!!! Removing task which is not in CBS?\n");
  } else {
    list_del(h1);
    kfree(list_entry(h1, struct task_list, others));
  }
  if (list_empty(&cbs->tasks)) {


    return 0;
  }
  return 1;
}


#if !defined __GRUB__
/* cbs_reactivate for CBS */
int cbs_reactivate(struct cbs_struct *t, unsigned long long r)
{

  if (t->activations++ != 0) {

    if (t == exec) {
      return 2;
    }
    return 0;
  }

  if (exec != NULL) {
    if (update_used_time(exec, r)) {
      update_priorities(exec);
    }
    cbs_idle_cpu(0);
    exec = NULL;
  } else {
    printk("ERROR!!! Reactivating with exec = NUL!!!\n");
  }

#ifdef __CBS_TRACE__
  trace_activation(t, r);
#endif
  /* CBS test: c > (d - r) * U ---> New deadline */
  if ((t->c > llimd(t->deadline - r, t->max_budget_clock, t->period_clock)) ||
		  (t->deadline < r)) {
	  
    /* Generate new deadline */
    t->deadline = r + t->period_clock;
    t->c = t->max_budget_clock;

#ifdef __CBS_TRACE__
  trace_dl_assign(t, r, t->deadline);
#endif
  }

  
  edf_list_add(t, 1);

  sched_caller = 4;
  cbs_schedule(r);
  sched_caller = 0;


  return 1;
}



#else
/* cbs_reactivate for GRUB */

int cbs_reactivate(struct cbs_struct *t, unsigned long long r)
{
  long int U_old = U;

  if (t->activations++ != 0) {

    if (t == exec) {
      return 2;
    }
    return 0;
  }

  if (exec != NULL) {
    if (update_used_time(exec, r)) {
      update_priorities(exec);
    }
    cbs_idle_cpu(0);
    exec = NULL;
  } else {
    printk("ERROR!!! ReActivating with exec = NUL!!!\n");
  }

#ifdef __CBS_TRACE__
  trace_activation(t, r);
#endif

   if (t->state == 3 || t->state == 0) {
      /* Server was Inactive */

      U += llimd(t->max_budget,fix_point,t->period);
#ifdef __GRUB_PWR__
      pwr_up(U);
#endif
      /* Generate new deadline */
      t->deadline = r + t->period_clock;
      t->c = t->max_budget_clock;



      if (U > fix_point) {
        sched_error("GRUB ERROR: U=%ld > 1\n",U);
	U = fix_point;
      }

/* Change the execution time for exec */
      if (exec != NULL && exec != t) {
	unsigned long int consumed_time;
	sched_stop_timer(&enforce);

	if (r >= last_update_time) {
	  consumed_time = (unsigned long int) llimd ((r - last_update_time), U_old, fix_point);
	  if ((exec->c) < consumed_time) {
            exec->c = exec->max_budget_clock;
	    exec->deadline += exec->period_clock;
	  }
	  exec->c -= consumed_time;
	}
	last_update_time = r;

	sched_set_timer(llimd(exec->c, fix_point, U), &enforce);
      }
   
   
   } else if (t->state == 2) {
      /* Server was ActiveNonContending */

      /* Since Vi = deadline-(c/bandwidth) we just postpone deadline of (period-(c/bandwidth)) */
      t->deadline += (unsigned long long int) ((t->period_clock) - llimd(t->c,t->period,t->max_budget));
      t->c = t->max_budget_clock; 
      sched_stop_timer(&(t->inactive));

    }
    t->state = 1; /* Server becomes ActiveContending */


  edf_list_add(t, 1);

  sched_caller = 4;
  cbs_schedule(r);
  sched_caller = 0;


  return 1;
}
#endif


#endif

void cbs_destroy(struct cbs_struct *t)
{
#ifdef __GRUB__
    long int U_old = U;
    if (t->state == 2 || t->state == 1) {
        /* Server is still Active */

        /* U-=Ui */
        U-=llimd(t->max_budget,fix_point,t->period);
#ifdef __GRUB_PWR__
        pwr_down(U);
#endif


        if (U < 0) {
            sched_error("GRUB ERROR(cbs_destroy): U=%ld < 0\n",U);
            U = 0;
        }
        sched_stop_timer(&(t->inactive));  /* Stop the timer */
#ifdef __SLEEP__
	sched_stop_timer(&(t->reactive));  /* Stop the timer */
#endif

        /* Change the execution time for exec */
        if (exec != NULL && exec != t) {
            unsigned long int consumed_time;
            unsigned long long int time= sched_read_clock();
            sched_stop_timer(&enforce);

            if (time >= last_update_time) {
                consumed_time = (unsigned long int) llimd ((time - last_update_time), U_old, fix_point);
                if ((exec->c) < consumed_time) {
                    exec->c = exec->max_budget_clock;
                    exec->deadline += exec->period_clock;
                }
                exec->c -= consumed_time;
            }
            last_update_time = time;

            sched_set_timer(llimd(exec->c, fix_point, U), &enforce);
        }
  
  
    } 
#endif


#ifdef __CBS_TRACE__
    trace_destruction(t, sched_read_clock());
#endif
    if ((t->rlist.next != NULL) || (t->rlist.prev != NULL)) {
        sched_error("CBS ERROR!!! Destroying a task while in ready queue?\n");
        return;
    }

    kfree(t);
}

void cbs_init(void)
{
  INIT_LIST_HEAD(&ready_list);
#ifdef __SLEEP__
  enforce.callback = cbs_sleep_postpone;
#else
  enforce.callback = cbs_postpone;
#endif
  enforce.param = NULL;
  sched_init_timer(&enforce);
#ifdef __CBS_TRACE__
  trace_start(sched_read_clock());
#endif
#ifdef __GRUB_PWR__
  pwr_init();
#endif
}
void cbs_deinit(void)
{
  sched_stop_timer(&enforce);
}
