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

extern rk_reserve_t cpu_ceiling_reserve_create(rk_resource_set_t new_rs, cpu_reserve_attr_t attr, 
					 int priority_index);


rk_resource_set_t ceiling_rs_from_pid(int srv_pid, int clt_pid)
{
  int i;  
  struct task_struct *srv_tsk;

  srv_tsk = __rk_find_process_by_pid(srv_pid);

  if (srv_tsk == NULL)
    {
#ifdef PCP_DEBUG
      printk("PCP:ceiling rs from pid  no task found\n");
#endif
      return NULL;
    }

  if (srv_tsk->rs_ceiling_vector == NULL)
    {
#ifdef PCP_DEBUG
      printk("PCP: ceiling rs form pid no ceiling vector\n");
#endif
      return NULL;
    }

  for (i=0; i<CEILING_VECTOR_SIZE; i++)
    {
      if (srv_tsk->rs_ceiling_vector[i].pid == clt_pid)
	{
	  return srv_tsk->rs_ceiling_vector[i].rs;
	}
    }
#ifdef PCP_DEBUG
  printk("PCP: ceiling rs from pid no clt pid found\n");
#endif
  return NULL;
}


asmlinkage int
sys_rk_detach_ceiling_rs(rk_resource_set_t rs, pid_t srv_pid, pid_t clt_pid)
{
  struct task_struct *srv_tsk;
  int slot,i, ceiling ;

#ifdef PCP_DEBUG
  printk("PCP detach_ceiling_rs\n");
#endif

  srv_tsk = __rk_find_process_by_pid(srv_pid);
  if (srv_tsk == NULL)
    {
#ifdef PCP_DEBUG
      printk("PCP: detach ceiling: no task found\n");
#endif
      return -1;
    }

  if (!rk_valid_rset(rs))
    {
#ifdef PCP_DEBUG
      printk("PCP: detach rs ceiling invalid rs\n");
#endif
      return -1;
    }
  
  if (srv_tsk->rs_ceiling_vector == NULL)
    {
#ifdef PCP_DEBUG
      printk("PCP: detach rs ceiling, ceiling vector == NULL\n");
#endif
      return -1;
    }

  for (i=0;i< CEILING_VECTOR_SIZE; i++)
    {
      if (srv_tsk->rs_ceiling_vector[i].pid == clt_pid)
	{
	  srv_tsk->rs_ceiling_vector[i].pid = -1;
	  srv_tsk->rs_ceiling_vector[i].rs = NULL;
	  return 0;
	}
    }

  return 0;
}

/* Attach a resource_set ceiling to the server srv_pid to be used
 * by the server when current blocks on a request for this server
 *
 * The priority Ceiling would be determined by the max of the set
 *
 */
asmlinkage int
sys_rk_attach_ceiling_rs(rk_resource_set_t rs, pid_t srv_pid, pid_t clt_pid)
{
  struct task_struct *srv_tsk;
  int slot,i, ceiling ;

#ifdef PCP_DEBUG
  printk("PCP attach_ceiling_rs\n");
#endif

  srv_tsk = __rk_find_process_by_pid(srv_pid);
  if (srv_tsk == NULL)
    {
      //#ifdef PCP_DEBUG
      printk("PCP: attach ceiling: no task found\n");
      //#endif
      return -1;
    }

  if (!rk_valid_rset(rs))
    {
      //#ifdef PCP_DEBUG
      printk("PCP: attach rs ceiling invalid rs\n");
      //#endif
      return -1;
    }
  
  if (srv_tsk->rs_ceiling_vector == NULL)
    {
      int i;
      /* Allocate the vector */
      srv_tsk->rs_ceiling_vector = malloc(sizeof(struct resource_set_vector_t)*CEILING_VECTOR_SIZE);
      if (srv_tsk->rs_ceiling_vector == NULL)
	{
	  printk("PCP: attach rs ceiling no memory for ceiling vector\n");
	  return -1;
	}
      
      for (i=0; i< CEILING_VECTOR_SIZE; i++)
	{
	  srv_tsk->rs_ceiling_vector[i].pid = -1;
	  srv_tsk->rs_ceiling_vector[i].rs = NULL;
	}
    }

  slot = -1;
  ceiling = 0;

  /* Search for the vector and figure out the new priority ceiling */ 
  for (i=0;i< CEILING_VECTOR_SIZE; i++)
    {
      if ((srv_tsk->rs_ceiling_vector[i].pid != -1) &&
	  (ceiling < ((cpu_reserve_t)list_entry(&srv_tsk->rs_ceiling_vector[i].rs->rs_cpu_list, struct rk_reserve, rsv_rsv))->cpu_priority_index))
	ceiling = ((cpu_reserve_t)list_entry(&srv_tsk->rs_ceiling_vector[i].rs->rs_cpu_list, struct rk_reserve, rsv_rsv))->cpu_priority_index;
      if (srv_tsk->rs_ceiling_vector[i].pid == clt_pid)
	{
	  slot = i;
	}
      else if ((slot == -1) && (srv_tsk->rs_ceiling_vector[i].pid == -1))
	slot = i;
    }
  if (slot != -1)
    {
      /* get the rs priority ceiling */
      if (ceiling < ((cpu_reserve_t)list_entry(&rs->rs_cpu_list, struct rk_reserve, rsv_rsv))->cpu_priority_index)
	ceiling = ((cpu_reserve_t)list_entry(&rs->rs_cpu_list, struct rk_reserve, rsv_rsv))->cpu_priority_index;

      srv_tsk->rs_ceiling_vector[slot].rs = rs; 
      srv_tsk->rs_ceiling_vector[slot].pid = clt_pid;
      srv_tsk->rt_ceiling_priority_index = ceiling;

#ifdef PCP_DEBUG
      printk("PCP: attach ceiling rs to slot(%d), ceiling(%d)\n",slot, ceiling);
#endif

      /* Adjust the ceiling of all the reserves */ 
      for (i=0;i< CEILING_VECTOR_SIZE; i++)
	{
	  if (srv_tsk->rs_ceiling_vector[i].pid != -1)
	    {
	      ((cpu_reserve_t)list_entry(&srv_tsk->rs_ceiling_vector[i].rs->rs_cpu_list, struct rk_reserve, rsv_rsv))->cpu_priority_index = ceiling;

	      // ToDo: 
	      // adjust the deadline as well .. capacity and the like
	      
	    }
	}      
    }  
  else
    {
      //#ifdef PCP_DEBUG
      printk("PCP: attach ceiling rs no slot available!!\n");
      //#endif
      return -1;
    }

  return 0;
}

