
/*
 * rk_sched.c: scheduler hooks
 *
 * 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.h>

#ifdef CONFIG_MEASURE
#include <linux/measure.h>
#endif				/* CONFIG_MEASURE */

#ifdef	DEBUG_RK
 /**/
#undef	DEBUG_RK_SCHED
     /**/
#endif				/*DEBUG_RK */
void (*rk_schedule_hook) (struct task_struct *, struct task_struct *);

void (*rk_resource_bind_hook) (struct task_struct *p, struct socket * sock);

extern void rk_resource_bind_socket(struct task_struct *, struct socket *);

struct task_struct *expected_current = (void *) -1;

void rk_schedule_cpu(struct task_struct *prev, struct task_struct *next)
{
    cpu_tick_data_t now;
    rk_resource_set_t prev_rs = prev->rk_resource_set;
    rk_resource_set_t next_rs = next->rk_resource_set;
    unsigned long flags;

    rk_spin_lock(flags);
    /* should assign prev_rs and next_rs here in order to be atomic -Apple */
    prev_rs = prev->rk_resource_set;
    next_rs = next->rk_resource_set;

#ifdef CONFIG_MEASURE
    /* XXX: check against wycc's code */
    measure_contextswap(next->pid);
#endif

#ifdef DEBUG_RK_SCHED
#ifdef	DEBUG_RK_ENFORCE
    DEBUG_RK_ENFORCE {
	printk("rk_schedule_cpu: pid(%d) rs(0x%x) -> pid(%d) rs(0x%x)\n",
	       prev->pid, (int) prev_rs, next->pid, (int) next_rs);
    }
    DEBUG_RK_ENFORCE_NOT {
	if (prev_rs || next_rs) {
	    printk
		("rk_schedule_cpu: pid(%d) rs(0x%x) -> pid(%d) rs(0x%x)\n",
		 prev->pid, (int) prev_rs, next->pid, (int) next_rs);
	}
    }
#else
    if (prev_rs || next_rs) {
	printk("rk_schedule_cpu: pid(%d) rs(0x%x) -> pid(%d) rs(0x%x)\n",
	       prev->pid, (int) prev_rs, next->pid, (int) next_rs);
    }
#endif
#endif

    if (prev_rs != rk_current_resource_set) {
#ifdef EXTRA_WARN
	printk("schedule_cpu: prev rs is not the same as current!\n");
	printk("Prev: %p [%d]     Curr: %p\n", prev_rs, prev->pid,
	       rk_current_resource_set);
#endif
	rk_current_resource_set = prev_rs;
	if (prev_rs) {
	    rk_current_cpu_reserve = prev_rs->rs_cpu;
	} else {
	    rk_current_cpu_reserve = NULL;
	}
    }
    if ((prev_rs != next_rs) || (rk_current_resource_set == 0)) {
	/* if there is a current resource set, stop it */
	if (rk_current_resource_set) {
	    if (prev_rs->rs_cpu) {
		if (prev_rs->rs_cpu->rsv_state & RSV_IS_RUNNING) {
		    rk_rdtsc(&now);

		    rk_resource_set_stop_account(prev_rs, &now);
		    if (next_rs == NULL_RESOURCE_SET) {
			/* "jiffy" is needed */
#ifdef CONFIG_MEASURE
			measure_reserve_swapto(NULL);
#endif				/* CONFIG_MEASURE */
		    }
		}
	    } else {
		printk
		    ("schedule_cpu: current resource set not running.\n");
	    }
	}

	/* if there is a resource set for next, start it */
#ifdef DEBUG_RK
	printk("[schedule_cpu:%x]", next_rs);
#endif				/* DEBUG_RK */
	if ((rk_current_resource_set = next_rs)) {
	    /* the above IS an assignment, not just a == comparison */
#ifdef CONFIG_MEASURE
	    measure_reserve_swapto(next_rs->rs_cpu);
#endif				/* CONFIG_MEASURE */
	    rk_current_cpu_reserve = next_rs->rs_cpu;

	    rk_resource_set_start_account(next_rs);
	} else {
	    rk_current_cpu_reserve = NULL_RESERVE;
	}
    }

    expected_current = next;

    rk_spin_unlock(flags);
}

void rk_enable_schedule_cpu(void)
{
    if (!rk_schedule_hook) {
	rk_schedule_hook = rk_schedule_cpu;
#ifdef	DEBUG_RK
	printk("rk_enable_schedule_cpu: rk_schedule_hook enabled\n");
#endif
    }

    if (!rk_resource_bind_hook) {
     
      rk_resource_bind_hook = rk_resource_bind_socket;
    }

}

void rk_disable_schedule_cpu(void)
{
    if (rk_schedule_hook) {
	rk_schedule_hook = (void *) 0;
#ifdef	DEBUG_RK
	printk("rk_disable_schedule_cpu: rk_schedule_hook disabled\n");
#endif
    }

    if (rk_resource_bind_hook) {
     
      rk_resource_bind_hook = NULL;
    }

}



#ifdef __RK__

#include <rk/rk.h>
#endif				/* __RK__ */
