
/*
 * cpu_reserve.c: code to support CPU reservations
 *
 * Copyright (C) 2000 TimeSys Corporation
 *
 * This is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * This software 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 * This file is derived from software distributed under the following terms:
 *
 * Real-time and Multimedia Systems Laboratory
 * Copyright (c) 2000 Carnegie Mellon University
 * All Rights Reserved.
 * 
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 * 
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 * 
 * Carnegie Mellon requests users of this software to return to
 * 
 *  Real-Time and Multimedia Systems Laboratory
 *  Attn: Prof. Raj Rajkumar
 *  Electrical and Computer Engineering, and Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 *  or via email to raj@ece.cmu.edu
 * 
 * any improvements or extensions that they make and grant Carnegie Mellon
 * the rights to redistribute these changes.
 */
#include <rk/rk_linux.h>
#include <rk/rk_error.h>
#include <rk/rk.h>
#include <rk/timespec.h>
#include <linux/time.h>
#include <asm/processor.h>
#include <asm/uaccess.h>
#include <asm/signal.h>
#ifdef CONFIG_MEASURE
#include <linux/measure.h>
#endif				/* CONFIG_MEASURE */

//#define EARLY_ENFORCE
#define CHECK_TICKET_EXPIRE
#define DELAY 5

extern struct task_struct *expected_current;
int current_critical = 0;

extern struct list_head rk_resource_set_root;
extern void rk_resource_set_schedule(struct rs_proc_list *rs_proc,
				     unsigned int arg);
extern void rk_resource_set_adjust_accounting(void);
extern int cpu_reserve_eligible(rk_reserve_t rsv);

/*
 * Function prototypes
 */
static int cpu_reserve_destroy(rk_reserve_t);
static void cpu_reserve_start_account(rk_reserve_t);
static void cpu_reserve_stop_account(rk_reserve_t, cpu_tick_t);
static void cpu_reserve_replenish(rk_reserve_t, cpu_tick_t, cpu_tick_t);
static void cpu_reserve_enforce(rk_reserve_t);
static void cpu_reserve_sleep_on(rk_reserve_t);
static void cpu_reserve_attach(rk_reserve_t, struct rs_proc_list *);
static void cpu_reserve_detach(rk_reserve_t, struct rs_proc_list *);
static void cpu_reserve_update_ticket(rk_reserve_t, unsigned long);
static void cpu_reserve_ticket_query(rk_reserve_t, unsigned long *);
static void cpu_reserve_wait_one_ticket(rk_reserve_t);
static int cpu_reserve_read_proc(rk_reserve_t, char *);
static void check_enforce_reserve_type(cpu_reserve_attr_t cpu_attr);
static int set_scheduling_policy(int policy);

/* Obtain the rk spinlock before calling these */
void cpu_reserve_sched(struct rs_proc_list *, cpu_reserve_t cpu);
void cpu_reserve_sched_realtime(struct rs_proc_list *,
				unsigned priority_index);
void cpu_reserve_sched_timeshare(struct rs_proc_list *,
				 unsigned priority_index);
void cpu_reserve_sched_timeshare_self(void);

extern void rk_sleep_on(struct wait_queue **p, struct list_head *lhead);

/* static  int rk_cpu_reserves_set_scheduling_policy(int policy); */
/* static  int rk_cpu_reserves_get_num(void);                     */
/* static  int set_scheduling_policy(int policy);                 */
/* static  int rk_cpu_reserves_get_scheduling_policy(void);       */

#define SUPER_CHARGED			1

#ifdef SUPER_CHARGED
#define RATE_MONOTONIC			0
#define DEADLINE_MONOTONIC 		1
#define EDF				2
#define NUM_CPU_RESERVE_POLICIES	(EDF + 1)
#define BLOCKING_PRIORITY               -1

static int cpu_reserves_scheduling_policy = DEADLINE_MONOTONIC;
#endif				/* SUPER_CHARGED */

struct rk_reserve_ops cpu_reserve_ops = {
    cpu_reserve_destroy,
    cpu_reserve_start_account,
    cpu_reserve_stop_account,
    cpu_reserve_replenish,
    cpu_reserve_enforce,
    cpu_reserve_attach,
    cpu_reserve_detach,
#ifdef	linux
    cpu_reserve_sleep_on,
    cpu_reserve_read_proc,
#endif
    cpu_reserve_update_ticket,	/* update the used tickets */
    cpu_reserve_ticket_query,	/* ask for the available tickets */
    cpu_reserve_wait_one_ticket,	/* (wait_on_quota)if no tickets , sleep */
};

#define	CAPACITY_INT(x)		((x)/100)
#define	CAPACITY_FRAC(x)	((x)-(x/100)*100)
#define	INT2CAPACITY(x)		((x)*10000)
#define	CAPACITY2INT(x)		((x)/10000)
#define	PERCENT2CAPACITY(x)	((x)*100)
#define	CAPACITY_OF(c,t)	(INT2CAPACITY(c)/(t))

/*
 *	66% ... is the maximum available capacity for reserves.
 */
#define	CPU_CAPACITY_MAX	PERCENT2CAPACITY(66)

/*
 *
 */
#define cpu_reserve_entry(list)	list_entry((list), struct cpu_reserve, cpu_link)

/*
 * Global variables
 */
struct list_head cpu_reserve_head;
cpu_capacity_t cpu_reserve_current_capacity;

/*
 * More function prototypes
 */
static int admit_reserve_request(cpu_reserve_t cpu);
static void priority_list_add(cpu_reserve_t cpu, struct list_head *head);
static int priority_list_remove(cpu_reserve_t cpu, struct list_head *head);
static int efficient_timespec_ceil(struct timespec dividend,
				   struct timespec divider);
static int ceiling(unsigned long dividend, unsigned long divider);
static int timespec_ceiling(struct timespec dividend,
			    struct timespec divider);
static struct timespec timespec_mult(struct timespec multiplicand,
				     int multiplier);
static struct timespec timespec_mult(struct timespec, int);

/*
 *
 */
void cpu_reserve_init(void)
{
    INIT_LIST_HEAD(&cpu_reserve_head);
    cpu_reserve_current_capacity = 0;
}

rk_reserve_t
cpu_reserve_create(rk_resource_set_t rs, cpu_reserve_attr_t cpu_attr)
{
    rk_reserve_t rsv;
    cpu_reserve_t cpu;
    cpu_capacity_t capacity;
    cpu_capacity_t new_capacity;
    cpu_capacity_quad_t qc, qt, qd;
    cpu_tick_data_t now;
    struct timespec cur_time;

    if (rs == NULL)
	return NULL_RESERVE;

    /* check for validity of "rs" first */
    if (!rk_valid_rset(rs))
	return NULL_RESERVE;

#if 0
    if (rs->rs_cpu) {
	/* pre-existing cpu reserve */
	return NULL_RESERVE;
    }
#endif

#ifdef	DEBUG_RK
    printk
	("cpu_reserve_create: rs(0x%x) c(%d,%d) t(%d,%d) d(%d,%d) mode(%d,%d,%d)",
	 (int) rs, (int) cpu_attr->compute_time.tv_sec,
	 (int) cpu_attr->compute_time.tv_nsec,
	 (int) cpu_attr->period.tv_sec, (int) cpu_attr->period.tv_nsec,
	 (int) cpu_attr->deadline.tv_sec, (int) cpu_attr->deadline.tv_nsec,
	 cpu_attr->reserve_type.enf_mode, cpu_attr->reserve_type.rep_mode,
	 cpu_attr->reserve_type.sch_mode);
#endif

    /* admission control */
    qc = cpu_attr->compute_time.tv_sec;
    qc *= NANOSEC;
    qc += cpu_attr->compute_time.tv_nsec;
    qt = cpu_attr->period.tv_sec;
    qt *= NANOSEC;
    qt += cpu_attr->period.tv_nsec;
    qd = cpu_attr->deadline.tv_sec;
    qd *= NANOSEC;
    qd += cpu_attr->deadline.tv_nsec;

    if (!qt)
	return NULL_RESERVE;

    capacity = CAPACITY_OF(qc, qt);

    /* check for zero reservation */
#if 0
    if (!timespec_nonzero(cpu_attr->compute_time)) {
	/* zero compute time: unacceptable value */
	return NULL_RESERVE;
    }
#endif
    /* check deadline */
    if (timespec_gt(cpu_attr->deadline, cpu_attr->period)) {
	/* deadline cannot be greater than the period */
	return NULL_RESERVE;
    }

    /* check for sane start_time value */
    if (cpu_attr->start_time.tv_nsec >= NANOSEC) {
	return NULL_RESERVE;
    }

    /* create cpu reserve object */
    cpu = malloc(sizeof(struct cpu_reserve));
    bzero(cpu, sizeof(struct cpu_reserve));
    memcpy(&(cpu->cpu_res_attr), cpu_attr,
	   sizeof(cpu_reserve_attr_data_t));
    cpu->cpu_capacity = capacity;

    /* assigned scheduling policy */
    cpu->scheduling_policy = SCHED_FIFO;

    /*
     * EDF stuff: In order to insert the reservation in the list,
     * we have to assign an absolute deadline to it... The correct
     * deadline is Start Time + Deadline.
     * (P.S.: the update in ``replenish'' is no more needed...)
     *                              Luca
     */
    rk_cur_time(&cur_time);
    rk_rdtsc(&now);
    timespec_set(cpu->absdl, cpu_attr->start_time);
    timespec_sub(cpu->absdl, cur_time);
    if (cpu->absdl.tv_sec < 0) {
	cpu->absdl.tv_sec = cpu->absdl.tv_nsec = 0;
    }
    cur_time.tv_sec = TICK2USEC(&now) / 1000000;
    cur_time.tv_nsec = (TICK2USEC(&now) % 1000000) * 1000;
    timespec_add(cpu->absdl, cur_time);
    timespec_add(cpu->absdl, cpu->cpu_res_attr.deadline);

    /* add reservation to reservation list in descending priority 
     * order expecting successful inclusion.
     */
    priority_list_add(cpu, &cpu_reserve_head);

    /* do an admission control test */
    if (!admit_reserve_request(cpu)) {
	/* admission control failed */
	priority_list_remove(cpu, &cpu_reserve_head);
	free(cpu);
	return NULL_RESERVE;	/* error */
    }
#ifdef CONFIG_MEASURE
    measure_newreserve(cpu);
#endif				/* CONFIG_MEASURE */

    new_capacity = capacity + cpu_reserve_current_capacity;
    cpu_reserve_current_capacity = new_capacity;

#ifdef	DEBUG_RK
    printk
	("cpu_reserve_create: capacity(%lu.%02lu) new total(%lu.%02lu)\n",
	 CAPACITY_INT(capacity), CAPACITY_FRAC(capacity),
	 CAPACITY_INT(new_capacity), CAPACITY_FRAC(new_capacity));
#endif

    /* calculate cpu ticks per capacity */
    nanosec2tick(&qt, &cpu->cpu_period_ticks);
    nanosec2tick(&qd, &cpu->cpu_deadline_ticks);
    nanosec2tick(&qc, &cpu->cpu_time_ticks);

#ifdef DEBUG_RK
    printk("c=%d, p=%d\n", (int) cpu->cpu_time_ticks,
	   (int) cpu->cpu_period_ticks);
#endif				/* DEBUG_RK */

    cpu->cpu_period_available_ticks = cpu->cpu_time_ticks;
    cpu->cpu_period_used_ticks = 0;

    /* init waitqueue */
    init_waitqueue(&cpu->depleted_wait);

    /* check reservation type */
    check_enforce_reserve_type(cpu_attr);

    /* create generic reserve object */
    rsv = rk_reserve_create(rs, RSV_CPU);
    rsv->rsv_state = RSV_IS_NULL;
    rsv->rsv_rsv = cpu;
    rsv->rsv_ops = &cpu_reserve_ops;
    rsv->rsv_reserve_param = cpu_attr->reserve_type;
    cpu->rsv = rsv;

    /* Check if this reserve enables tickets */
    if (cpu->cpu_res_attr.ticket_type != DISABLE) {
	cpu->tickets.quota_tickets = cpu->cpu_res_attr.quota_tickets;
	cpu->tickets.ticket_age = cpu->cpu_res_attr.ticket_age;
	cpu->tickets.available_tickets = 0;
	cpu->tickets.expiration = 0;
    }
    init_waitqueue(&cpu->ticket_wait);

    /* create a timer for it */
    /* XXX: we must later have one timer per resource instance in set */
    rk_replenish_timer_create(rsv, cpu_attr->start_time);

    return rsv;			/* success */
}