/* the base rs will determine the priority, period, and deadline of the new rs
 */

asmlinkage rk_reserve_t
sys_rk_cpu_ceiling_reserve_create(rk_reserve_t base_rsv, rk_resource_set_t new_rs,
				  cpu_reserve_attr_t cpu_attr)
{
  cpu_reserve_t base_cpu_rsv;
  cpu_reserve_attr_data_t local_attr;

  if (!rk_valid_rsv(base_rsv))
    {
      return NULL_RESERVE;
    }
  
  base_cpu_rsv = base_rsv->rsv_rsv;

#ifdef PCP_DEBUG
    printk("PCP: cpu_ceiling_reserve_create base_cpu_rsv(%p) newrs(%p), cpuattr(%p)\n", base_cpu_rsv, new_rs, cpu_attr);
#endif

    /* check region before access */
    if ((!cpu_attr) || (verify_area(VERIFY_READ, cpu_attr,
				    sizeof(cpu_reserve_attr_data_t)))) {
#ifdef PCP_DEBUG
      printk("PCP wrong cpu_attr\n");
#endif
	return NULL_RESERVE;
    }
    if (copy_from_user(&local_attr, cpu_attr,
		       sizeof(cpu_reserve_attr_data_t))) {
#ifdef PCP_DEBUG
      printk("PCP oculd not copy attr from user\n");
#endif
	return NULL_RESERVE;
    }

#if 0
    if (!rk_valid_rsv(base_cpu_rsv))
      {
#ifdef PCP_DEBUG
	printk("PCP invalid rsv\n");
#endif
	return NULL_RESERVE;
      }
#endif

    if (!rk_valid_rset(new_rs))
      {
#ifdef PCP_DEBUG
	printk("PCP invalid newrs\n");
#endif
	return NULL_RESERVE;
      }

#if 0
    local_attr.period.tv_sec = base_cpu_rsv->cpu_res_attr.period.tv_sec;
    local_attr.period.tv_nsec = base_cpu_rsv->cpu_res_attr.period.tv_nsec;
    local_attr.deadline.tv_sec = base_cpu_rsv->cpu_res_attr.deadline.tv_sec;
    local_attr.deadline.tv_nsec = base_cpu_rsv->cpu_res_attr.deadline.tv_nsec;
#endif

#if 0
    local_attr.period.tv_sec =  ((cpu_reserve_t)list_entry(&base_rs->rs_cpu_list, struct rk_reserve, rsv_rsv))->cpu_res_attr.period.tv_sec;
    local_attr.period.tv_nsec = ((cpu_reserve_t)list_entry(&base_rs->rs_cpu_list, struct rk_reserve, rsv_rsv))->cpu_res_attr.period.tv_nsec;
    local_attr.deadline.tv_sec = ((cpu_reserve_t)list_entry(&base_rs->rs_cpu_list, struct rk_reserve, rsv_rsv))->cpu_res_attr.deadline.tv_sec;
    local_attr.deadline.tv_sec = ((cpu_reserve_t)list_entry(&base_rs->rs_cpu_list, struct rk_reserve, rsv_rsv))->cpu_res_attr.deadline.tv_nsec;

#endif
    local_attr.blocking_time.tv_sec = 0;
    local_attr.blocking_time.tv_nsec = 0;


#ifdef PCP_DEBUG
    printk("PCP before ceiling create period sec(%ld), nsec(%ld) priority(%d)\n",local_attr.period.tv_sec, local_attr.period.tv_nsec, base_cpu_rsv->cpu_priority_index);
#endif
     
    return cpu_ceiling_reserve_create(new_rs, &local_attr, 
				     base_cpu_rsv->cpu_priority_index);
}
