/*
 * resource_set.c: code to manage resource sets
 *
 * 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>
#ifdef CONFIG_MEASURE
#include <linux/measure.h>
#endif				/* CONFIG_MEASURE */
#ifdef RK_NET_RSV
#include <net/sock.h>
#include <linux/skbuff.h>
#include <linux/file.h>
#include <linux/smp_lock.h>
#endif

// #define DEBUG_RK
int need_cleanup = 0;

int dbgvar = 0;

/* supporting default and idle resource set */
rk_resource_set_t rk_default_resource_set;
rk_resource_set_t rk_idle_resource_set;

rk_resource_set_t rk_current_resource_set;
/* Supporting multiple cpu reserves in one single resource set */
rk_reserve_t rk_current_cpu_reserve;
LIST_HEAD(rk_resource_set_root);

extern void rk_resource_set_schedule(struct rs_proc_list *rs_proc,
				     unsigned int arg);
extern void int_rk_resource_set_detach_process(struct rs_proc_list
					       *rs_proc,
					       rk_resource_set_t rs);
extern void rk_resource_set_adjust_accounting(void);
extern rk_reserve_t rk_resource_set_update_cpu(rk_resource_set_t rs);
extern void rk_resource_set_check_default_rs(struct rs_proc_list *rs_proc,
					     unsigned int arg);
extern int cpu_reserve_eligible(rk_reserve_t rsv);
extern inline void cpu_reserve_sched_reserve_enable(struct rs_proc_list
						    *rs_proc,
						    cpu_reserve_t cpu);
extern inline void cpu_reserve_sched_reserve_disable(struct rs_proc_list
						     *rs_proc);
extern void cpu_reserve_set_base_sched_params(struct task_struct *tsk,
					      cpu_reserve_t cpu);

void rk_resource_set_init(void)
{
    rk_current_resource_set = NULL_RESOURCE_SET;
    rk_default_resource_set = NULL_RESOURCE_SET;
    rk_idle_resource_set = NULL_RESOURCE_SET;
    INIT_LIST_HEAD(&rk_resource_set_root);
}

#include <asm/uaccess.h>
rk_resource_set_t rk_resource_set_create(char *name)
{
    rk_resource_set_t rs;

#ifdef DEBUG_RK
    printk("rs_create: %s\n", name);
#endif				/* DEBUG_RK */
    rs = malloc(sizeof(struct rk_resource_set));
    bzero(rs, sizeof(struct rk_resource_set));

    if (name == NULL)
	rs->rs_name[0] = '\0';
    else {
	strcpy(rs->rs_name, name);
	rs->rs_name[RSET_NAME_LEN - 1] = '\0';	/* terminate string */
    }

    if (list_empty(&rk_resource_set_root)) {
	/* enable rk scheduling hook */
	rk_enable();
	need_cleanup = 1;
    }

    list_add(&rs->rs_rs, &rk_resource_set_root);

    rs->rs_cpu = NULL_RESERVE;
    rs->rs_net = NULL_RESERVE;
    rs->rs_disk = NULL_RESERVE;
    rs->rs_rcv  = NULL_RESERVE;

    INIT_LIST_HEAD(&rs->rs_devices);

#ifdef	linux
    INIT_LIST_HEAD(&rs->rs_proc_list);	/* just for sure */
    rk_proc_rs_create(rs);	/* create directory as /proc/rk/<rs_id>/ */
#endif

    INIT_LIST_HEAD(&rs->rs_cpu_list);	/* the list of cpu reserves */
    rs->sch_mode = RSV_HARD;	/* The default scheduling mode of the resource 
				   set */

    return rs;
}

/*
 * rk_resource_set_destroy_reserves(struct list_head *rsv_list)
 *	called from rk_resource_set_destroy to destroy all the reserves 
 *	on the list specified by ``rsv_list''.
 */

static void rk_resource_set_destroy_reserves(struct list_head *rsv_list)
{
    rk_reserve_t rsv;
    /* XXX: we should check for eligibility of destruction */


#ifdef DEBUG_RK
    printk("rk_resource_set_destroy_reserves: rsv_list(0x%x)\n",
	   (unsigned int) rsv_list);
#endif
    while (!list_empty(rsv_list)) {
	/* get a reserve */
	rsv = list_entry(rsv_list->next, struct rk_reserve, rsv_rs_link);
	list_del(&rsv->rsv_rs_link);
	/* destroy all */
#ifdef DEBUG_RK
	printk("rk_resource_set_destroy_reserves: rsv(0x%x)\n",
	       (unsigned int) rsv);
	printk
	    ("rk_resource_set_destroy_reserves: rsv_ops(0x%x) detroy(0x%x)\n",
	     (unsigned int) rsv->rsv_ops,
	     (unsigned int) rsv->rsv_ops->destroy);
#endif
	(rsv->rsv_ops->destroy) (rsv);
    }
}

int rk_resource_set_destroy(rk_resource_set_t rs)
{

    rk_reserve_t net, rnet;
    static void rk_resource_set_detach_all_processes(rk_reserve_t cpu, struct list_head
						     *proc_list);

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

    if (rs == NULL)
	return -EFAULT;

    if (!rk_valid_rset(rs))
	return -EFAULT;

    if (list_empty(&(rs->rs_rs))) {	/* more sanity check necessary */
	printk("rk_resource_set_destroy: rs(0x%x) not on list\n",
	       (unsigned int) rs);
	/* cannot destroy non-active resource set */
	return RK_ERROR;	/* error */
    }
#ifdef DEBUG_RK
    printk("(empty)");
#endif				/* DEBUG_RK */


    net = rs->rs_net;
    rnet = rs->rs_rcv;

    //printk("rnet rsv_ops %p\n", rnet->rsv_ops);
    /* start cleaning up */

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

    /* free attached processes/threads */
#ifdef	linux
    /* change to rk_multiple_resource_set_detach_all_processes ; 
     * for supporting multiple cpu reserves in one resource set
     * and multiple resource sets in one process.
     * If there are still processes attached to the resource set,
     * detach all.
     */
    if (!list_empty(&rs->rs_proc_list)) {
	/* detach rs to each process */
	rs_proc_list_apply_rs(&rs->rs_proc_list,
			      int_rk_resource_set_detach_process, rs);
	/* Warning!!! We also have to detach from network.... */
    }
#endif				/* linux */

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

    rk_resource_set_destroy_reserves(&rs->rs_cpu_list);	/* destroy all cpu reserves */
    if (net) {
	rk_resource_set_detach_all_processes(net, &rs->rs_proc_list);
	(net->rsv_ops->destroy)(net);
    }

   if (rnet) {
	rk_resource_set_detach_all_processes(rnet, &rs->rs_proc_list);
	//printk("detach done\n");
	(rnet->rsv_ops->destroy)(rnet);
    } 

   printk("here at resource set\n");
    rk_resource_set_destroy_reserves(&rs->rs_devices);	/* device reserves? */

    {
	rk_reserve_t disk;
	disk = rs->rs_disk;
	if (disk)
	    (disk->rsv_ops->destroy) (disk);
    }

    /* 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 */

    rk_resource_set_adjust_accounting();

#ifdef	linux
    /* remove /proc/rk/<rs_id> entry
     * should be after removing its contents */
    rk_proc_rs_destroy(rs);
#endif				/* linux */

    /* finally free resource set */
    list_del(&rs->rs_rs);
    INIT_LIST_HEAD(&rs->rs_rs);	/* just for sure */
    free(rs);
    if (list_empty(&rk_resource_set_root)) {
	/* disable rk scheduling hook */
	rk_disable();
	need_cleanup = 0;
    }

    return RK_SUCCESS;		/* success */
}