int cpu_reserve_ctl(rk_reserve_t rsv, cpu_reserve_attr_t cpu_attr)
{
    cpu_reserve_t cpu;
    cpu_reserve_attr_data_t old_local_attr;
    cpu_capacity_t capacity;
    cpu_capacity_t new_capacity, old_capacity;
    cpu_capacity_quad_t qc, qt, qd;
    int admit_ok = FALSE;
    int pos_adjust = FALSE;

    /* check for validity of "rs" first */
    if ((rsv == NULL) || (!rk_valid_rsv(rsv)))
	return -EINVAL;

    if ((void *) (cpu = rsv->rsv_rsv) == NULL_RESERVE)
	return -EINVAL;

    /* check for zero reservation request */
    if (!timespec_nonzero(cpu_attr->compute_time)) {
	/* zero compute time: unacceptable value */
	return -EINVAL;
    }

    /* check deadline */
    if (timespec_gt(cpu_attr->deadline, cpu_attr->period)) {
	/* deadline cannot be greater than the period */
	return -EINVAL;
    }
#ifdef	DEBUG_RK
    printk
	("cpu_reserve_ctl: rsv(0x%x) OLD: c(%ld,%ld) t(%ld,%ld) NEW: c(%ld,%ld) t(%ld,%ld)\n",
	 (int) rsv, cpu->cpu_res_attr.compute_time.tv_sec,
	 cpu->cpu_res_attr.compute_time.tv_nsec,
	 cpu->cpu_res_attr.period.tv_sec, cpu->cpu_res_attr.period.tv_nsec,
	 cpu_attr->compute_time.tv_sec, cpu_attr->compute_time.tv_nsec,
	 cpu_attr->period.tv_sec, cpu_attr->period.tv_nsec);
#endif

    /* calculate a new capacity */
    qc = cpu_attr->compute_time.tv_sec;
    qc *= NANOSEC;
    qc += cpu_attr->compute_time.tv_nsec;
    qt = cpu_attr->period.tv_sec;
    qt *= NANOSEC;
    qt += cpu_attr->period.tv_nsec;
    qd = cpu_attr->deadline.tv_sec;
    qd *= NANOSEC;
    qd += cpu_attr->deadline.tv_nsec;

    capacity = CAPACITY_OF(qc, qt);

    /* save the old parameters */
    memcpy(&old_local_attr, &(cpu->cpu_res_attr),
	   sizeof(cpu_reserve_attr_data_t));
    old_capacity = cpu->cpu_capacity;

    /* load the new parameters */
    memcpy(&(cpu->cpu_res_attr), cpu_attr,
	   sizeof(cpu_reserve_attr_data_t));
    cpu->cpu_capacity = capacity;

    /* we must re-locate the reserve in the list if its period or 
     * deadline changed.
     */

#ifdef SUPER_CHARGED
    {
	int adjust = FALSE;
	switch (cpu_reserves_scheduling_policy) {
	case RATE_MONOTONIC:
	    if (timespec_ne(old_local_attr.period, cpu_attr->period)) {
		adjust = TRUE;
		break;
	    }
	    if ((timespec_eq(old_local_attr.deadline, cpu_attr->deadline))
		&&
		(timespec_ge
		 (old_local_attr.blocking_time, cpu_attr->blocking_time))
		&&
		(timespec_ge
		 (old_local_attr.compute_time, cpu_attr->compute_time))) {
		/* same period, same deadline, less compute time: must be ok */
		admit_ok = TRUE;
	    }
	    break;
	case DEADLINE_MONOTONIC:
	    if (timespec_ne(old_local_attr.deadline, cpu_attr->deadline)) {
		adjust = TRUE;
		break;
	    }
	    if ((timespec_eq(old_local_attr.period, cpu_attr->period)) &&
                (timespec_eq(old_local_attr.deadline, cpu_attr->deadline)) &&
		(timespec_ge(old_local_attr.blocking_time,
			     cpu_attr->blocking_time)) &&
		(timespec_ge(old_local_attr.compute_time,
			     cpu_attr->compute_time))) {
		/* same period, same deadline, less compute time: must be ok */
		admit_ok = TRUE;
	    }
	    break;
	    /* Added the test for EDF: (same as for DM)
	     *                               Luca
	     */
	case EDF:
	    if (timespec_ne(old_local_attr.deadline, cpu_attr->deadline)) {
		adjust = TRUE;
		break;
	    }
	    if ((timespec_eq(old_local_attr.period, cpu_attr->period)) &&
		(timespec_ge(old_local_attr.blocking_time,
			     cpu_attr->blocking_time)) &&
		(timespec_ge(old_local_attr.compute_time,
			     cpu_attr->compute_time))) {
		/* same period, same deadline, less compute time: must be ok */
		admit_ok = TRUE;
	    }
	    break;
	}

	if (adjust) {
	    pos_adjust = TRUE;	/* need this for possible resetting later */
	    priority_list_remove(cpu, &cpu_reserve_head);
	    priority_list_add(cpu, &cpu_reserve_head);
	}
    }
#else				/* SUPER_CHARGED */
    if (timespec_ne(old_local_attr.period, cpu_attr->period)) {
	priority_list_remove(cpu, &cpu_reserve_head);
	priority_list_add(cpu, &cpu_reserve_head);
    }
#endif				/* SUPER_CHARGED */

    /* do a new admission control test */
    if ((!admit_ok) && (!admit_reserve_request(cpu))) {
	/* admission control failed: return to original values */
	memcpy(&(cpu->cpu_res_attr), &old_local_attr,
	       sizeof(cpu_reserve_attr_data_t));
	cpu->cpu_capacity = old_capacity;

	if (pos_adjust) {
	    /* remove and add from list again */
	    priority_list_remove(cpu, &cpu_reserve_head);
	    priority_list_add(cpu, &cpu_reserve_head);
	}
	return RK_ERROR;	/* error since change failed */
    }

    /* available utilization: is this really needed? */
    new_capacity = capacity + cpu_reserve_current_capacity -
	cpu->cpu_capacity;
    cpu_reserve_current_capacity = new_capacity;

#ifdef DEBUG_RK
    printk("cpu_reserve_ctl: capacity(%lu.%02lu) new total(%lu.%02lu)\n",
	   CAPACITY_INT(capacity), CAPACITY_FRAC(capacity),
	   CAPACITY_INT(new_capacity), CAPACITY_FRAC(new_capacity));
#endif				/* DEBUG_RK */

    /* check reservation type */
    check_enforce_reserve_type(cpu_attr);

    {
	unsigned long flags;

	rk_spin_lock(flags);

	/* update reserve parameters */
	rsv->rsv_reserve_param = cpu_attr->reserve_type;

	/* calculate cpu ticks per capacity */
	nanosec2tick(&qt, &cpu->cpu_period_ticks);
	nanosec2tick(&qc, &cpu->cpu_time_ticks);
	nanosec2tick(&qd, &cpu->cpu_deadline_ticks);

	cpu->cpu_period_available_ticks = cpu->cpu_time_ticks;	/* fix 7.5.00 */
	if (cpu->cpu_period_used_ticks > cpu->cpu_time_ticks) {
	    cpu->cpu_period_used_ticks = cpu->cpu_time_ticks - 1;
	}

	rk_spin_unlock(flags);
    }

    /* Check if this reserve enables tickets */
    if (cpu->cpu_res_attr.ticket_type != DISABLE) {
	cpu->tickets.quota_tickets = cpu->cpu_res_attr.quota_tickets;
	cpu->tickets.ticket_age = cpu->cpu_res_attr.ticket_age;
    }

    return RK_SUCCESS;		/* success */
}

static int cpu_reserve_destroy(rk_reserve_t rsv)
{
    cpu_reserve_t cpu = rsv->rsv_rsv;

#ifdef DEBUG_RK
    printk("cpu_reserve_destroy: rsv(0x%x) cpu(0x%x)\n",
	   (int) rsv, (int) cpu);
#endif				/* DEBUG_RK */

    /* destroy timer */
    rk_replenish_timer_destroy(rsv);

#ifdef CONFIG_MEASURE
    measure_endreserve(cpu);
#endif				/* CONFIG_MEASURE */

    /* return capacity */
    cpu_reserve_current_capacity -= cpu->cpu_capacity;
    if ((int) cpu_reserve_current_capacity < 0) {
	cpu_reserve_current_capacity = 0;
    }

    list_del(&cpu->cpu_link);
    INIT_LIST_HEAD(&cpu->cpu_link);	/* for sure */
    kfree(cpu);
    rsv->rsv_rsv = NULL_RESERVE;

    rk_reserve_destroy(rsv);
    return RK_SUCCESS;		/* success */
}

/*
 *
 */
static inline void
cpu_reserve_summation_of_used_ticks(cpu_reserve_t cpu, cpu_tick_t now)
{
    cpu->cpu_period_used_ticks += (*now - cpu->cpu_period_start_ticks);
    cpu->cpu_period_start_ticks = *now;
}

/* 
 * Enable scheduler to make a process eligible for execution.
 */
inline void cpu_reserve_sched_enable(struct rs_proc_list *rs_proc,
				     unsigned int arg)
{
    rs_proc->rs_proc_task->rk_cannot_schedule = FALSE;
    current->need_resched = 1;
}

/* 
 * Disable scheduler from making process eligible for execution.
 */
inline void cpu_reserve_sched_disable(struct rs_proc_list *rs_proc,
				      unsigned int arg)
{
    rs_proc->rs_proc_task->rk_cannot_schedule = TRUE;
    current->need_resched = 1;
}

/*
 * Replenish & Enforce a reserve
 */
/* Add parameter start_ticks which is the start time of each period
 * of the reserve. This is for computing the eligible deadline of 
 * the reserve.
 */
