/*
 *
 * 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.
 *
 *
 */
/* $Author: miyos $	 
 * $Id: rcl_uid_stats.c,v 1.1.1.1 2001/04/19 08:43:55 miyos Exp $
 * 
 * rcl_uid_stats.c
 *       Linux specific bookkeeping and util functions.
 */

#define __NO_VERSION__

#include <linux/kernel.h>
#include <linux/module.h>

#include <rk/rk_linux.h>
#include <rk/rk_error.h>
#include <rk/rk.h>

#include "rclmodule.h"

/*
 * Yep, I'm too lazy to create a hash table.... miyos 
 */
struct list_head          *rpal_list_head = NULL; //points to head and also record for process 0

struct resource_principal*
search_rpal_from_pid(pid_t pid){
  struct resource_control *rcl;
  
  rcl = rcl_head;
  while(rcl){
    if(rs_proc_list_search_pid(&(rcl->rpal->rs_proc_list), pid))
      return rcl->rpal;
    rcl = rcl->next;
  }
  return NULL;
}



struct resource_principal*
search_rpal_org_from_pid(pid_t pid){
  struct resource_control *rcl;

  rcl = rcl_head;
  while(rcl){
    if(rs_proc_list_search_pid(&(rcl->rpal->rs_proc_list_org), pid))
      return rcl->rpal;
    rcl = rcl->next;
  }
  return NULL;
}



/* search pid from proc_list */
inline struct rs_proc_list*
rs_proc_list_search_pid(struct list_head *proc_list_head, pid_t pid){
  struct rs_proc_list* proc_list; 
  
  proc_list = (struct rs_proc_list *)proc_list_head->next;
  if(proc_list->rs_proc_pid == pid)
  return proc_list;

  while(proc_list != (struct rs_proc_list *)proc_list_head){
    if(proc_list->rs_proc_pid == pid)
      return proc_list;
    proc_list = (struct rs_proc_list *)proc_list->rs_proc_list.next;
  }
  return NULL;
}




/*
 *
 */
inline
int register_forked_child(int uid, pid_t cpid){
  struct rs_proc_list *proc_list;
  struct resource_principal *rpal;

  /*
   * Usually parent should already be associated with rpal. 
   * Some don't because they are forked before the rkmodules are loaded
   */
  rpal = search_rpal_from_pid(current->pid);
  if(!rpal){
    printk("register_forked_child: rpal==NULL");
    return RK_ERROR;
  }
    
  /* newly forked child should at this point,
   *  1) inherit parent rset: that is why we do not allocate a 
   *                          new resource_principal for this guy.
   *      - by default, child inherits rset in rk.
   *  2) included in parent rpal structure (done here)
   */
  
  if((proc_list = rs_proc_list_search_pid(&(rpal->rs_proc_list), cpid)) == NULL){

    proc_list = create_new_proc_entry(cpid, current->p_cptr);
    list_add(&proc_list->rs_proc_list, &rpal->rs_proc_list_org);
    
    proc_list = create_new_proc_entry(cpid, current->p_cptr);
    list_add(&proc_list->rs_proc_list, &rpal->rs_proc_list);
    

  }
  return 0;
}



/* don't handle SMPs yet */
#define CPU 0

/*
 * returns number of processes in rs_proc_list
 *   in:  rs_proc_list
 *   out: numproc
 */
inline void num_proc(struct list_head *rs_proc_list, int *numproc){
  struct rs_proc_list* proc_list;
  *numproc = 0;
  proc_list = (struct rs_proc_list *)rs_proc_list->next;
  while(proc_list != (struct rs_proc_list *)rs_proc_list){
    *numproc = *numproc + 1;
    proc_list = (struct rs_proc_list *)proc_list->rs_proc_list.next;
  }
}


/*
 *  Use it only if the process is exiting.
 *  If it is going to another resource principal, shouldn't use this (for now).
 */
inline struct rs_proc_list* remove_proc_from_rpal(struct resource_principal *rpal, int pid){
  struct rs_proc_list *proc_list;
  int num = 0;
  
  if((proc_list = rs_proc_list_search_pid(&rpal->rs_proc_list, pid)) == NULL){
    printk("remove_proc_from_rpal: ERROR rs_proc_list_search_pid failed!\n");
    return NULL;
  }
  list_del(&proc_list->rs_proc_list);

  num_proc(&rpal->rs_proc_list, &num);
  // if it was the last process, free rset

#if 0  
  if(num==0 && rpal->rset != NULL ){
    if(sys_resource_set_destroy(rpal->rset) != RK_SUCCESS)
      printk("pre_execve_check: ERROR rk_resource_set_destroy!!\n");
    rpal->rset = NULL;
  }
#endif

  return proc_list;
}



//TODO: I should merge this with remove_proc_from_rpal()....
inline struct rs_proc_list* remove_proc_from_rpal_org(struct resource_principal *rpal, int pid){
  struct rs_proc_list *proc_list;
  
  if((proc_list = rs_proc_list_search_pid(&rpal->rs_proc_list_org, pid)) == NULL){
    printk("remove_proc_from_rpal: ERROR rs_proc_list_search_pid failed!\n");
    return NULL;
  }
  list_del(&proc_list->rs_proc_list);

  return proc_list;
}



inline struct rs_proc_list* create_new_proc_entry(pid_t pid, 
				  struct task_struct* tsk) {
  struct rs_proc_list       *proc_list;
  
  proc_list               = malloc(sizeof(struct rs_proc_list));
  bzero(proc_list, sizeof(struct rs_proc_list));
  INIT_LIST_HEAD(&proc_list->rs_proc_list); /* just in case.*/
  proc_list->rs_proc_pid  = pid;
  proc_list->rs_proc_task = tsk;
  return proc_list;
}



inline void set_cpuattr(cpu_reserve_attr_data_t *cpu_attr, 
			struct resource_control *rcl){
  cpu_attr->compute_time = rcl->ct;
  cpu_attr->period       = rcl->tt;
  cpu_attr->deadline     = rcl->tt;
  cpu_attr->blocking_time.tv_sec  = 0;
  cpu_attr->blocking_time.tv_nsec = 0;
  cpu_attr->start_time.tv_sec     = 0;
  cpu_attr->start_time.tv_nsec    = 0;
  cpu_attr->reserve_type = rcl->p; 
}