int rk_resource_set_attach_reserve(rk_resource_set_t rs, rk_reserve_t rsv)
{
    if (rsv == NULL)
	return RK_ERROR;
    if (!list_empty(&rsv->rsv_rs_link)) {	/* if already attached */
	return RK_ERROR;	/* error */
    }


    switch (rsv->rsv_type) {
    case RSV_CPU:		/* cpu capacity */
	{
	    unsigned long flags;
	    rk_spin_lock(flags);
	    list_add(&rsv->rsv_rs_link, &rs->rs_cpu_list);
	    rk_spin_unlock(flags);
	}
	rsv->rsv_rs = rs;
	/* update the current cpu reserve */

	rk_resource_set_update_cpu(rs);

	/* check the state of the resource set */
	{
	    static void rk_resource_set_update_sch_mode(rk_resource_set_t);
	    rk_resource_set_update_sch_mode(rs);
	}

	if (!list_empty(&rs->rs_proc_list)) {
	    /* attach/detach default resource set depending on
	     * the task reserve state and schedule to the eligible
	     * resource set w/ highest priority
	     */
	    rs_proc_list_apply(&rs->rs_proc_list,
			       rk_resource_set_check_default_rs, 0);

	    /* we need to update its scheduling policy */
	    dbgvar = 4;
	    rs_proc_list_apply(&rs->rs_proc_list,
			       rk_resource_set_schedule, 0);

	    dbgvar = 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 */
	rk_resource_set_adjust_accounting();
	break;
/* For the moment, let's assume a single net reserve... */
    case RSV_NET:		/*network bandwidth */
	if (rs->rs_net) {	/* resource set has netbw reserve */
	    /*
	     * at this moment, a resource set can use only
	     * a single netbw reserve.
	     */
	    return RK_ERROR;	/* error */
	}
	/* */
	rs->rs_net = rsv;
	rsv->rsv_rs = rs;
	break;
    case RSV_RCV:
      	if (rs->rs_rcv) {	/* resource set has netbw reserve */
	    /*
	     * at this moment, a resource set can use only
	     * a single netbw reserve.
	     */
	    return RK_ERROR;	/* error */
	}
	/* */
	rs->rs_rcv = rsv;
	rsv->rsv_rs = rs;
	break;
    case RSV_DEV:		/* virtual devices */
	list_add(&rsv->rsv_rs_link, &rs->rs_devices);
	rsv->rsv_rs = rs;
	break;
    case RSV_DISK:		/* disk reserves */
	if (rs->rs_disk) {
	    /* At this moment, we allow only one disk reserve attached 
	       to a resource set */
	    return RK_ERROR;
	}
	rs->rs_disk = rsv;
	rsv->rsv_rs = rs;
	break;
    default:			/* unknown reserve type */
	break;
	return RK_ERROR;	/* error */
    }

    return RK_SUCCESS;		/* success */
}

void rk_resource_set_detach_reserve(rk_resource_set_t rs, rk_reserve_t rsv)
{
    /* detach from rk_resource_set */
    {
	unsigned long flags;

	rk_spin_lock(flags);
	list_del(&rsv->rsv_rs_link);
	rk_spin_unlock(flags);
    }

    /* clear link */
    rsv->rsv_rs = NULL_RESOURCE_SET;
    INIT_LIST_HEAD(&rsv->rsv_rs_link);

    switch (rsv->rsv_type) {
    case RSV_CPU:
	if (rs->rs_cpu == rsv) {
	    /* update the current cpu reserve */
	    rk_resource_set_update_cpu(rs);

	    /* Check the state of the resource set */
	    {
		static void
		    rk_resource_set_update_sch_mode(rk_resource_set_t);
		rk_resource_set_update_sch_mode(rs);
	    }

	    /* If there are some processes attaching to the resource set,
	     * we need to update its scheduling policy
	     */

	    if (!list_empty(&rs->rs_proc_list)) {
		/* attach/detach default resource set depending on
		 * the task reserve state and schedule to the eligible
		 * resource set w/ highest priority
		 */
		rs_proc_list_apply(&rs->rs_proc_list,
				   rk_resource_set_check_default_rs, 0);

		/* we need to update its scheduling policy */
		dbgvar = 5;
		rs_proc_list_apply(&rs->rs_proc_list,
				   rk_resource_set_schedule, 0);

		dbgvar = 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 */
	rk_resource_set_adjust_accounting();
	break;
    case RSV_NET:
	break;
    case RSV_RCV:
      break;
     case RSV_DEV:
	break;
    case RSV_DISK:
	break;
    default:
	break;
    }
}

/*
 * Functions depending on the upper OS kernel
 *
 */
#ifdef	linux

asmlinkage rk_resource_set_t sys_rk_resource_set_create(char *name)
{
    char rs_name[RSET_NAME_LEN];
#ifdef DEBUG_RK
    printk("sys_rk_cpu_reserve_create: %s\n", name);
#endif				/* DEBUG_RK */
    if (name == NULL)
	rs_name[0] = '\0';
    else {
	copy_from_user(rs_name, name, RSET_NAME_LEN);
	rs_name[RSET_NAME_LEN - 1] = '\0';	/* terminate string */
    }

    return rk_resource_set_create(rs_name);
}

asmlinkage int sys_rk_resource_set_destroy(rk_resource_set_t rs)
{
#ifdef DEBUG_RK
    printk("sys_rk_rset_destroy: %d\n", (unsigned int) rs);
#endif				/* DEBUG_RK */

    /* first check for validity of rs */
    if (!rk_valid_rset(rs))
	return -EFAULT;

    /* Saowanee: We should check if this is not system (default/idle) rs */
#ifndef APPLE_DEBUG
    if ((rs == rk_default_resource_set) || (rs == rk_idle_resource_set)) {
	printk("Trying to destroy default or idle reserve \n");
	return RK_ERROR;
    }
#endif				/* APPLE_DEBUG */

    /* XXX: we must also check eligibility of destruction by this process.
     * this must be done for all create/delete/control operations on 
     * reserves.
     */
    return rk_resource_set_destroy(rs);
}

int resource_set_attach_process(rk_resource_set_t rs,
				struct task_struct *tsk)
{
    rk_reserve_t cpu;
    rk_reserve_t net;
    rk_reserve_t netr;
    struct rs_proc_list *rs_proc;
    struct resource_set_list *new_rs_ptr;
    unsigned long flags;
    /* no need to bind NULL_RESOURCE_SET */
    if (!rs)
	return RK_SUCCESS;

    cpu = rs->rs_cpu;
    net = rs->rs_net;
    netr= rs->rs_rcv;


#ifdef PREEMPT_FIX
    tsk->rk_resource_set = rs;
#else
#endif

    /* Luca: if the task is periodic, let's set the
     * tmr->rsv filed in the correct way (used by CBS)
     */
    if (tsk->periodicType == PERIODIC) {
	if (tsk->period_timer->tmr_rsv != NULL) {
	    printk("Error: timer rsv set in an unreserved task?\n");
	}
	tsk->period_timer->tmr_rsv = rs->rs_cpu;
    }

    /* Supporting multiple resource sets in one process */

    /* add this rs to the task's resource_set_list */
    new_rs_ptr = malloc(sizeof(struct resource_set_list));
    bzero(new_rs_ptr, sizeof(struct resource_set_list));

    new_rs_ptr->rk_resource_set = rs;


    /* move this to below */
    /* tsk->rk_resource_set = rs; */

    /* add process in to the proc_list */
    rs_proc = malloc(sizeof(struct rs_proc_list));
    bzero(rs_proc, sizeof(struct rs_proc_list));

    rs_proc->rs_proc_task = tsk;
    rs_proc->rs_proc_pid = tsk->pid;

#ifdef DEBUG_RK
    printk("(adding to list %d)", tsk->pid);
#endif				/* DEBUG_RK */

    rk_spin_lock(flags);
    list_add(&rs_proc->rs_proc_list, &rs->rs_proc_list);
    /* Initialize it */
    if (tsk->rs_list.resource_set_list.next == NULL) {
	void rk_proc_process_create(pid_t);
	INIT_LIST_HEAD(&(tsk->rs_list.resource_set_list));

    }
    list_add(&new_rs_ptr->resource_set_list,
	     &(&tsk->rs_list)->resource_set_list);
    rk_spin_unlock(flags);



    /* attach/detach default resource set depending on
     * the task reserve state and schedule to the eligible
     * resource set w/ highest priority
     */
    rk_resource_set_check_default_rs(rs_proc, 0);

    dbgvar = 6;
    rk_resource_set_schedule(rs_proc, 0);
    dbgvar = 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 (net) {
	net->rsv_ops->attach(net, rs_proc);
    }
    
      if(netr) {

      netr->rsv_ops->attach(netr, rs_proc);
      }

      //printk("test1\n");
    if (current == tsk)		/* &&  rk_current_resource_set != rs ????
				   OK, that test is performed in 
				   adjust_accounting */
	rk_resource_set_adjust_accounting();


    //printk("test2\n");
    return RK_SUCCESS;
}

/** For network related reserves only */

#ifdef RK_NET_RSV
int resource_set_attach_socket (rk_resource_set_t rs, struct socket * sock, rk_reserve_type_t rsv_type)
{
  
  rk_reserve_t net;
#ifdef THREADED_NET
  rk_reserve_t rcv;
#endif
  struct rs_sock_list *rs_sock;
    struct sock *sk;
  unsigned long flags;
  
  
  sk = sock->sk;
  

  if (!rs)
    return RK_ERROR;
  
  switch (rsv_type) {
    
  case RSV_NET:
    net = rs->rs_net;
    if (!net)
      return RK_ERROR;
    sk->rk_net_reserve = rs->rs_net;
    break;

  case RSV_RCV:
#ifdef THREADED_NET
    rcv = rs->rs_rcv;
    if(!rcv)
      return RK_ERROR;
    sk->rk_rcv_net_reserve = rs->rs_rcv;
#endif
    break;

  default:
    
     net = rs->rs_net;
    if (!net)
      return RK_ERROR;
#ifdef THREADED_NET
    rcv = rs->rs_rcv;
    if(!rcv)
      return RK_ERROR;
    sk->rk_net_reserve = rs->rs_net;
    sk->rk_rcv_net_reserve = rs->rs_rcv;
#endif
    break;

  
  }

  

  rs_sock = malloc(sizeof(struct rs_sock_list));
  bzero(rs_sock, sizeof(struct rs_sock_list));
  
  rs_sock->sk = sk;

  rk_spin_lock(flags);
  list_add(&rs_sock->rs_sock_list, &rs->rs_sock_list);
  rk_spin_unlock(flags);

  return RK_SUCCESS;

}
#endif

static int default_resource_set_attach_process(rk_resource_set_t rs,
					       struct task_struct *tsk)
{
    rk_reserve_t cpu;
    struct rs_proc_list *rs_proc;
    struct resource_set_list *new_rs_ptr;
    unsigned long flags;
    /* no need to bind NULL_RESOURCE_SET */
    if (!rs)
	return RK_SUCCESS;

    cpu = rs->rs_cpu;

    /* add this rs to the task's resource_set_list */
    new_rs_ptr = malloc(sizeof(struct resource_set_list));
    bzero(new_rs_ptr, sizeof(struct resource_set_list));

    new_rs_ptr->rk_resource_set = rs;


    /* move this to below */
    /* tsk->rk_resource_set = rs; */

    /* add process in to the proc_list */
    rs_proc = malloc(sizeof(struct rs_proc_list));
    bzero(rs_proc, sizeof(struct rs_proc_list));

    rs_proc->rs_proc_task = tsk;
    rs_proc->rs_proc_pid = tsk->pid;

#ifdef DEBUG_RK
    printk("(default adding to list %d)", tsk->pid);
#endif				/* DEBUG_RK */

    rk_spin_lock(flags);
    list_add(&rs_proc->rs_proc_list, &rs->rs_proc_list);
    /* Initialize it */
    if (tsk->rs_list.resource_set_list.next == NULL) {
	void rk_proc_process_create(pid_t);
	INIT_LIST_HEAD(&(tsk->rs_list.resource_set_list));

    }


    list_add(&new_rs_ptr->resource_set_list,
	     (&tsk->rs_list)->resource_set_list.prev);

    rk_spin_unlock(flags);

    return RK_SUCCESS;
}


asmlinkage int
sys_rk_resource_set_attach_process(rk_resource_set_t rs, pid_t pid)
{
    struct task_struct *tsk;
    if (!rk_valid_rset(rs))
	return -ESRCH;

#ifdef	DEBUG_RK
    printk("resource_set_attach_process: rs(0x%x) pid(%d)\n",
	   (int) rs, pid);
#endif

    tsk = __rk_find_process_by_pid(pid);
#ifdef DEBUG_RK
    printk("->task(0x%x)\n", (int) tsk);
#endif				/* DEBUG_RK */

    if (!tsk) {
	printk("resource_set_attach_process: invalid pid(%d)\n", pid);
	return RK_ERROR;
    }

    return resource_set_attach_process(rs, tsk);
}

/* Kill function to also destroy the default resource set from the task */
int rk_resource_set_kill_process(struct task_struct *tsk)
{
    struct resource_set_list *list, *rs_list;
    struct list_head *ptr;
    struct rk_resource_set *rk_resource_set;

    /* get the resource set attached to the process */
    list = &(tsk->rs_list);
    /* no resource set attached */
    if (list->resource_set_list.next == NULL)
	return RK_SUCCESS;

    for (ptr = (&list->resource_set_list)->next;
	 ptr != (&list->resource_set_list)->next; ptr = ptr->next) {
	/* get the resource_set_list entry */
	rs_list =
	    list_entry(ptr, struct resource_set_list, resource_set_list);
	rk_resource_set = rs_list->rk_resource_set;
	/* detach resource set */
	{
	    int __rk_resource_set_detach_process(rk_resource_set_t,
						 struct task_struct *);
	    __rk_resource_set_detach_process(rk_resource_set, tsk);
	}
	/* destroy resource set if no proc attached to the resource set */
	if (list_empty(&rk_resource_set->rs_proc_list)) {
	    rk_resource_set_destroy(rk_resource_set);
	}
    }
    return RK_SUCCESS;
}

#ifdef RK_NET_RSV
asmlinkage int
sys_rk_resource_set_attach_socket(rk_resource_set_t rs, int socket_fd , rk_reserve_type_t rsv_type)

     // rsv_type: 0: sending, 1:receiving
{

  struct socket *sock;
  int err;

  extern struct socket *sockfd_lookup(int, int*);
  
  if (!rk_valid_rset(rs))
    return -ESRCH;

  
 sock = sockfd_lookup(socket_fd, &err);
  
  if (sock == NULL) {
		printk("resource_set_attach_socket: invalid socket file descriptor(%d)\n",
		       socket_fd);
		return RK_ERROR;
	}
  fput(sock->file);
  return resource_set_attach_socket(rs, sock, rsv_type);

}

int resource_set_detach_socket (rk_resource_set_t rs, struct socket * sock, rk_reserve_type_t rsv_type)
{
  
   rk_reserve_t net,rcv;
#if 0
  struct rs_sock_list *rs_sock;
  unsigned long flags;
#endif
  struct sock *sk;
  
  
  sk = sock->sk;
  

  if (!rs)
    return RK_SUCCESS;
  
  switch (rsv_type) {
    
  case RSV_NET:
    net = rs->rs_net;
    if (!net)
      return RK_ERROR;
    if (sk->rk_net_reserve == rs->rs_net)
    sk->rk_net_reserve = NULL;
    break;

  case RSV_RCV:
    rcv = rs->rs_rcv;
    if(!rcv)
      return RK_ERROR;
    if (sk->rk_rcv_net_reserve == rcv)
    sk->rk_rcv_net_reserve = NULL;
    sk->rcv_queue = NULL;
    break;

  default:
    
     net = rs->rs_net;
    if (!net)
      return RK_ERROR;
    rcv = rs->rs_rcv;
    if(!rcv)
      return RK_ERROR;
    if (sk->rk_net_reserve == rs->rs_net)
    sk->rk_net_reserve = NULL;
    if (sk->rk_rcv_net_reserve == rs->rs_rcv)
      {
    sk->rk_rcv_net_reserve = NULL;
    sk->rcv_queue = NULL;
      }
    break;

  
  }

  
#if 0
  rs_sock = malloc(sizeof(struct rs_sock_list));
  bzero(rs_sock, sizeof(struct rs_sock_list));
  
  rs_sock->sk = sk;

  rk_spin_lock(flags);
  list_add(&rs_sock->rs_sock_list, &rs->rs_sock_list);
  rk_spin_unlock(flags);
#endif
  return RK_SUCCESS;


}

asmlinkage int
sys_rk_resource_set_detach_socket(rk_resource_set_t rs, int socket_fd, unsigned char rsv_type)
// rsv_type: 0: sending, 1:receiving
{
  struct socket *sock;
  int err;
  extern struct socket *sockfd_lookup(int, int*);

   if (!rk_valid_rset(rs))
    return -ESRCH;


    lock_kernel();  
 sock = sockfd_lookup(socket_fd, &err);
  
  if (sock == NULL) {
		printk("resource_set_attach_socket: invalid socket file descriptor(%d)\n",
		       socket_fd);
		unlock_kernel();
		return RK_ERROR;
	}
  fput(sock->file);
  unlock_kernel();

  return resource_set_detach_socket(rs, sock, rsv_type); 
  
}


#endif

int __rk_resource_set_is_process_attached(rk_resource_set_t rs, struct task_struct *tsk)
{
    struct rs_proc_list *rs_proc;
    struct list_head *proc_list;

    if (!tsk) {
	return -1;
    }

    if (!rk_valid_rset(rs)) {
	return -1;
    }


    proc_list = &(rs->rs_proc_list);
    for (proc_list = proc_list->next; proc_list != &(rs->rs_proc_list);
	 proc_list = proc_list->next) 
      {
	/* get an rs_proc */
	rs_proc = list_entry(proc_list, struct rs_proc_list, rs_proc_list);
	if (rs_proc->rs_proc_task == tsk) 
	  {
	    /* found */ 
	    return 1;
	  }
      }

    /* not found*/
    return 0;
}

/* XXX: this must be called in exit.c stub after a process dies */
int __rk_resource_set_detach_process(rk_resource_set_t rs,
				     struct task_struct *tsk)
{
    struct rs_proc_list *rs_proc;
    struct list_head *proc_list;
    rk_reserve_t net;
    rk_reserve_t netr;

    if (!tsk) {
	return -ESRCH;
    }

    if (!rk_valid_rset(rs)) {
	return -EINVAL;
    }

    net = rs->rs_net;
    netr= rs->rs_rcv;

    /* XXX: delete from reservation list - fix */
    proc_list = &(rs->rs_proc_list);
    for (proc_list = proc_list->next; proc_list != &(rs->rs_proc_list);
	 proc_list = proc_list->next) {
	/* get an rs_proc */
	rs_proc = list_entry(proc_list, struct rs_proc_list, rs_proc_list);
	if (rs_proc->rs_proc_task == tsk) {
	    /* found process */
	    list_del(&(rs_proc->rs_proc_list));

	    /* delete a resource set from the list in the task struct */
	    {
		unsigned long flags;
		static void
		    rk_resource_set_tsk_delete_rs(rk_resource_set_t,
						  struct task_struct *);
		rk_spin_lock(flags);
		rk_resource_set_tsk_delete_rs(rs, tsk);
		rk_spin_unlock(flags);
	    }


//	    if (tsk->rk_resource_set == rs) {
		/* If this is the current resource set of the task,
		 * we need to reschedule resource set 
		 */
		rk_resource_set_check_default_rs(rs_proc, 0);
		if (tsk->rs_list.resource_set_list.next ==
		    &(tsk->rs_list.resource_set_list)) {
		    extern void
			cpu_reserve_setscheduler(struct task_struct *p,
						 unsigned long policy,
						 unsigned long
						 rt_priority);
		    /* In the future, we will have to attach it to DEFAULT RS */
		    tsk->rk_resource_set = NULL;
		    tsk->rk_base_resource_set = NULL;
		    tsk->rk_cannot_schedule = FALSE;
		    cpu_reserve_setscheduler(tsk, SCHED_OTHER, 0);
		} else {
		    dbgvar = 7;
		    rk_resource_set_schedule(rs_proc, 0);
		    dbgvar = 0;
		}
//	    }
	    /* destroy it */
	    INIT_LIST_HEAD(&rs_proc->rs_proc_list);	/* just for sure */
	    free(rs_proc);

	    if (net) {
	      net->rsv_ops->detach(net, rs_proc);
	    }

	    if(netr) {
	      
	      netr->rsv_ops->detach(netr, rs_proc);
	    }

	    /*??? */
	    if (current == tsk)
		rk_resource_set_adjust_accounting();

	    /* done, get out */
	    return RK_SUCCESS;
	}
    }

    return RK_ERROR;
}

static int default_resource_set_detach_process(rk_resource_set_t rs,
					       struct task_struct *tsk)
{
    struct rs_proc_list *rs_proc;
    struct list_head *proc_list;
    struct resource_set_list *rs_list;
    if (!tsk) {
	return -ESRCH;
    }

    if (!rk_valid_rset(rs)) {
	return -EINVAL;
    }

    /* XXX: delete from reservation list - fix */
    proc_list = &(rs->rs_proc_list);
    for (proc_list = proc_list->next; proc_list != &(rs->rs_proc_list);
	 proc_list = proc_list->next) {
	/* get an rs_proc */
	rs_proc = list_entry(proc_list, struct rs_proc_list, rs_proc_list);
	if (rs_proc->rs_proc_task == tsk) {
	    /* found process */
	    list_del(&(rs_proc->rs_proc_list));

	    /* deletea default resource set from the list in the task struct */
	    {
		unsigned long flags;
		static void
		    rk_resource_set_tsk_delete_rs(rk_resource_set_t,
						  struct task_struct *);
		rk_spin_lock(flags);
		rs_list =
		    list_entry(tsk->rs_list.resource_set_list.prev,
			       struct resource_set_list,
			       resource_set_list);
		if (rs_list->rk_resource_set == rs)
		    list_del(tsk->rs_list.resource_set_list.prev);
		rk_spin_unlock(flags);
	    }

	    /* destroy it */
	    INIT_LIST_HEAD(&rs_proc->rs_proc_list);	/* just for sure */
	    free(rs_proc);

	    /* done, get out */
	    return RK_SUCCESS;
	}
    }

    return RK_ERROR;
}

asmlinkage int
sys_rk_resource_set_detach_process(rk_resource_set_t rs, pid_t pid)
{
    struct task_struct *tsk;

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

    if (!rk_valid_rset(rs))
	return -ESRCH;

    tsk = __rk_find_process_by_pid(pid);
#ifdef	DEBUG_RK
    printk("resource_set_detach_process: rs(0x%x) pid(%d)->task(0x%x)\n",
	   (int) rs, pid, (int) tsk);
#endif

    return (__rk_resource_set_detach_process(rs, tsk));
}


#if 1				/* used  again :) */
static void
rk_resource_set_detach_all_processes(rk_reserve_t cpu,
				     struct list_head *proc_list)
{
    struct rs_proc_list *rs_proc;
    struct list_head *ptr, *next;

    if (!cpu)
	return;

    for (ptr = proc_list->next; ptr != proc_list; ptr = next) {
	/* get a rs_proc */
	rs_proc = list_entry(ptr, struct rs_proc_list, rs_proc_list);
	next = ptr->next;
	list_del(ptr);

	printk("Detachin'\n");
	/* detach reserve */
	cpu->rsv_ops->detach(cpu, rs_proc);
	printk("Detached\n");

	/* detach resource set from task */
	rs_proc->rs_proc_task->rk_resource_set = NULL_RESOURCE_SET;

	/* XXX: restore its original scheduling parameters */

	/* destroy it */
	INIT_LIST_HEAD(&rs_proc->rs_proc_list);	/* just for sure */
	printk("Freeing\n");
	free(rs_proc);
#ifdef DEBUG_RK
	printk("(end)");
#endif				/* DEBUG_RK */
    }
}

#endif

int resource_set_status_proc(char *buf)
{
    char *p = buf;
    rk_resource_set_t rs;
    struct list_head *e;

    e = rk_resource_set_root.next;
    while (e != &rk_resource_set_root) {
	rs = list_entry(e, struct rk_resource_set, rs_rs);
	p += sprintf(p, "%x\n", (int) rs);
	e = e->next;
    }

    return (p - buf);
}

int rk_resource_sets_get_num(void)
{
    struct list_head *e;
    int count = 0;

    for (e = rk_resource_set_root.next; e != &rk_resource_set_root;
	 e = e->next) count++;
    return count;
}

asmlinkage int sys_rk_resource_sets_get_num(void)
{
#ifdef DEBUG_RK
    printk("rk_rset_get_num ");
#endif				/* DEBUG_RK */
    return (rk_resource_sets_get_num());
}

asmlinkage int
sys_rk_resource_sets_get_list(rk_resource_set_t * rs, int size)
{
    struct list_head *e;
    int i;
    int local_count = rk_resource_sets_get_num();
    int local_size = local_count * sizeof(rk_resource_set_t);
    rk_resource_set_t rset;

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

    if (size < (local_count * sizeof(void *)))
	return -EINVAL;

    if (verify_area(VERIFY_WRITE, rs, local_size)) {
	return -EFAULT;
    }

    /* copy known resource sets to list */
    for (e = rk_resource_set_root.next, i = 0; e != &rk_resource_set_root;
	 e = e->next, i++) {
	rset = list_entry(e, struct rk_resource_set, rs_rs);
	if (copy_to_user(&(rs[i]), &rset, sizeof(rk_resource_set_t))) {
	    return -EFAULT;
	}
    }
    return local_count;
}

asmlinkage rk_resource_set_t sys_rk_proc_get_rset(pid_t pid)
{
    struct task_struct *tsk;

#ifdef DEBUG_RK
    printk("(rk_proc_get_rset %d) ", pid);
#endif				/* DEBUG_RK */

    tsk = __rk_find_process_by_pid(pid);
#ifdef DEBUG_RK
    printk("->task(0x%x)\n", (int) tsk);
#endif				/* DEBUG_RK */

    if (tsk) {
	return tsk->rk_resource_set;
    } else {
	return NULL_RESOURCE_SET;
    }
}

inline int rk_resource_set_get_num_procs(rk_resource_set_t rs)
{
    int count;
    struct list_head *e;

    for (e = rs->rs_proc_list.next, count = 0; e != &(rs->rs_proc_list);
	 e = e->next) {
	count++;
    }
    return count;
}

asmlinkage int
sys_rk_resource_set_get_proclist(rk_resource_set_t rs, pid_t * procs)
{
    struct list_head *e;
    struct rs_proc_list *rs_proc;
    int i;
    int local_count;
    int local_size;

#ifdef DEBUG_RK
    printk("rk_rset_get_proclist: rs(0x%x) proc (0x%x)\n", rs, procs);
#endif				/* DEBUG_RK */

    if (!rk_valid_rset(rs))
	return -EINVAL;

    local_count = rk_resource_set_get_num_procs(rs);
    if (local_count == 0) {
	return 0;
    }
    local_size = local_count * sizeof(pid_t);

    if (verify_area(VERIFY_WRITE, procs, local_size)) {
	return -EFAULT;
    }

    /* copy process ids to buffer */
    for (e = rs->rs_proc_list.next, i = 0; e != &(rs->rs_proc_list);
	 e = e->next, i++) {
	rs_proc = list_entry(e, struct rs_proc_list, rs_proc_list);
	if (copy_to_user(&(procs[i]), &(rs_proc->rs_proc_pid),
			 sizeof(pid_t))) {
	    return -EFAULT;
	}
    }

    return i;
}

asmlinkage int sys_rk_resource_set_get_num_procs(rk_resource_set_t rs)
{
#ifdef DEBUG_RK
    printk("rk_rset_get_num_procs: rs(0x%x)\n", rs);
#endif				/* DEBUG_RK */

    if (!rk_valid_rset(rs))
	return -EINVAL;

    return (rk_resource_set_get_num_procs(rs));
}


#endif

asmlinkage int
sys_rk_resource_set_get_name(rk_resource_set_t rs, char *name)
{
#ifdef DEBUG_RK
    printk("rk_rset_get_name: rs(0x%x)\n", rs);
#endif				/* DEBUG_RK */

    if (verify_area(VERIFY_WRITE, name, RSET_NAME_LEN)) {
	return -EFAULT;
    }

    if (!rk_valid_rset(rs))
	return -EINVAL;

    /* copy resource name */
    if (copy_to_user(name, rs->rs_name, RSET_NAME_LEN)) {
	return -EFAULT;
    }

    return RK_SUCCESS;
}

asmlinkage int
sys_rk_resource_set_set_name(rk_resource_set_t rs, char *name)
{
#ifdef DEBUG_RK
    printk("rk_rset_set_name: rs(0x%x)\n", rs);
#endif				/* DEBUG_RK */

    if (!rk_valid_rset(rs))
	return -EINVAL;

    if (verify_area(VERIFY_READ, name, RSET_NAME_LEN)) {
	return -EFAULT;
    }

    /* copy resource name */
    if (copy_from_user(rs->rs_name, name, RSET_NAME_LEN)) {
	return -EFAULT;
    }

    return RK_SUCCESS;
}

int rk_resource_set_set_name(rk_resource_set_t rs, char *name) 
{
  strcpy(rs->rs_name, name);
  rs->rs_name[RSET_NAME_LEN-1] = '\0';      /* terminate string */
  return RK_SUCCESS;
}

asmlinkage rk_reserve_t
sys_rk_resource_set_get_cpu_rsv(rk_resource_set_t rs)
{
#ifdef DEBUG_RK
    printk("rk_rset_get_rsv: rs(0x%x)\n", rs);
#endif				/* DEBUG_RK */

    if (!rk_valid_rset(rs))
	return NULL;

#ifdef DEBUG_RK
    printk("(cpu: %x)", rs->rs_cpu);
#endif				/* DEBUG_RK */

    return rs->rs_cpu;
}

int rk_valid_rset(rk_resource_set_t rset)
{
    rk_resource_set_t rs;
    struct list_head *e;

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

    for (e = rk_resource_set_root.next; e != &rk_resource_set_root;
	 e = e->next) {
	rs = list_entry(e, struct rk_resource_set, rs_rs);
	if (rs == rset) {
#ifdef DEBUG_RK
	    printk("true\n");
#endif				/* DEBUG_RK */
	    return TRUE;
	}
    }

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

/* Update the current cpu reserve of the resource set.
 * This function will choose the eligible cpu reserve 
 * (~RSV_DEPLETED & RSV_ACTIVE) and set it to rs_cpu of the resources_set.
 * It returns the chosen cpu reserve or NULL_RESERVE if no eligible reserve
 * is available.
 */
rk_reserve_t rk_resource_set_update_cpu(rk_resource_set_t rs)
{
    struct list_head *cpu_list;
    rk_reserve_t rsv;

    /* check all cpu reserve in the list */
    cpu_list = &(rs->rs_cpu_list);
    for (cpu_list = cpu_list->next; cpu_list != &(rs->rs_cpu_list);
	 cpu_list = cpu_list->next) {
	/* get an reserve */
	rsv = list_entry(cpu_list, struct rk_reserve, rsv_rs_link);
	if (cpu_reserve_eligible(rsv)) {
	    /* found eligible cpu reserve */
	    rs->rs_cpu = rsv;
	    return rsv;
	}
    }
    rs->rs_cpu = NULL_RESERVE;
    return NULL_RESERVE;
}

/* Update the sch_mode of the resource set.
 * If all cpu reserves attached to the resource set have HARD enforcement,
 * the sch_mode is HARD. Otherwise, it is SOFT.
 * I haven't considered the FIRM TYPE sch_mode yet.
 */
static void rk_resource_set_update_sch_mode(rk_resource_set_t rs)
{
    struct list_head *cpu_list;
    rk_reserve_t rsv;
    rk_reserve_mode_t mode = RSV_HARD;

    /* check all cpu reserve in the list */
    cpu_list = &(rs->rs_cpu_list);
    for (cpu_list = cpu_list->next; cpu_list != &(rs->rs_cpu_list);
	 cpu_list = cpu_list->next) {
	/* get an reserve */
	rsv = list_entry(cpu_list, struct rk_reserve, rsv_rs_link);
	mode &= (rsv->rsv_reserve_param.enf_mode & RSV_HARD);
    }
    /* If all cpu reserves have HARD enforcement */
    if (mode & RSV_HARD)
	rs->sch_mode = RSV_HARD;
    else
	rs->sch_mode = RSV_SOFT;

}

/* Check and activate/deactivate the default resource set to the task.
 * If all resource sets attached to the task have HARD enforcement,
 * we should unlink the default resource set from the task.
 * Otherwise, the default resource is automatically linked
 */
void
rk_resource_set_check_default_rs(struct rs_proc_list *rs_proc,
				 unsigned int arg)
{
    struct task_struct *tsk = rs_proc->rs_proc_task;
    struct list_head *rs_list;
    struct resource_set_list *entry;
    rk_resource_set_t rs;
    rk_reserve_mode_t mode = RSV_HARD;

    if (tsk->rs_list.resource_set_list.next == NULL) {
	/* Hmm..Something is wrong */
	INIT_LIST_HEAD(&(tsk->rs_list.resource_set_list));
	return;
    }
    /* check all resource sets in the list */
    rs_list = &((&tsk->rs_list)->resource_set_list);
    for (rs_list = rs_list->next;
	 rs_list != &((&tsk->rs_list)->resource_set_list);
	 rs_list = rs_list->next) {
	/* get an resource set */
	entry =
	    list_entry(rs_list, struct resource_set_list,
		       resource_set_list);
	rs = entry->rk_resource_set;
	mode &= (rs->sch_mode & RSV_HARD);
    }
    /* If all resource sets have HARD scheduling mode */
    if (mode & RSV_HARD) {
	/* delete default reserve */
	if (tsk->default_rs_added) {
	    /* Detach the default resource set to the task */
	    default_resource_set_detach_process(rk_default_resource_set,
						tsk);
	    tsk->default_rs_added = 0;
	}
    } else {
	/* add default reserve */
	if (!tsk->default_rs_added) {
	    /* Should add at the end */
	    static int
	     default_resource_set_attach_process(rk_resource_set_t,
						 struct task_struct *);
	    default_resource_set_attach_process(rk_default_resource_set,
						tsk);
	    tsk->default_rs_added = 1;
	}
    }
}

/* Reschedule the eligible resource set with highest priority 
 * (top of the rs_list). If no eligible resource set is available,
 * halt the task. Otherwise, update the scheduling paramemter of the task
 */
void rk_resource_set_schedule(struct rs_proc_list *rs_proc,
			      unsigned int arg)
{
    struct task_struct *tsk = rs_proc->rs_proc_task;
    struct list_head *rs_list;
    struct resource_set_list *entry;
    rk_resource_set_t rs;

    if (tsk->rs_list.resource_set_list.next == NULL) {
	/*Something is wrong */
	printk("rs_set_schedule: error! no rs to schedule! %d\n", dbgvar);
	INIT_LIST_HEAD(&(tsk->rs_list.resource_set_list));
#ifdef HALT_IT
	goto halt_it;
#else
	tsk->rk_resource_set = NULL;
        tsk->rk_cannot_schedule = FALSE;
	cpu_reserve_setscheduler(tsk, SCHED_OTHER, 0);

	return;
#endif
    }

    /* deactivate previous rs */
    {
	struct list_head *ptr;

	/* delete from previous rs proc list if this rs is not part of the
	 * resource_set_list of the process
	 */

	for (ptr = tsk->rs_list.resource_set_list.next;
	     (ptr != &tsk->rs_list.resource_set_list)
	     &&
	     (list_entry
	      (ptr, struct resource_set_list,
	       resource_set_list)->rk_resource_set !=
	      tsk->rk_resource_set); ptr = ptr->next);

	if (list_entry
	    (ptr, struct resource_set_list,
	     resource_set_list)->rk_resource_set != tsk->rk_resource_set) {
	    for (ptr = tsk->rk_resource_set->rs_proc_list.next;
		 (ptr != &tsk->rk_resource_set->rs_proc_list)
		 &&
		 (list_entry
		  (ptr, struct rs_proc_list,
		   rs_proc_list)->rs_proc_task != tsk); ptr = ptr->next);

	    if (list_entry
		(ptr, struct rs_proc_list,
		 rs_proc_list)->rs_proc_task == tsk) {
#ifdef RK_MUTEX_DEBUG_3
		printk
		    ("resource_set_schedule: removing inherited rs(%x) from list\n",
		     (unsigned int) tsk->rk_resource_set);
#endif
		list_del(ptr);
		free(ptr);
		tsk->rk_resource_set = NULL;
		tsk->rk_base_resource_set = NULL;
	    }
	}

    }

    /* check all resource sets in the list */
    rs_list = &((&tsk->rs_list)->resource_set_list);

#if 0
    if (rs_list ==  &((&tsk->rs_list)->resource_set_list) ){

#ifdef HALT_IT
      /* follow the old procedure below */
#else
      goto no_halt;
#endif
    }
#endif

    for (rs_list = rs_list->next;
	 rs_list != &((&tsk->rs_list)->resource_set_list);
	 rs_list = rs_list->next) {
	/* get an resource set */
	entry =
	    list_entry(rs_list, struct resource_set_list,
		       resource_set_list);
	rs = entry->rk_resource_set;
	/* If this resource set is eligible */
	if (rs->rs_cpu) {
	    /* set rs to current resource set of the task */
	    tsk->rk_resource_set = rs;
	    tsk->rk_base_resource_set = rs;

	    cpu_reserve_set_base_sched_params(tsk, rs->rs_cpu->rsv_rsv);

#ifdef  RK_MUTEX_DEBUG_3
	    printk
		("rk_resource_set_schedule: after set_base_sched_params rs(%x) pid(%d) prior(%d) cannot_schedule(%d)\n",
		 (unsigned int) tsk->rk_resource_set, tsk->pid,
		 (int) tsk->rt_priority, (int) tsk->rk_cannot_schedule);
#endif

	    //cpu_reserve_sched_reserve_enable(rs_proc, rs->rs_cpu->rsv_rsv);

#ifdef APPLE_DEBUG
	    printk("schdule cpu (%x) rs(%x) to pid(%d) \n",
		   (unsigned int) rs->rs_cpu, (unsigned int) rs,
		   (unsigned int) tsk->pid);
#endif				/* APPLE_DEBUG */
	    return;
	}
    }

    /* if the rs == 0 then try to reinherit */
    {
	void try_reinheritance(struct task_struct *);

	try_reinheritance(tsk);
	if (tsk->rk_resource_set && tsk->rk_resource_set->rs_cpu) {
#ifdef  RK_MUTEX_DEBUG_3
	    printk
		("rk_resource_set_schedule: assigning rs(%x) to pid(%d)\n",
		 (unsigned int) tsk->rk_resource_set, tsk->pid);
#endif
	    return;
	}
    }

    /* no eligible resource set, halt it */
  halt_it:
    tsk->rk_resource_set = NULL_RESOURCE_SET;
    cpu_reserve_sched_reserve_disable(rs_proc);
#ifdef APPLE_DEBUG
    printk("no eligible rs .. halt pid (%d) \n", tsk->pid);
#endif				/* APPLE_DEBUG */
#if 0
  no_halt: 
    tsk->rk_resource_set = NULL;
    tsk->rk_cannot_schedule = FALSE;
    cpu_reserve_setscheduler(tsk, SCHED_OTHER, 0);
    //printk("no rs attach ....run it as non-realtime (%d) \n", tsk->pid);
#endif
}

/* Update the accounting of the current task 
 * if its scheduling parameter changes 
 */
void rk_resource_set_adjust_accounting(void)
{
    cpu_tick_data_t now;

    /* If no change of current cpu reserve */
    if ((current->rk_resource_set == rk_current_resource_set) &&
	((!current->rk_resource_set) ||
	 (current->rk_resource_set->rs_cpu == rk_current_cpu_reserve))) {
	return;
    }

    /* stop old accounting */
    if (rk_current_cpu_reserve) {
	rk_rdtsc(&now);
//printk("Stop6\n");
	rk_current_cpu_reserve->rsv_ops->
	    stop_account(rk_current_cpu_reserve, &now);
    }
    /* update rk_current_resource_set and rk_current_cpu_reserve
     * and start new accounting 
     */
    rk_current_resource_set = current->rk_resource_set;

    if (rk_current_resource_set) {
	rk_current_cpu_reserve = rk_current_resource_set->rs_cpu;
	if (rk_current_cpu_reserve) {
//printk("Start8\n");
	    rk_current_cpu_reserve->rsv_ops->
		start_account(rk_current_cpu_reserve);
	    if (rk_current_cpu_reserve->rsv_state & RSV_IS_DEPLETED) {
#ifdef DEBUG_RK
		printk("(enforcing)");
#endif				/* DEBUG_RK */
		rk_current_cpu_reserve->rsv_ops->
		    enforce(rk_current_cpu_reserve);
#ifdef DEBUG_RK
		printk("(enforced)");
#endif				/* DEBUG_RK */
	    }
	}
    } else {
	/* no eligible rs to run */
	rk_current_cpu_reserve = NULL_RESERVE;
    }
}

/* Update the accounting of the expected current task
 * if its scheduling parameter changes
 */
void rk_resource_set_adjust_expect_accounting(void)
{
    cpu_tick_data_t now;
    extern struct task_struct *expected_current;

    /* If no change of current cpu reserve */
    if ((expected_current->rk_resource_set == rk_current_resource_set) &&
	((!expected_current->rk_resource_set) ||
	 (expected_current->rk_resource_set->rs_cpu ==
	  rk_current_cpu_reserve))) {
	return;
    }

    /* stop old accounting */
    if (rk_current_cpu_reserve) {
	rk_rdtsc(&now);
	rk_current_cpu_reserve->
	    rsv_ops->stop_account(rk_current_cpu_reserve, &now);
    }
    /* update rk_current_resource_set and rk_current_cpu_reserve
     * and start new accounting
     */
    rk_current_resource_set = expected_current->rk_resource_set;

    if (rk_current_resource_set) {
	rk_current_cpu_reserve = rk_current_resource_set->rs_cpu;
	if (rk_current_cpu_reserve) {
	    rk_current_cpu_reserve->
		rsv_ops->start_account(rk_current_cpu_reserve);
	    if (rk_current_cpu_reserve->rsv_state & RSV_IS_DEPLETED) {
#ifdef DEBUG_RK
		printk("(enforcing)");
#endif				/* DEBUG_RK */
		rk_current_cpu_reserve->
		    rsv_ops->enforce(rk_current_cpu_reserve);
#ifdef DEBUG_RK
		printk("(enforced)");
#endif				/* DEBUG_RK */
	    }
	}
    } else {
	/* no eligible rs to run */
	rk_current_cpu_reserve = NULL_RESERVE;
    }
}

/* Detach resource set from the specified rs_proc.
 * Then choose the next eligible resource set to run.
 * If no eligible resource set is available, 
 * halt the process.
 */
void
int_rk_resource_set_detach_process(struct rs_proc_list *rs_proc,
				   rk_resource_set_t rs)
{
    __rk_resource_set_detach_process(rs, rs_proc->rs_proc_task);
}

/*delete a resource set from the list in the task*/
static void
rk_resource_set_tsk_delete_rs(rk_resource_set_t rs,
			      struct task_struct *tsk)
{
    struct list_head *head;
    struct list_head *ptr;
    struct resource_set_list *rs_list;

    if (tsk->rs_list.resource_set_list.next == NULL) {
	INIT_LIST_HEAD(&(tsk->rs_list.resource_set_list));
	return;
    }
    head = &((&tsk->rs_list)->resource_set_list);
    for (ptr = head->next; ptr != head; ptr = ptr->next) {
	rs_list =
	    list_entry(ptr, struct resource_set_list, resource_set_list);
	if (rs_list->rk_resource_set == rs) {
	    list_del(ptr);
	    free(rs_list);
	    return;
	}
    }

}

void rk_resource_bind_socket(struct task_struct *p, struct socket *sock)
{
	struct rs_sock_list *rs_sock;
	unsigned long flags;


	/* if the task is associated with a RS create and add an rs_sock_list */
	//if (p->rk_resource_set) 
	  {
		rs_sock = malloc(sizeof(struct rs_sock_list));
		bzero(rs_sock, sizeof(struct rs_sock_list));
		rs_sock->sk = sock->sk;
		
		rk_spin_lock(flags);
		list_add(&rs_sock->rs_sock_list, &p->rs_sock_list);
		rk_spin_unlock(flags);

		if(p->rk_base_resource_set != NULL)
		  resource_set_attach_socket(p->rk_resource_set, sock, RSV_NULL);
	
	}

}

asmlinkage int sys_rk_cleanup(void)
{
    extern void rk_reserve_cleanup(void);

    /* destroy resource set */
    struct list_head *rs_list;
    rk_resource_set_t rs;

    printk("Syscall: rk_cleanup is invoked\n");
    rs_list = &rk_resource_set_root;
    for (rs_list = rs_list->next; rs_list != &rk_resource_set_root;) {
	rs = list_entry(rs_list, struct rk_resource_set, rs_rs);
	rs_list = rs_list->next;
	rk_resource_set_destroy(rs);
    }
    printk("Syscall: rk_cleanup completed\n");
    rk_reserve_cleanup();
    if (need_cleanup) {
	rk_disable();
    }

    /* Should clear all proc here */
    return RK_SUCCESS;
}


//Sourav's additions


     int __fast_resource_set_swap(rk_resource_set_t rs, struct task_struct *tsk, rk_resource_set_t rs1)
{
    struct rs_proc_list *rs_proc = NULL;
    struct list_head *proc_list;
    struct resource_set_list *new_rs_ptr= NULL;
    unsigned long flags;


    struct list_head *head;
    struct list_head *ptr;
    struct resource_set_list *rs_list;

   rk_spin_lock(flags);

    /***************Detach from the old resource set first *************/

    /* XXX: delete from reservation list - fix */
    proc_list = &(rs->rs_proc_list);
    for (proc_list = proc_list->next; proc_list != &(rs->rs_proc_list);
	 proc_list = proc_list->next) {
	/* get an rs_proc */
	rs_proc = list_entry(proc_list, struct rs_proc_list, rs_proc_list);
	if (rs_proc->rs_proc_task == tsk) {
	    /* found process */
	    list_del(&(rs_proc->rs_proc_list));

	    /* delete a resource set from the list in the task struct */
	    {
	      //unsigned long flags;
#if 0
		static void
		    rk_resource_set_tsk_delete_rs(rk_resource_set_t,
						  struct task_struct *);
		//rk_spin_lock(flags);
		rk_resource_set_tsk_delete_rs(rs, tsk);
#endif
		
	  if (tsk->rs_list.resource_set_list.next == NULL) {
	INIT_LIST_HEAD(&(tsk->rs_list.resource_set_list));
    }
	  
    head = &((&tsk->rs_list)->resource_set_list);
    for (ptr = head->next; ptr != head; ptr = ptr->next) {
	rs_list =
	    list_entry(ptr, struct resource_set_list, resource_set_list);
	if (rs_list->rk_resource_set == rs) {
	  list_del(ptr);
	  free(rs_list);
	    
	  //new_rs_ptr = rs_list;
	  break;
	}
    }			
//rk_spin_unlock(flags);
	    }


//	    if (tsk->rk_resource_set == rs) {
		/* If this is the current resource set of the task,
		 * we need to reschedule resource set 
		 */
#if 0
		rk_resource_set_check_default_rs(rs_proc, 0);
#endif
#if 0
		if (tsk->rs_list.resource_set_list.next ==
		    &(tsk->rs_list.resource_set_list)) {
		    extern void
			cpu_reserve_setscheduler(struct task_struct *p,
						 unsigned long policy,
						 unsigned long
						 rt_priority);
		    /* In the future, we will have to attach it to DEFAULT RS */
		    tsk->rk_resource_set = NULL;
		    tsk->rk_base_resource_set = NULL;
		    tsk->rk_cannot_schedule = FALSE;
		    cpu_reserve_setscheduler(tsk, SCHED_OTHER, 0);
		} else {
		    dbgvar = 7;
		    rk_resource_set_schedule(rs_proc, 0);
		    dbgvar = 0;
		}



		
	    /* destroy it */
	    INIT_LIST_HEAD(&rs_proc->rs_proc_list);	/* just for sure */
	    free(rs_proc);

	    /*??? */
	    if (current == tsk)
		rk_resource_set_adjust_accounting();
#endif

	    INIT_LIST_HEAD(&rs_proc->rs_proc_list);/* just for sure */
	    
#if 1	    
	    free(rs_proc);
#endif
	    //rk_spin_unlock(flags);

	    /* done, get out */
	    break;
	}
    }

    /*****************Attach to the new resource set now *******************/


#ifdef PREEMPT_FIX
    tsk->rk_resource_set = rs1;
#else
#endif


if (tsk->periodicType == PERIODIC) {
	if (tsk->period_timer->tmr_rsv != NULL) {
	    printk("Error: timer rsv set in an unreserved task?\n");
	}
	tsk->period_timer->tmr_rsv = rs1->rs_cpu;
    }

#if 1
 new_rs_ptr = malloc(sizeof(struct resource_set_list));
 bzero(new_rs_ptr, sizeof(struct resource_set_list));
#endif

 new_rs_ptr->rk_resource_set = rs1;


    /* move this to below */
    /* tsk->rk_resource_set = rs1; */

 /* add process in to the proc_list */

 /** Following should not be done as rs_proc is already present ***/
#if 1
 rs_proc = malloc(sizeof(struct rs_proc_list));
 bzero(rs_proc, sizeof(struct rs_proc_list));
#endif
 rs_proc->rs_proc_task = tsk;
 rs_proc->rs_proc_pid = tsk->pid;


#ifdef DEBUG_RK
    printk("(adding to list %d)", tsk->pid);
#endif				/* DEBUG_RK */

    //rk_spin_lock(flags);
    list_add(&rs_proc->rs_proc_list, &rs1->rs_proc_list);

#if 1
    /* Initialize it */
    if (tsk->rs_list.resource_set_list.next == NULL) {
	void rk_proc_process_create(pid_t);
	INIT_LIST_HEAD(&(tsk->rs_list.resource_set_list));
	//printk("fst\n");

    }

    list_add(&new_rs_ptr->resource_set_list,
	     &(&tsk->rs_list)->resource_set_list);
#endif    

    //rk_spin_unlock(flags);
    /* attach/detach default resource set depending on
     * the task reserve state and schedule to the eligible
     * resource set w/ highest priority
     */
    //rk_resource_set_check_default_rs(rs_proc, 0);

    dbgvar = 6;
    rk_resource_set_schedule(rs_proc, 0);
    dbgvar = 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 */



      //printk("test1\n");
    if (current == tsk)		/* &&  rk_current_resource_set != rs1 ????
				   OK, that test is performed in 
				   adjust_accounting */
	rk_resource_set_adjust_accounting();

   rk_spin_unlock(flags);


    return RK_SUCCESS;
}