static void
cpu_reserve_replenish(rk_reserve_t rsv, cpu_tick_t period,
		      cpu_tick_t start_ticks)
{
    cpu_reserve_t cpu = rsv->rsv_rsv;
    cpu_capacity_t c;
    long long ticks;
    struct list_head *ptr;
    cpu_reserve_t r;
    int done;
    long flags;

#ifdef PREEMPT_FIX
/* Let's try the Apple fix... */
    int safe_preemption = 0;


    if (current->rk_resource_set == rk_current_resource_set) {
	/* Well.... It can happen that the replenish timer interruptsi
	 * the scheduler - the kernel lock is released immediately before
	 * calling rk_sched_hook :( - in this case, current can be the
	 * previos task, and it is completely wrong to use it :( */
	safe_preemption = 1;
    }
#endif

#ifdef APPLE_DEBUG
    printk("replenish rsv (%x) \n", (unsigned int) rsv);
#endif				/* APPLE_DEBUG */

    rk_spin_lock(flags);

    *period = cpu->cpu_period_ticks;

#ifdef SUPER_CHARGED
    /*
     * This is the terrible thing... For CBS, we do not
     * need replenish here (it only confuses everything...)
     * Luca, FIX IT!!!
     */
    if ((rsv->rsv_reserve_param.enf_mode == RSV_SOFT) &&
	(cpu_reserves_scheduling_policy == EDF)) {
	rk_spin_unlock(flags);
	return;
    }
#endif

    /* update eligible time */
    /* set up the next deadline of the eligible time */
    cpu->cpu_eligible_deadline_ticks =
	*start_ticks + cpu->cpu_deadline_ticks;

    if (rsv->rsv_state & RSV_IS_RUNNING) {
	cpu_tick_data_t now;
	rk_rdtsc(&now);
	cpu_reserve_summation_of_used_ticks(cpu, &now);
#ifdef SUPER_CHARGED
	/*
	 * EDF: We also need to adjust the absolute deadline....
	 * ...for some strange reason, if replenishment and enforcement
	 * should be simultaneous, replenish could raise first...
	 * ...so, IT has to postpone deadline!!!
	 *                      Luca
	 */
	if (cpu_reserves_scheduling_policy == EDF) {

	    timespec_add(cpu->absdl, cpu->cpu_res_attr.deadline);
	    priority_list_remove(cpu, &cpu_reserve_head);
	    priority_list_add(cpu, &cpu_reserve_head);
#ifdef DEBUG_RK
	    printk("Postponing DL: %ld %ld\n",
		   cpu->absdl.tv_sec, cpu->absdl.tv_nsec);
#endif
	    /* Let's set all the priorities in the proper way... */
	    ptr = cpu_reserve_head.next;
	    done = 0;
	    while (!done) {
		r = cpu_reserve_entry(ptr);
		if ((r->rsv->rsv_reserve_param.enf_mode == RSV_SOFT) ||
		    ((r->rsv->rsv_state & RSV_IS_DEPLETED) == 0)) {
		    rs_proc_list_apply(&(r->rsv->rsv_rs->rs_proc_list),
				       cpu_reserve_sched_realtime,
				       r->cpu_priority_index);
		}
		if (cpu_reserve_entry(ptr) == cpu) {
		    done = 1;
		}
		ptr = ptr->next;
	    }

	    current->need_resched = 1;
	}
#endif				/* SUPER_CHARGED */
    }

    /* update statistics */
    cpu->cpu_period_prev_used_ticks = cpu->cpu_period_used_ticks;
    c = CAPACITY_OF(cpu->cpu_period_used_ticks, cpu->cpu_period_ticks);
    if (cpu->cpu_max_utilization < c) {
	cpu->cpu_max_utilization = c;
    }
	else if ((cpu->cpu_min_utilization > c) ||
		 (cpu->cpu_min_utilization == 0)) {
	cpu->cpu_min_utilization = c;
    }
    /* summation for average */
    cpu->cpu_average.total_utils += c;
    cpu->cpu_average.total_count++;

#ifdef DEBUG_RK2
    printk("cpu_reserve_replenish: rsv(0x%x) used(%lu/%lu)\n",
	   (int) rsv,
	   (unsigned long) cpu->cpu_period_used_ticks,
	   (unsigned long) cpu->cpu_period_available_ticks);
#endif				/* DEBUG_RK2 */

    /* refill the capacity */
    switch (rsv->rsv_reserve_param.rep_mode) {
    case RSV_SOFT:
	cpu->cpu_period_available_ticks = cpu->cpu_time_ticks;
	break;
    case RSV_FIRM:
	ticks = cpu->cpu_period_used_ticks - cpu->cpu_time_ticks;
	/* when excessively used */
	if (ticks > 0) {
	    cpu_tick_data_t next;
	    next = cpu->cpu_time_ticks - ticks;
	    if (cpu->cpu_time_ticks >= ticks) {
		cpu->cpu_period_available_ticks = next;
	    } else {
		cpu->cpu_period_available_ticks = 0;
	    }
	} else {
	    cpu->cpu_period_available_ticks = cpu->cpu_time_ticks;
	}
	break;
    case RSV_HARD:
	ticks =
	    cpu->cpu_period_used_ticks - cpu->cpu_period_available_ticks;
	/* when excessively used */
	if (ticks > 0) {
	    cpu_tick_data_t next;
	    next = cpu->cpu_time_ticks - ticks;
	    if (cpu->cpu_time_ticks >= ticks) {
		cpu->cpu_period_available_ticks = next;
	    } else {
		cpu->cpu_period_available_ticks = 0;
	    }
	} else {
	    cpu->cpu_period_available_ticks = cpu->cpu_time_ticks;
	}
	break;
    default:
	printk("replenish: unknown rep mode!\n");
	break;
    }

    /* reset the used ticks */
    cpu->cpu_period_used_ticks = 0;

#ifdef DEBUG_RK2
    printk
	("cpu_reserve_replenish: rsv(0x%x) state(%x) next available(%lu)\n",
	 (int) rsv, (int) rsv->rsv_state,
	 (unsigned long) cpu->cpu_period_available_ticks);
#endif				/* DEBUG_RK2 */

    /* issue tickets */
    switch (cpu->cpu_res_attr.ticket_type) {
    case CONSTANT:
	cpu->tickets.available_tickets = cpu->tickets.quota_tickets;
	cpu->tickets.expiration = *start_ticks + cpu->tickets.ticket_age;
	wake_up(&cpu->ticket_wait);
	break;
    default:
	cpu->tickets.available_tickets = 0;	/* disable other types at this moment */
	break;
    }

    if (rsv->rsv_state & RSV_IS_DEPLETED)
	rsv->rsv_state &= ~RSV_IS_DEPLETED;

    /* update cpu reserve of the resource set */
    {
	rk_reserve_t rk_resource_set_update_cpu(rk_resource_set_t);
	rk_resource_set_update_cpu(rsv->rsv_rs);
    }
    if (rsv->rsv_rs->rs_cpu) {
	rs_proc_list_apply(&rsv->rsv_rs->rs_proc_list,
			   rk_resource_set_schedule, 0);
    }

#ifdef PREEMPT_FIX
    if (safe_preemption) {
#endif
	/* Make sure the enforcement timer is set */
	/* stop old accounting */
	if (rk_current_cpu_reserve) {
	    cpu_tick_data_t now;

	    rk_rdtsc(&now);
	    rk_current_cpu_reserve->rsv_ops->
		stop_account(rk_current_cpu_reserve, &now);
	}
#ifndef PREEMPT_FIX
/* This is critical; if current is not the same as expected current,
         * we shouldn't touch anything to rk_current_resource_set yet -Apple */
        if ((expected_current != (void *) -1) &&
            (expected_current != current)) {
#ifdef APPLE_DEBUG_RK
          printk("Danger interrupt (replenish rsv(0x%x)) during schedule: data in sync current (%d) but expect (%d)\n", (int) rsv, current->pid, expected_current->pid);
#endif APPLE_DEBUG_RK
          current_critical = 1;
        } else current_critical = 0;
        if (!current_critical) {
#endif
	/* update rk_current_resource_set and rk_current_cpu_reserve */

	rk_current_resource_set = current->rk_resource_set;
	if (rk_current_resource_set) {
	    rk_current_cpu_reserve = current->rk_resource_set->rs_cpu;
	    /* start new accounting */
	    if (rk_current_cpu_reserve) {
		rk_current_cpu_reserve->rsv_ops->
		    start_account(rk_current_cpu_reserve);
	    }
	} else {
	    rk_current_cpu_reserve = NULL_RESERVE;
	}
    }
#ifndef PREEMPT_FIX
      else {
       /* update rk_current_resource_set and rk_current_cpu_reserve */
        rk_current_resource_set = expected_current->rk_resource_set;
        if (rk_current_resource_set) {
          rk_current_cpu_reserve = expected_current->rk_resource_set->rs_cpu;
          /* start new accounting */
          if (rk_current_cpu_reserve) {
            rk_current_cpu_reserve->rsv_ops->start_account(rk_current_cpu_reserve);
          }
        }
        else {
          rk_current_cpu_reserve = NULL_RESERVE;
        }
    }
#endif
    
    rk_spin_unlock(flags);
}

void signal_tasks(struct rs_proc_list *rs_proc,
		  unsigned int priority_index);

static void cpu_reserve_enforce(rk_reserve_t rsv)
{
    rk_resource_set_t rs;
    struct list_head *ptr;
    cpu_reserve_t cpu = rsv->rsv_rsv;
    cpu_reserve_t r;
    int done;
    long flags;


    rk_spin_lock(flags);

    if (!(rsv->rsv_state & RSV_IS_DEPLETED)) {
#ifdef DEBUG_RK2
#ifdef DEBUG_RK_ENFORCE
	debug_rk_enforce_flag = 1;
#endif				/* DEBUG_RK_ENFORCE */
	printk("cpu_reserve_enforce: rsv(0x%x)\n", (int) rsv);
#endif				/* DEBUG_RK2 */
	rsv->rsv_state |= RSV_IS_DEPLETED;
    }
#ifdef SUPER_CHARGED
    /*
     * EDF: Let's update the absolute deadline!!!
     * Simply increase by the period...
     *              Luca
     */
    if (cpu_reserves_scheduling_policy == EDF) {
	/* set up the next deadline of the eligible time */
	cpu->cpu_eligible_deadline_ticks += cpu->cpu_deadline_ticks;
	timespec_add(cpu->absdl, cpu->cpu_res_attr.period);

#ifdef DEBUG_RK
	{
	    struct timespec now;
	    rk_cur_time(&now);
	    printk
		("[%d] 0x%x: Postponing deadline at %d %d | Time %ld %ld\n",
		 current->pid, rsv->rsv_rs, cpu->absdl.tv_sec,
		 cpu->absdl.tv_nsec, now.tv_sec, now.tv_nsec);
	}
#endif
	priority_list_remove(cpu, &cpu_reserve_head);
	priority_list_add(cpu, &cpu_reserve_head);

	/* Let's update the kernel priorities in the proper way */
	ptr = cpu_reserve_head.next;
	done = 0;
	while (!done) {
	    r = cpu_reserve_entry(ptr);
	    if ((r->rsv->rsv_reserve_param.enf_mode == RSV_SOFT) ||
		((r->rsv->rsv_state & RSV_IS_DEPLETED) == 0)) {
		rsv->rsv_state &= ~RSV_IS_DEPLETED;
		rs_proc_list_condition_rs_apply(&
						(r->rsv->rsv_rs->
						 rs_proc_list),
						r->rsv->rsv_rs,
						cpu_reserve_sched, r);
		rsv->rsv_state |= RSV_IS_DEPLETED;
	    }
	    if (cpu_reserve_entry(ptr) == cpu) {
		done = 1;
	    }
	    ptr = ptr->next;
	}
	current->need_resched = 1;
    }
#endif				/* SUPER_CHARGED */

    /* cancel tickets */
    {
	cpu_reserve_t cpu = rsv->rsv_rsv;
	cpu->tickets.available_tickets = 0;
    }

    /* Notify the enforcement to process through a RT signal */
    //rs_proc_list_apply(&rsv->rsv_rs->rs_proc_list, signal_tasks, 0);


#ifdef SUPER_CHARGED
    if (cpu_reserves_scheduling_policy == EDF) {
	if (rsv->rsv_reserve_param.enf_mode == RSV_SOFT) {	/* CBS!!! */
	    if (rsv->rsv_state & RSV_IS_RUNNING) {
		cpu_tick_data_t now;

		rk_rdtsc(&now);
		cpu->cpu_period_available_ticks = cpu->cpu_time_ticks;
		cpu->cpu_period_used_ticks = 0;
		cpu_reserve_stop_account(rsv, &now);
		rsv->rsv_state &= ~RSV_IS_DEPLETED;
		cpu->cpu_period_available_ticks = cpu->cpu_time_ticks;
		cpu->cpu_period_used_ticks = 0;
		ptr = cpu_reserve_head.next;
	    }
	    rsv->rsv_state &= ~RSV_IS_DEPLETED;
	}
    }
#endif

    rs = rsv->rsv_rs;

    /* update the current cpu of the resource set */
    {
	rk_reserve_t rk_resource_set_update_cpu(rk_resource_set_t);
	rk_resource_set_update_cpu(rs);
    }
    /* If this resource set is still eligible,
     * we can just update the scheduling parameters of all tasks bound
     * to this resource set using the new cpu reserve
     */
    if (rs->rs_cpu) {

	rs_proc_list_condition_rs_apply(&rs->rs_proc_list,
					rs,
					cpu_reserve_sched,
					(cpu_reserve_t) (rs->rs_cpu->
							 rsv_rsv));
    }
    /* This resource set is not eligible, each task that uses this resource
     * set needs to reschedule another resource set */
    else {
	rs_proc_list_condition_rs_apply(&rs->rs_proc_list,
					rs, rk_resource_set_schedule, 0);
    }


    /* If there is an update of the current reserve of the current task,
     * adjust the accounting of the current resource set if there is 
     * a change */
     if ((expected_current!=(void *)-1) && (expected_current!=current)) {
#ifdef APPLE_DEBUG_RK
          printk("Danger Interrupt (enforce -rsv (0x%x)) during scheduling: current (%d) but expect (%d) \n", rsv, current->pid, expected_current->pid);
#endif APPLE_DEBUG_RK
        current_critical = 1;
    } else {
        current_critical = 0;
    }
    if (current_critical) {
        extern void rk_resource_set_adjust_expect_accounting(void);
        rk_resource_set_adjust_expect_accounting();
    } else {
        rk_resource_set_adjust_accounting();
    }

    rk_spin_unlock(flags);
}

static void cpu_reserve_sleep_on(rk_reserve_t rsv)
{
#if 0
    cpu_reserve_t cpu = rsv->rsv_rsv;

//      interruptible_sleep_on(&cpu->depleted_wait);
    list_entry(rsv->rsv_rs->rs_proc_list.next, struct rs_proc_list,
	       rs_proc_list)->rs_proc_task->state = TASK_INTERRUPTIBLE;
    schedule();

#else				/* RAJ_RK */
    rs_proc_list_apply(&rsv->rsv_rs->rs_proc_list,
		       cpu_reserve_sched_disable, 0);

    /* re-schedule */
    schedule();
#endif				/* RAJ_RK */
}

/*
 * Start & Stop the account of CPU utilization.
 */
static void cpu_reserve_start_account(rk_reserve_t rsv)
{
    cpu_reserve_t cpu = rsv->rsv_rsv;
    long long next;
    long long eligible_ticks;
    int no_more_eligible = 0;

    if (cpu->cpu_period_available_ticks < cpu->cpu_period_used_ticks) {
	cpu->cpu_period_used_ticks = cpu->cpu_period_available_ticks - DELAY;
    }
    next = cpu->cpu_period_available_ticks - cpu->cpu_period_used_ticks;

#ifdef SUPER_CHARGED
    if ((cpu_reserves_scheduling_policy == EDF) &&
	(rsv->rsv_reserve_param.enf_mode == RSV_SOFT)) {
    } else
#endif
    {
	/* check the eligible_ticks */
	cpu_tick_data_t now;
	rk_rdtsc(&now);
	eligible_ticks = cpu->cpu_eligible_deadline_ticks - now;
	if (eligible_ticks < next) {
	    no_more_eligible = 1;
	    next = eligible_ticks;
	}
    }

    switch (rsv->rsv_state) {
    case RSV_IS_NULL:
	printk
	    ("cpu_reserve_start_account: rsv(0x%x) illegal state(NULL)\n",
	     (int) rsv);
    case RSV_IS_STARTED:

	rsv->rsv_state |= RSV_IS_RUNNING;
	if (next > DELAY) {
	    rk_enforce_timer_start(rsv, &next,
				   &cpu->cpu_period_start_ticks);
	} else {
            if (!no_more_eligible) {
                /* Just to avoid useless warnings... */
#ifdef EXTRA_WARN
	        printk("start_account with no time left, but not depleted?\n");
#endif
            }
#ifdef EARLY_ENFORCE
	    rsv->rsv_state |= RSV_IS_DEPLETED;
	    /*should do enforcement */
	    cpu_reserve_enforce(rsv);
#else
	    next = DELAY;		/* Very small value... */
	    rk_enforce_timer_start(rsv, &next,
				   &cpu->cpu_period_start_ticks);
#endif
	}
	break;
    case RSV_IS_RUNNING | RSV_IS_STARTED:	/* must not be so */
    case RSV_IS_RUNNING:	/* must not be so */
	printk
	    ("cpu_reserve_start_account: rsv(0x%x) illegal state(RUNNING)\n",
	     (int) rsv);
	if (next > 0) {
	    rk_enforce_timer_start(rsv, &next,
				   &cpu->cpu_period_start_ticks);
	} else {
	    rsv->rsv_state |= RSV_IS_DEPLETED;
	    rk_rdtsc(&cpu->cpu_period_start_ticks);
	}
	break;

    case RSV_IS_RUNNING | RSV_IS_DEPLETED:	/* must not be so */
    case RSV_IS_STARTED | RSV_IS_RUNNING | RSV_IS_DEPLETED:	/* must not be so */
	printk
	    ("cpu_reserve_start_account: rsv(0x%x) illegal state(RUNNING|DEPLETED)\n",
	     (int) rsv);
	break;

    default:			/* unknown */
	printk
	    ("cpu_reserve_start_account: rsv(0x%x) unknown state(0x%x) next available(%lu)\n",
	     (int) rsv, (int) rsv->rsv_state, (unsigned long) next);
	rsv->rsv_state = RSV_IS_RUNNING;
	if (next > 0) {
	    rk_enforce_timer_start(rsv, &next,
				   &cpu->cpu_period_start_ticks);
	} else {
	    rsv->rsv_state |= RSV_IS_DEPLETED;
	    rk_rdtsc(&cpu->cpu_period_start_ticks);
	}
	break;
    }
}


static inline void
cpu_reserve_check_enforce(rk_reserve_t rsv, cpu_reserve_t cpu,
			  cpu_tick_t now)
{
    if (cpu->cpu_period_used_ticks >= cpu->cpu_period_available_ticks) {
#ifdef DEBUG_RK
	printk
	    ("cpu_reserve_check_enforce: enforce rsv(0x%x) used(%lu/%lu)\n",
	     (int) rsv, (unsigned long) cpu->cpu_period_used_ticks,
	     (unsigned long) cpu->cpu_period_available_ticks);
#endif				/* DEBUG_RK */
	/* enforcing a reserve */
#ifdef  EARLY_ENFORCE
	cpu_reserve_enforce(rsv);
#else
#ifdef EXTRA_WARN
	printk("Early enforcing disabled\n");
#endif
#endif
    }
#ifdef SUPER_CHARGED
    if ((cpu_reserves_scheduling_policy == EDF) &&
	(rsv->rsv_reserve_param.enf_mode == RSV_SOFT)) {
    } else
#endif
	/* If eligible? */
    if (*now >= cpu->cpu_eligible_deadline_ticks) {
#ifdef DEBUG_RK
	printk
	    ("cpu_reserve_check_enforce: enforce rsv(0x%x) used(%lu/%lu) eligible(%lu) time(%lu)-eligible \n",
	     (int) rsv, (unsigned long) cpu->cpu_period_used_ticks,
	     (unsigned long) cpu->cpu_period_available_ticks,
	     (unsigned long) cpu->cpu_eligible_deadline_ticks,
	     (unsigned long) *now);
#endif				/* DEBUG_RK */
#ifdef EARLY_ENFORCING
	/* enforcing a reserve */
	cpu_reserve_enforce(rsv);
#else
	cpu->cpu_period_used_ticks = cpu->cpu_period_available_ticks - 1;
#endif
	return;
    }
}

static void cpu_reserve_stop_account(rk_reserve_t rsv, cpu_tick_t now)
{
    cpu_reserve_t cpu = rsv->rsv_rsv;

    cpu_reserve_summation_of_used_ticks(cpu, now);
    rk_enforce_timer_cancel();

    if (rsv == rk_current_cpu_reserve)
	rk_current_cpu_reserve = NULL_RESERVE;

    switch (rsv->rsv_state) {
    case RSV_IS_RUNNING:
    case RSV_IS_STARTED | RSV_IS_RUNNING:
	/* Original... */
	rsv->rsv_state &= ~RSV_IS_RUNNING;
	cpu_reserve_check_enforce(rsv, cpu, now);
	break;
    case RSV_IS_RUNNING | RSV_IS_DEPLETED:
    case RSV_IS_STARTED | RSV_IS_RUNNING | RSV_IS_DEPLETED:
	rsv->rsv_state &= ~RSV_IS_RUNNING;
	break;
    case RSV_IS_NULL:		/* must not be so */
    case RSV_IS_STARTED:	/* must not be so */
	printk("cpu_reserve_stop_account: rsv(0x%x) illegal state(NULL)\n",
	       (int) rsv);
	cpu_reserve_check_enforce(rsv, cpu, now);
	break;
    case RSV_IS_DEPLETED:	/* must not be so */
    case RSV_IS_STARTED | RSV_IS_DEPLETED:	/* must not be so */
	printk
	    ("cpu_reserve_stop_account: rsv(0x%x) illegal state(NULL|DEPLETED)\n",
	     (int) rsv);
	break;
    default:			/* unkown */
	printk
	    ("cpu_reserve_stop_account: rsv(0x%x) unknown state(0x%x))\n",
	     (int) rsv, (int) rsv->rsv_state);
	rsv->rsv_state = RSV_IS_NULL;
	cpu_reserve_check_enforce(rsv, cpu, now);
	break;
    }
}

static void
cpu_reserve_attach(rk_reserve_t rsv, struct rs_proc_list *rs_proc)
{
    unsigned long flags;
#ifdef CONFIG
    measure_reserv_attach_process(rsv, rs_proc->rs_proc_task->pid);
#endif				/* CONFIG */

#ifdef DEBUG_RK
    printk("(attach)");
#endif				/* DEBUG_RK */

    if (!cpu_reserve_eligible(rsv)) {
	/* something wrong */
	rs_proc->rs_proc_task->rk_cannot_schedule = TRUE;
	printk("(depleted)");
	cpu_reserve_enforce(rsv);
	return;
    }
    rk_spin_lock(flags);
    cpu_reserve_sched(rs_proc, (cpu_reserve_t) rsv->rsv_rsv);
    rk_spin_unlock(flags);
}

static void
cpu_reserve_detach(rk_reserve_t rsv, struct rs_proc_list *rs_proc)
{
    unsigned long flags;

    rk_spin_lock(flags);

    /* Avoid crashes when a RS is destroyed byt the timer is still active */
    if (rs_proc->rs_proc_task->period_timer != NULL) {
	rs_proc->rs_proc_task->period_timer->tmr_rsv = NULL_RESERVE;
    }

    rk_spin_unlock(flags);

#ifdef CONFIG
    measure_reserv_detach_process(rsv, rs_proc->rs_proc_task->pid);
#endif				/* CONFIG */
}

static void
cpu_reserve_update_ticket(rk_reserve_t rsv, unsigned long tickets)
{
    cpu_tick_data_t now;
    cpu_reserve_t cpu = rsv->rsv_rsv;

    rk_rdtsc(&now);
    switch (cpu->cpu_res_attr.ticket_type) {
    case CONSTANT:
	/* If there is not enough tickets */
	if (cpu->tickets.available_tickets < tickets) {
	    /* Something wrong! */
	    printk("Someone is using tikcets over the quota \n");
	    cpu->tickets.available_tickets = 0;
	    return;
	}
	/* Tickets are expired */
	if (now > cpu->tickets.expiration) {
	    printk("Tickets are expired, throw them away \n");
	    cpu->tickets.available_tickets = 0;
	    return;
	}
	cpu->tickets.available_tickets -= tickets;
	break;
    default:
	/* Something wrong! */
	printk("Someone is using tikcets w/o permission \n");
	cpu->tickets.available_tickets = 0;
	break;
    }
}

static void
cpu_reserve_ticket_query(rk_reserve_t rsv, unsigned long *tickets)
{
    cpu_tick_data_t now;
    cpu_reserve_t cpu = rsv->rsv_rsv;
    rk_rdtsc(&now);
    switch (cpu->cpu_res_attr.ticket_type) {
    case CONSTANT:
	/* Tickets are expired */
	if (now > cpu->tickets.expiration) {
	    printk("Tickets are expired, throw them away \n");
	    cpu->tickets.available_tickets = 0;
	}

	*tickets = cpu->tickets.available_tickets;
	break;
    default:
	/* Something wrong! */
	printk("Someone is using tikcets w/o permission \n");
	*tickets = 0;
	break;
    }
}

static void cpu_reserve_wait_one_ticket(rk_reserve_t rsv)
{
    cpu_tick_data_t now;
    struct wait_queue wait = { current, NULL };
    cpu_reserve_t cpu = rsv->rsv_rsv;

    rk_rdtsc(&now);
    if ((cpu->tickets.available_tickets)
#ifdef CHECK_TICKET_EXPIRE
	&& (now <= cpu->tickets.expiration)
#endif /* CHECK_TICKET_EXPIRE */
	) {
	
	cpu->tickets.available_tickets--;
	return;
    }
    add_wait_queue(&cpu->ticket_wait, &wait);
    while (1) {
	current->state = TASK_INTERRUPTIBLE;
	rk_rdtsc(&now);
	if ((cpu->tickets.available_tickets)
#ifdef CHECK_TICKET_EXPIRE
	    && (now <= cpu->tickets.expiration)
#endif /* CHECK_TICKET_EXPIRE */
	    ) {
	    cpu->tickets.available_tickets--;
	    break;
	}
	schedule();
    }
    remove_wait_queue(&cpu->ticket_wait, &wait);
    current->state = TASK_RUNNING;
}


/*
 * admission control for CPU reserves
 */
int admit_reserve_request(cpu_reserve_t cpu)
{
    struct timespec completion_time, prev_completion_time;
    struct timespec result;
    cpu_reserve_t curr, r;
    int ceil_value;
    cpu_reserve_attr_t attr = &(cpu->cpu_res_attr);
    struct list_head *ptr, *p2;
    /* This are used by the EDF capacity-based guarantee */
    cpu_capacity_t guarcap;
    cpu_capacity_quad_t qc, qt;

#ifdef DEBUG_RK
    printk("admit_reserve_request: ");
#endif				/* DEBUG_RK */

    guarcap = PERCENT2CAPACITY(0);

    /* the admission control policy for a reserve is as follows.
     * We check the completion times of the incoming reserve and ALL
     * lower priority reserves assuming that the reserve is admitted.
     * If the completion times of all these reserves are less than their
     * respective deadlines, then the incoming reserve can be admitted.
     */

#ifdef LOG_RESERVES
    if (log_messages) {
	log_start = clock_ttime(clockrt);
    }
#endif				/* LOG_RESERVES */

    /* do basic checks quickly */
    if (timespec_gt(attr->compute_time, attr->period) ||
	timespec_gt(attr->compute_time, attr->deadline)) {
#ifdef DEBUG_RK
	printk("false (0)\n");
#endif				/* DEBUG_RK */
	return FALSE;
    }

    /* perform the "completion time test" */
    for (ptr = cpu_reserve_head.next; ptr != &cpu_reserve_head;
	 ptr = ptr->next) {
	cpu_reserve_attr_t curr_attr;

	curr = cpu_reserve_entry(ptr);
	curr_attr = &(curr->cpu_res_attr);

	/* repeat for each reserve in the current set of reserves */

	/* Optimization: skip reserves with shorter deadlines for
	 *   deadline-monotonic scheduling policy or with shorter periods for
	 *   rate-monotonic scheduling.
	 */
#ifdef SUPER_CHARGED
	{
	    int cont = FALSE;
	    switch (cpu_reserves_scheduling_policy) {
	    case RATE_MONOTONIC:
		if (timespec_lt(curr_attr->period, attr->period)) {
		    /* shorter period reservation: must have been tested earlier */
		    cont = TRUE;
		}
		break;
	    case DEADLINE_MONOTONIC:
		if (timespec_lt(curr_attr->deadline, attr->deadline)) {
		    /* shorter deadline reservation: must have been tested earlier */
		    cont = TRUE;
		}
		break;
	    case EDF:
		/* The EDF admission control uses the simple test Sum(Ci/Di) < 1
		 *                      Luca
		 */
		qc = curr_attr->compute_time.tv_sec;
		qc *= NANOSEC;
		qc += curr_attr->compute_time.tv_nsec;
		qt = curr_attr->period.tv_sec;
		qt *= NANOSEC;
		qt += curr_attr->period.tv_nsec;

		guarcap += CAPACITY_OF(qc, qt);
		if (guarcap > PERCENT2CAPACITY(100))
		    return FALSE;
		cont = TRUE;
		break;
	    }
	    if (cont)
		continue;
	}
#else				/* SUPER_CHARGED */
	if (timespec_lt(curr_attr->period, attr->period)) {
	    /* shorter period reservation: must have been tested earlier */
	    continue;
	}
#endif				/* SUPER_CHARGED */

	timespec_zero(prev_completion_time);
	timespec_set(completion_time, curr_attr->compute_time);
	timespec_add(completion_time, curr_attr->blocking_time);

	/* calculate the worst-case completion time */
	while (timespec_le(prev_completion_time, curr_attr->deadline) &&
	       timespec_lt(prev_completion_time, completion_time)) {
	    timespec_set(prev_completion_time, completion_time);
	    timespec_zero(completion_time);

	    for (p2 = cpu_reserve_head.next;
		 p2 != &cpu_reserve_head; p2 = p2->next) {
		cpu_reserve_attr_t r_attr;

		r = cpu_reserve_entry(p2);

		/* We compute preemption time from the HIGHER priority reserves and
		 * any EQUAL priority reserves.  This is necessary because the
		 * deadlines can be different for reserves with the same period.
		 */
		if (r == curr) {
		    /* self */
		    continue;
		}

		r_attr = &(r->cpu_res_attr);

#ifdef SUPER_CHARGED
		{
		    int done = FALSE;
		    switch (cpu_reserves_scheduling_policy) {
		    case RATE_MONOTONIC:
			if (timespec_gt(r_attr->period, curr_attr->period)) {
			    done = TRUE;
			}
			break;
		    case DEADLINE_MONOTONIC:
			if (timespec_gt
			    (r_attr->deadline, curr_attr->deadline)) {
			    /* we have found a reserve with a longer period/deadline and
			     * therefore a lower priority, break from loop */
			    done = TRUE;
			}
			break;
		    }
		    if (done)
			break;
		}
#else				/* SUPER_CHARGED */
		if (timespec_gt(r_attr->period, curr_attr->period))
		    break;
#endif				/* SUPER_CHARGED */

		ceil_value = efficient_timespec_ceil(prev_completion_time,
						     r_attr->period);
		result = timespec_mult(r_attr->compute_time, ceil_value);
		timespec_add(completion_time, result);
	    }

	    /* add computation time and blocking time of self */
	    timespec_add(completion_time, curr_attr->compute_time);
	    timespec_add(completion_time, curr_attr->blocking_time);
	}			/* end while */

	if (timespec_gt(completion_time, curr_attr->period) ||
	    timespec_gt(completion_time, curr_attr->deadline)) {
	    /* deadline already missed; return failure */
#ifdef DEBUG_RK
	    printk("false\n");
#endif				/* DEBUG_RK */
	    return FALSE;
	}
    }

#ifdef LOG_RESERVES
    if (log_messages) {
	log_end = clock_ttime(clockrt);
	timespec_sub(log_end, log_start);
	sprintf(LINEA, " admission control %d %d \n", log_end.seconds,
		log_end.nanoseconds);
	kern_msg_log(LINEA);
    }
#endif				/* LOG_RESERVES */

    /* everything seems fine */
#ifdef DEBUG_RK
    printk("true\n");
#endif				/* DEBUG_RK */

    return TRUE;
}

int cpu_reserve_delete(rk_resource_set_t rs)
{
    rk_reserve_t rsv;
    cpu_reserve_t cpu;

    /* check validity of "rs" first */
    if ((rs == NULL) || (!rk_valid_rset(rs)))
	return RK_ERROR;
    rsv = rs->rs_cpu;
    if (rsv == NULL)
	return RK_ERROR;

    /* get cpu reserve */
    cpu = rsv->rsv_rsv;

#ifdef DEBUG_RK
    printk("cpu_reserve_delete: cpu(0x%x)\n", (int) cpu);
#endif				/* DEBUG_RK */

    /* destroy timer */
    rk_replenish_timer_destroy(rsv);

    /* return capacity */
    cpu_reserve_current_capacity -= cpu->cpu_capacity;
    if ((int) cpu_reserve_current_capacity < 0) {
	cpu_reserve_current_capacity = 0;
    }
#ifdef CONFIG_MEASURE
    measure_endreserve(cpu);
#endif				/* CONFIG_MEASURE */

    list_del(&cpu->cpu_link);
    INIT_LIST_HEAD(&cpu->cpu_link);	/* for sure */
    rsv->rsv_rsv = NULL_RESERVE;
    kfree(cpu);

    rk_reserve_destroy(rsv);
    return RK_SUCCESS;		/* success */
}

/*
 * Linux-specific
 */
#ifdef	linux

/*
 * Notify enforcements to tasks through the first Linux RT signal
 */
void signal_tasks(struct rs_proc_list *rs_proc, unsigned int arg)
{
    struct siginfo info;
    struct task_struct *p;
    rk_resource_set_t rs;
    rk_reserve_t rsv;
    cpu_reserve_t cpu;
    struct timespec err;
    int l;

    p = rs_proc->rs_proc_task;
    rs = p->rk_resource_set;
    if (rs == NULL) {
	printk("signlal_tasks: NULL RS\n");
	return;
    }
    rsv = rs->rs_cpu;
    if (rsv == NULL) {
	printk("signlal_tasks: NULL rs_cpu\n");
	return;
    }

    cpu = rsv->rsv_rsv;
    if (cpu == NULL) {
	printk("signlal_tasks: NULL cpu\n");
	return;
    }
    timespec_set(err, cpu->absdl);
#ifdef DEBUG_RK_SIGNAL
    printk("lastdl %ld %ld\n", cpu->absdl.tv_sec, cpu->absdl.tv_nsec);
    printk("lastarrv %ld %ld\n", current->last_start.tv_sec,
	   current->last_start.tv_nsec);
#endif
    timespec_sub(err, current->last_start);
    l = timespec2micro(err);
#ifdef DEBUG_RK_SIGNAL
    printk("Signaling task %d\n", p);
#endif
    memset(&info, 0, sizeof(info));

    info.si_signo = SIGRTMIN + 1 + ENFORCE_SIGNAL;
/*    info.si_signo = SIGRTMIN + 1; */
    info.si_errno = 0;
    info.si_code = SI_KERNEL;
    info.si_pid = 0;
    info.si_uid = 0;
    info._sifields._rt._sigval.sival_int = l;

    send_sig_info(SIGRTMIN + 1 + ENFORCE_SIGNAL, &info, p);
}


/*
 * Linux proc file system interface
 */
asmlinkage int
sys_rk_blocked(int pid)
{
  struct task_struct *tsk = __rk_find_process_by_pid(pid);
  if (tsk != NULL)
    {
#ifdef DEBUG_RK
      printk("rk_blocked: pid found cannot_sched = %d\n",tsk->rk_cannot_schedule);
#endif
      return tsk->rk_cannot_schedule;
    }
  printk("rk_blocked: pid not found\n");
  return -1;
}


asmlinkage rk_reserve_t
sys_rk_cpu_reserve_create(rk_resource_set_t rs,
			  cpu_reserve_attr_t cpu_attr)
{
    cpu_reserve_attr_data_t local_attr;

#ifdef DEBUG_RK
    printk("cpu_rsv_create: rs(0x%x)\n", (int) rs);
#endif				/* DEBUG_RK */

    /* check region before access */
    if ((!cpu_attr) || (verify_area(VERIFY_READ, cpu_attr,
				    sizeof(cpu_reserve_attr_data_t)))) {
	return NULL_RESERVE;
    }
    if (copy_from_user(&local_attr, cpu_attr,
		       sizeof(cpu_reserve_attr_data_t))) {
	return NULL_RESERVE;
    }

    return cpu_reserve_create(rs, &local_attr);
}

asmlinkage int
sys_rk_cpu_reserve_ctl(rk_reserve_t rsv, cpu_reserve_attr_t cpu_attr)
{
    cpu_reserve_attr_data_t local_attr;

#ifdef DEBUG_RK
    printk("cpu_rsv_ctl: rsv(0x%x)\n", (int) rsv);
#endif				/* DEBUG_RK */

    if (copy_from_user(&local_attr, cpu_attr,
		       sizeof(cpu_reserve_attr_data_t))) {
	return -EFAULT;
    }

    return cpu_reserve_ctl(rsv, &local_attr);
}

asmlinkage int sys_rk_cpu_reserve_delete(rk_resource_set_t rs)
{
#ifdef DEBUG_RK
    printk("cpu_rsv_delete: rs(0x%x)\n", (int) rs);
#endif				/* DEBUG_RK */
    return cpu_reserve_delete(rs);
}

asmlinkage int sys_rk_cpu_reserves_set_scheduling_policy(int policy)
{
#ifdef DEBUG_RK
    printk("cpu_rsv_set_sch: pol(0x%x)\n", (int) policy);
#endif				/* DEBUG_RK */
    return rk_cpu_reserves_set_scheduling_policy(policy);
}

asmlinkage int sys_rk_cpu_reserves_get_scheduling_policy(void)
{
#ifdef DEBUG_RK
    printk("cpu_rsv_get_sch ");
#endif				/* DEBUG_RK */
    return rk_cpu_reserves_get_scheduling_policy();
}

asmlinkage int sys_rk_cpu_reserves_get_num(void)
{
#ifdef DEBUG_RK
    printk("cpu_rsv_get_num ");
#endif				/* DEBUG_RK */
    return rk_cpu_reserves_get_num();
}

asmlinkage int sys_rk_cpu_reserves_get_list(rk_reserve_t * rsv, int size)
{
    cpu_reserve_t cpu;
    struct list_head *e;
    int local_count, i;

#ifdef DEBUG_RK
    printk("cpu_rsv_get_list: rsv(0x%x) size %d\n", rsv, size);
#endif				/* DEBUG_RK */

    local_count = rk_cpu_reserves_get_num() * sizeof(rk_reserve_t);

    if (size < local_count)
	return -EINVAL;

    if (verify_area(VERIFY_WRITE, rsv, local_count)) {
	return -EFAULT;
    }

    /* copy known cpu reserves to list */
    for (e = cpu_reserve_head.next, i = 0; e != &cpu_reserve_head;
	 e = e->next, i++) {
	cpu = cpu_reserve_entry(e);

	/* this must be changed for reserves other than CPU */
	if (copy_to_user(&(rsv[i]), &(cpu->rsv), sizeof(rk_reserve_t))) {
	    return -EFAULT;
	}
    }

    return rk_cpu_reserves_get_num();
}

asmlinkage int
sys_rk_cpu_reserve_get_attr(rk_reserve_t rsv,
			    cpu_reserve_attr_t cpu_params)
{
    cpu_reserve_t cpu;

#ifdef DEBUG_RK
    printk("cpu_rsv_get_attr: rsv(0x%x)\n", rsv);
#endif				/* DEBUG_RK */

    /* verify validity of reserve first */
    if (!rk_valid_rsv(rsv))
	return -EINVAL;

    /* check region before access */
    cpu = rsv->rsv_rsv;
    if ((!cpu) || (verify_area(VERIFY_WRITE, cpu_params,
			       sizeof(cpu_reserve_attr_data_t)))) {
	return -EFAULT;
    }
    if (copy_to_user(cpu_params, &(cpu->cpu_res_attr),
		     sizeof(cpu_reserve_attr_data_t))) {
	return -EINVAL;
    }

    return RK_SUCCESS;
}
//Sourav
asmlinkage int sys_rk_cpu_reserve_get_history(rk_reserve_t rsv, rk_reserve_history_t data)
{
  return -EINVAL;
}

/* We will use priorities above 256 to ensure that other unreserved 
 * Linux can be preempted automatically by reserved processes.
 */
/* XXX: should be (MAX_LINUX_PRIORITY+1) */
#define	LINUX_REALTIME_PRIORITY		257
#define	LINUX_TIMESHARE_PRIORITY	0

void
cpu_reserve_setscheduler(struct task_struct *p,
			 unsigned long policy, unsigned long rt_priority)
{
    p->rk_cannot_schedule = FALSE;
    p->policy = policy;

    rt_adjbaseprio(p, policy, rt_priority);
    current->need_resched = 1;
    if (p->rt_priority == BLOCKING_PRIORITY) {
	p->rt_priority = 0;
	p->rk_cannot_schedule = TRUE;
    }
}

void
cpu_reserve_set_base_sched_params(struct task_struct *tsk,
				  cpu_reserve_t cpu)
{
    /* for priority inheritance, set the base rs */
    switch (cpu->scheduling_policy) {
    case SCHED_FIFO:
	cpu_reserve_setscheduler(tsk, SCHED_FIFO,
				 cpu->cpu_priority_index +
				 LINUX_REALTIME_PRIORITY);
	break;
    case SCHED_OTHER:
	cpu_reserve_setscheduler(tsk, SCHED_OTHER,
				 LINUX_TIMESHARE_PRIORITY);
	break;
    default:
	cpu_reserve_setscheduler(tsk, SCHED_OTHER,
				 LINUX_TIMESHARE_PRIORITY);
    }
}

/* To set  the scheduling parameter of the task accoding 
 * to the specified cpu reserve.
 * This cpu_reserve_sched functions must be called w/ the rk spinlock  */
void cpu_reserve_sched(struct rs_proc_list *rs_proc, cpu_reserve_t cpu)
{
    struct task_struct *p = rs_proc->rs_proc_task;

    p->rk_cannot_schedule = FALSE;
    switch (cpu->scheduling_policy) {
    case SCHED_FIFO:
	cpu_reserve_setscheduler(p, SCHED_FIFO,
				 (LINUX_REALTIME_PRIORITY +
				  cpu->cpu_priority_index));
	break;
    case SCHED_OTHER:
	cpu_reserve_setscheduler(p, SCHED_OTHER, LINUX_TIMESHARE_PRIORITY);
	break;
    default:
	/* ?? */
	cpu_reserve_setscheduler(p, SCHED_OTHER, LINUX_TIMESHARE_PRIORITY);
    }
}

/* The cpu_reserve_sched functions must be called with the rk spinlock */

void
cpu_reserve_sched_blocking(struct rs_proc_list *rs_proc,
			   unsigned int priority_index)
{
    struct task_struct *p = rs_proc->rs_proc_task;
#ifdef DEBUG_RK
    printk("cpu_reserve_sched_realtime\n");
#endif

#ifdef DEBUG_RK
    printk("RT:%d (%d)", p->pid, priority_index);
#endif				/* DEBUG_RK */
    /* enable scheduling of process */
    p->rk_cannot_schedule = FALSE;
    cpu_reserve_setscheduler(p, SCHED_OTHER, BLOCKING_PRIORITY);

}

void
cpu_reserve_sched_realtime(struct rs_proc_list *rs_proc,
			   unsigned int priority_index)
{
    struct task_struct *p = rs_proc->rs_proc_task;
#ifdef DEBUG_RK
    printk("cpu_reserve_sched_realtime(%d)--> ", p->pid);
#endif

#ifdef DEBUG_RK
    printk("RT: %d\n", priority_index);
#endif				/* DEBUG_RK */
    /* enable scheduling of process */
    p->rk_cannot_schedule = FALSE;
    cpu_reserve_setscheduler(p, SCHED_FIFO,
#ifdef linux
			     (LINUX_REALTIME_PRIORITY + priority_index)
#else
			     REALTIME_PRIORITY
#endif				/* linux */
	);
}

void
cpu_reserve_sched_timeshare(struct rs_proc_list *rs_proc,
			    unsigned priority_index)
{
    struct task_struct *p = rs_proc->rs_proc_task;

#ifdef DEBUG_RK
    printk("cpu_reserve_sched_timeshare\n");
#endif

    /* enable scheduling of process */
    p->rk_cannot_schedule = FALSE;
    cpu_reserve_setscheduler(p, SCHED_OTHER, LINUX_TIMESHARE_PRIORITY);
}

void cpu_reserve_sched_timeshare_self(void)
{
    struct task_struct *p = current;

    if (p->policy & SCHED_FIFO) {
#ifdef DEBUG_RK2
	printk("cpu_reserve_sched_timeshare_self: pid(%d)\n", p->pid);
#endif				/* DEBUG_RK2 */
	/* enable scheduling of process */
	p->rk_cannot_schedule = FALSE;
	cpu_reserve_setscheduler(p, SCHED_OTHER, LINUX_TIMESHARE_PRIORITY);
    }
}

static int cpu_reserve_read_proc(rk_reserve_t rsv, char *buf)
{
    char *p = buf;
    cpu_reserve_t cpu = rsv->rsv_rsv;
    unsigned long used_cpu_time;
    cpu_capacity_t ave, cur, prv;

    used_cpu_time = TICK2USEC(&cpu->cpu_period_used_ticks);
    cur = CAPACITY_OF(cpu->cpu_period_used_ticks, cpu->cpu_period_ticks);
    prv =
	CAPACITY_OF(cpu->cpu_period_prev_used_ticks,
		    cpu->cpu_period_ticks);

    if (cpu->cpu_average.total_count) {
	ave = cpu->cpu_average.total_utils / cpu->cpu_average.total_count;
    } else {
	ave = cur;
    }

    /* 1st line: enf_mode, rep_mode */
    p += sprintf(p, "%d %d\n",
		 (int) rsv->rsv_reserve_param.enf_mode,
		 (int) rsv->rsv_reserve_param.rep_mode);

    /* 2nd line: utilization statistics
     * reseved, previous, average, max, min */
    p += sprintf(p, "%lu.%02lu %lu.%02lu %lu.%02lu %lu.%02lu %lu.%02lu\n",
		 CAPACITY_INT(cpu->cpu_capacity),
		 CAPACITY_FRAC(cpu->cpu_capacity), CAPACITY_INT(prv),
		 CAPACITY_FRAC(prv), CAPACITY_INT(ave), CAPACITY_FRAC(ave),
		 CAPACITY_INT(cpu->cpu_max_utilization),
		 CAPACITY_FRAC(cpu->cpu_max_utilization),
		 CAPACITY_INT(cpu->cpu_min_utilization),
		 CAPACITY_FRAC(cpu->cpu_min_utilization));

    /* 3rd line: current CPU usage 
     * used available requested */
    p += sprintf(p, "%lu %lu %lu\n",
		 used_cpu_time,
		 TICK2USEC(&cpu->cpu_period_available_ticks),
		 TICK2USEC(&cpu->cpu_time_ticks));
    /* 4th line: count of replenishment */
    p += sprintf(p, "%lu\n", cpu->cpu_average.total_count);

    return (p - buf);
}

int cpu_reserve_status_proc(char *buf)
{
    char *p = buf;

    /* cpu ticks per second, CPU capacity taken for reserves */
    p += sprintf(p, "%lu %lu.%02lu\n",
		 (unsigned long) rk_cpu_ticks_per_second,
		 CAPACITY_INT(cpu_reserve_current_capacity),
		 CAPACITY_FRAC(cpu_reserve_current_capacity));

    return (p - buf);
}
#endif				/* linux */

/*
 * Add specified reservation into reservation list in priority order.
 * Adjust reservation_priority index of list members accordingly.
 */
void priority_list_add(cpu_reserve_t cpu, struct list_head *head)
{
    cpu_reserve_t r;
    int i, done = FALSE;
    struct list_head *ptr;

    if (head->next == head) {
	/* insert at the head */
	cpu->cpu_priority_index = 0;
	list_add(&(cpu->cpu_link), head);
	return;
    }

    for (ptr = head->next; ptr != head; ptr = ptr->next) {
	r = cpu_reserve_entry(ptr);
	i = r->cpu_priority_index + 1;

#ifdef SUPER_CHARGED
	switch (cpu_reserves_scheduling_policy) {
	case RATE_MONOTONIC:
	    if (timespec_lt
		(cpu->cpu_res_attr.period, r->cpu_res_attr.period)) {
		done = TRUE;
	    }
	    break;
	case DEADLINE_MONOTONIC:
	    if (timespec_lt
		(cpu->cpu_res_attr.deadline, r->cpu_res_attr.deadline)) {
		done = TRUE;
	    }
	    break;
	case EDF:
	    /* EDF scheduler added: tasks are scheduled by absolute deadlines...
	     *                       Luca
	     */
	    if (timespec_lt(cpu->absdl, r->absdl)) {
		done = TRUE;
	    }
	    break;
	}
#else				/* SUPER_CHARGED */
	if (timespec_lt(cpu->cpu_res_attr.period, r->cpu_res_attr.period)) {
	    done = TRUE;
	}
#endif				/* SUPER_CHARGED */

	if ((done) || (ptr == head)) {
	    /* insert reservation here: subsequent indices will be fine as is! */
	    cpu->cpu_priority_index = i;
	    list_add(&(cpu->cpu_link), ptr->prev);
	    break;
	} else {
	    /* this increments the priority index of this entry */
	    r->cpu_priority_index = i;
	}
    }

    if (!done) {
	cpu->cpu_priority_index = 0;	/* Added by Luca */
	list_add(&cpu->cpu_link, ptr->prev);
    }
}

int rk_cpu_reserves_get_num(void)
{
    int count = 0;
    struct list_head *ptr;

    for (ptr = cpu_reserve_head.next; ptr != &cpu_reserve_head;
	 ptr = ptr->next) {
	count++;
    }
    return count;
}

int rk_cpu_reserves_set_scheduling_policy(int policy)
{
#ifdef SUPER_CHARGED
    /* check for root privileges */
#ifdef linux
    if (current->flags | PF_SUPERPRIV) {
	return set_scheduling_policy(policy);
    }
#else				/* linux */
    return set_scheduling_policy(policy);
#endif				/* linux */

#endif				/* SUPER_CHARGED */
    return RK_ERROR;
}

int set_scheduling_policy(int policy)
{
#ifdef SUPER_CHARGED
    /* 0 is a valid scheduling policy... Fixed by Luca */
    if ((policy >= 0) && (policy < NUM_CPU_RESERVE_POLICIES)) {
	cpu_reserves_scheduling_policy = policy;
	return RK_SUCCESS;
    }
#endif				/* SUPER_CHARGED */
    return -1;
}

int rk_cpu_reserves_get_scheduling_policy(void)
{
#ifdef SUPER_CHARGED
    return cpu_reserves_scheduling_policy;
#endif				/* SUPER_CHARGED */
    return -1;
}

/*
 * Remove specified reservation from reservation list.
 * Adjust reservation_priority index of remaining list members accordingly.
 */
int priority_list_remove(cpu_reserve_t cpu, struct list_head *head)
{
    cpu_reserve_t r;
    int i;
    struct list_head *ptr;

    if (head->next == head) {
	/* empty list */
	return -1;
    }

    if (head->next == &(cpu->cpu_link)) {
	/* remove item to make empty list */
	list_del(&(cpu->cpu_link));
	return 0;
    }


    /* search through list to find item */
    for (ptr = head->next; ptr != head; ptr = ptr->next) {
	r = cpu_reserve_entry(ptr);
	i = r->cpu_priority_index - 1;

	if (r == cpu) {
	    /* delete reservation */
	    list_del(&(cpu->cpu_link));

	    /* we are done; subsequent entries already have valid priority indices */
	    return 0;
	} else {
	    /* this decrements the priority index of this entry */
	    r->cpu_priority_index = i;
	}
    }

    /* we should not reach here, but just in case, we set the priority 
     * index correctly.
     */
    for (ptr = head->prev, i = 0; ptr != head; ptr = ptr->prev, i++) {
	r = cpu_reserve_entry(ptr);
	r->cpu_priority_index = i;
    }

    return (-1);
}


/* this ceiling computation works faster by assuming that the seconds
 * field is less than 1000 seconds, and by truncating the nanoseconds field.
 * If the seconds field is greater than 1000 seconds, a valid but VERY 
 * inefficient response will result!
 */
int efficient_timespec_ceil(struct timespec dividend,
			    struct timespec divider)
{
    unsigned long dividend_microsecs, divider_microsecs;

    if ((divider.tv_sec == 0) && (divider.tv_nsec == 0)) {
	return -1;
    }
    if ((dividend.tv_sec >= 1000) || (divider.tv_sec >= 1000)) {
	/* be ready to pay a BIG penalty now! */
	return (timespec_ceiling(dividend, divider));
    }
#define    MICROSECS_PER_SECOND          1000000

    /* truncate nanoseconds */
    dividend_microsecs = (dividend.tv_sec % 1000) * MICROSECS_PER_SECOND +
	(dividend.tv_nsec / 1000);
    divider_microsecs = (divider.tv_sec % 1000) * MICROSECS_PER_SECOND +
	(divider.tv_nsec / 1000);
    return (ceiling(dividend_microsecs, divider_microsecs));
}


int ceiling(unsigned long dividend, unsigned long divider)
{
    int quotient;
    quotient = dividend / divider;

    if (divider * quotient == dividend)
	return (quotient);
    else
	return (++quotient);
}

int timespec_ceiling(struct timespec dividend, struct timespec divider)
{
    int quotient = 1;
    struct timespec divider1;

    divider1 = divider;
    while (timespec_gt(dividend, divider1)) {
	timespec_add(divider1, divider);
	quotient++;
    }
    return (quotient);
}

struct timespec timespec_mult(struct timespec multiplicand, int multiplier)
{
    struct timespec result;

    result.tv_sec = 0;
    result.tv_nsec = 0;

    do {
	timespec_add(result, multiplicand);
    } while (--multiplier);

    return (result);
}


static
void check_enforce_reserve_type(cpu_reserve_attr_t cpu_attr)
{
    rk_reserve_param_t rtype = &(cpu_attr->reserve_type);

    if (!((rtype->enf_mode == RSV_HARD) || (rtype->enf_mode == RSV_SOFT) ||
	  (rtype->enf_mode == RSV_FIRM))) {
#ifdef DEBUG_RK
	printk("BAD enf value %d\n", rtype->enf_mode);
#endif				/* DEBUG_RK */
	rtype->enf_mode = RSV_HARD;
    }

    if (!((rtype->rep_mode == RSV_HARD) || (rtype->rep_mode == RSV_SOFT) ||
	  (rtype->rep_mode == RSV_FIRM))) {
#ifdef DEBUG_RK
	printk("BAD rep value %d\n", rtype->rep_mode);
#endif				/* DEBUG_RK */
	rtype->rep_mode = RSV_HARD;
    }

    if (!((rtype->sch_mode == RSV_HARD) || (rtype->sch_mode == RSV_SOFT) ||
	  (rtype->sch_mode == RSV_FIRM))) {
#ifdef DEBUG_RK
	printk("BAD sch value %d\n", rtype->sch_mode);
#endif				/* DEBUG_RK */
	rtype->sch_mode = RSV_HARD;
    }
}

/* The cpu reserve for measurement only.
 * This is for default and idle resource sets.
 * No need to apply admission control to these reserves.
 * We apply the 100% capacity reserve.
 * The parameter duration is the measurement granularity we want
 * to keep track the cpu usage.
 */
rk_reserve_t cpu_reserve_dummy_create(rk_resource_set_t rs,
				      time_t duration)
{
    cpu_reserve_t cpu;
    cpu_capacity_quad_t qc, qt, qd;
    cpu_reserve_attr_t cpu_attr;
    rk_reserve_t rsv;
    /* create cpu reserve object */
    cpu = malloc(sizeof(struct cpu_reserve));
    bzero(cpu, sizeof(struct cpu_reserve));
    cpu_attr = &(cpu->cpu_res_attr);
    cpu_attr->compute_time.tv_sec = duration;
    cpu_attr->compute_time.tv_nsec = 0;
    cpu_attr->period.tv_sec = duration;
    cpu_attr->period.tv_nsec = 0;
    cpu_attr->deadline.tv_sec = duration;
    cpu_attr->deadline.tv_nsec = 0;
    cpu_attr->blocking_time.tv_sec = 0;
    cpu_attr->blocking_time.tv_nsec = 0;
    /* start it, whenever the system is ready */
    cpu_attr->start_time.tv_sec = 0;
    cpu_attr->start_time.tv_nsec = 10000000;
    cpu_attr->reserve_type.sch_mode = RSV_HARD;
    cpu_attr->reserve_type.enf_mode = RSV_HARD;
    cpu_attr->reserve_type.rep_mode = RSV_HARD;

    qc = cpu_attr->compute_time.tv_sec;
    qc *= NANOSEC;
    qc += cpu_attr->compute_time.tv_nsec;
    qt = cpu_attr->period.tv_sec;
    qt *= NANOSEC;
    qt += cpu_attr->period.tv_nsec;
    qd = cpu_attr->deadline.tv_sec;
    qd *= NANOSEC;
    qd += cpu_attr->deadline.tv_nsec;
    cpu->cpu_capacity = CAPACITY_OF(qc, qt);

    /* No need to add this to cpu_reserve_list for admission control */
    INIT_LIST_HEAD(&cpu->cpu_link);	/* for sure */
    cpu->scheduling_policy = SCHED_OTHER;
    cpu->cpu_priority_index = LINUX_TIMESHARE_PRIORITY;

    /* calculate cpu ticks per capacity */
    nanosec2tick(&qt, &cpu->cpu_period_ticks);
    nanosec2tick(&qc, &cpu->cpu_time_ticks);
    nanosec2tick(&qd, &cpu->cpu_deadline_ticks);

    cpu->cpu_period_available_ticks = cpu->cpu_time_ticks;

    /* init waitqueue */
    init_waitqueue(&cpu->depleted_wait);

    /* check reservation type */
    check_enforce_reserve_type(cpu_attr);

    /* create generic reserve object */
    rsv = rk_reserve_create(rs, RSV_CPU);
    rsv->rsv_state = RSV_IS_NULL;
    rsv->rsv_rsv = cpu;
    rsv->rsv_ops = &cpu_reserve_ops;
    rsv->rsv_reserve_param = cpu_attr->reserve_type;
    cpu->rsv = rsv;

    /* create a timer for it */
    /* XXX: we must later have one timer per resource instance in set */
    rk_replenish_timer_create(rsv, cpu_attr->start_time);

    return rsv;

}

rk_reserve_t cpu_ceiling_reserve_create(rk_resource_set_t rs,
				      cpu_reserve_attr_t par_cpu_attr, int priority_index)
{
    cpu_reserve_t cpu;
    cpu_capacity_quad_t qc, qt, qd;
    cpu_reserve_attr_t cpu_attr;
    rk_reserve_t rsv;

#ifdef PCP_DEBUG
    printk("RK ceiling_reserve_create\n");
#endif

    /* create cpu reserve object */
    cpu = malloc(sizeof(struct cpu_reserve));
    bzero(cpu, sizeof(struct cpu_reserve));
    cpu_attr = &(cpu->cpu_res_attr);
    cpu_attr->compute_time.tv_sec = par_cpu_attr->compute_time.tv_sec; //duration;
    cpu_attr->compute_time.tv_nsec = par_cpu_attr->compute_time.tv_nsec;
    cpu_attr->period.tv_sec = par_cpu_attr->period.tv_sec;
    cpu_attr->period.tv_nsec = par_cpu_attr->period.tv_nsec;
    cpu_attr->deadline.tv_sec =  par_cpu_attr->deadline.tv_sec;
    cpu_attr->deadline.tv_nsec = par_cpu_attr->deadline.tv_nsec;
    cpu_attr->blocking_time.tv_sec = par_cpu_attr->blocking_time.tv_sec;
    cpu_attr->blocking_time.tv_nsec = par_cpu_attr->blocking_time.tv_nsec;
    /* start it, whenever the system is ready */
    cpu_attr->start_time.tv_sec = 0;
    cpu_attr->start_time.tv_nsec = 0;
    cpu_attr->reserve_type.sch_mode = RSV_HARD;
    cpu_attr->reserve_type.enf_mode = RSV_HARD;
    cpu_attr->reserve_type.rep_mode = RSV_HARD;

    qc = cpu_attr->compute_time.tv_sec;
    qc *= NANOSEC;
    qc += cpu_attr->compute_time.tv_nsec;
    qt = cpu_attr->period.tv_sec;
    qt *= NANOSEC;
    qt += cpu_attr->period.tv_nsec;
    qd = cpu_attr->deadline.tv_sec;
    qd *= NANOSEC;
    qd += cpu_attr->deadline.tv_nsec;

#ifdef PCP_DEBUG
    printk("RK ceiling create capacity of t.s(%ld), t.ns(%ld), c.s(%ld), c.ns(%ld)\n",
	   cpu_attr->period.tv_sec, cpu_attr->period.tv_nsec, cpu_attr->compute_time.tv_sec,
	   cpu_attr->compute_time.tv_nsec);
#endif

    cpu->cpu_capacity = CAPACITY_OF(qc, qt);

    /* No need to add this to cpu_reserve_list for admission control */
    INIT_LIST_HEAD(&cpu->cpu_link);	/* for sure */
    cpu->scheduling_policy = SCHED_FIFO;
    cpu->cpu_priority_index = priority_index;

    /* calculate cpu ticks per capacity */
    nanosec2tick(&qt, &cpu->cpu_period_ticks);
    nanosec2tick(&qc, &cpu->cpu_time_ticks);
    nanosec2tick(&qd, &cpu->cpu_deadline_ticks);

    cpu->cpu_period_available_ticks = cpu->cpu_time_ticks;

    /* init waitqueue */
    init_waitqueue(&cpu->depleted_wait);

    /* check reservation type */
    check_enforce_reserve_type(cpu_attr);

    /* create generic reserve object */
    rsv = rk_reserve_create(rs, RSV_CPU);
    rsv->rsv_state = RSV_IS_NULL;
    rsv->rsv_rsv = cpu;
    rsv->rsv_ops = &cpu_reserve_ops;
    rsv->rsv_reserve_param = cpu_attr->reserve_type;
    cpu->rsv = rsv;

    /* create a timer for it */
    /* XXX: we must later have one timer per resource instance in set */
    rk_replenish_timer_create(rsv, cpu_attr->start_time);

    return rsv;

}

/* Check the eligibility of the cpu reserve */
int cpu_reserve_eligible(rk_reserve_t rsv)
{
    cpu_reserve_t cpu = rsv->rsv_rsv;
    cpu_tick_data_t now;

#ifdef SUPER_CHARGED
    /* A CBS reserve is ALWAYS eligible... */
    if ((cpu_reserves_scheduling_policy == EDF) &&
	(rsv->rsv_reserve_param.enf_mode == RSV_SOFT)) {
	return 1;
    }
#endif
    /*  reserve's state  needs not to be RSV_IS_NULL */
    /*  It needs to be in the duration of  eligible reserve */
    rk_rdtsc(&now);
    if ((!(rsv->rsv_state & RSV_IS_DEPLETED)) &&
	(rsv->rsv_state & RSV_IS_STARTED) &&
	(cpu->cpu_period_available_ticks > 0) &&
	(now < cpu->cpu_eligible_deadline_ticks)) return 1;
    else
	return 0;
}


inline void cpu_reserve_sched_reserve_enable(struct rs_proc_list *rs_proc,
					     cpu_reserve_t cpu)
{
    /* set schedulable */
    cpu_reserve_sched_enable(rs_proc, 0);
    /* set scheduling paramter */
#if 0
    cpu_reserve_sched_realtime(rs_proc, cpu->cpu_priority_index);
#else
    cpu_reserve_sched(rs_proc, cpu);
#endif
}

inline void cpu_reserve_sched_reserve_disable(struct rs_proc_list *rs_proc)
{
    cpu_reserve_sched_disable(rs_proc, 0);
}

void cpu_reserve_start(rk_reserve_t rsv, cpu_tick_t start_ticks)
{
    cpu_tick_data_t now;
    cpu_reserve_t cpu = rsv->rsv_rsv;
    rsv->rsv_state |= RSV_IS_STARTED;
    cpu->cpu_eligible_deadline_ticks =
	*start_ticks + cpu->cpu_deadline_ticks;

    rk_rdtsc(&now);

    /* set up the next deadline of the eligible time */
    cpu->cpu_eligible_deadline_ticks = now + cpu->cpu_deadline_ticks;
}

int rk_valid_rsv(rk_reserve_t rsv)
{
    cpu_reserve_t p;
    struct list_head *e;

    for (e = cpu_reserve_head.next; e != &cpu_reserve_head; e = e->next) {
	p = cpu_reserve_entry(e);
	/* this must be changed for other CPU reserves */
	if (p->rsv == rsv) {
#ifdef DEBUG_RK
	    printk("true\n");
#endif				/* DEBUG_RK */
	    return TRUE;
	}
    }

#ifdef DEBUG_RK
    printk("false\n");
#endif				/* DEBUG_RK */
    return FALSE;
}

asmlinkage rk_reserve_t sys_rk_cpu_reserve_dummy_create(rk_resource_set_t rs, 
				time_t duration)
{
    return cpu_reserve_dummy_create(rs, duration);
}


