/*
 * RT-Linux scheduler
 *
 * Written by Michael Barabanov, Victor Yodaiken
 * Copyright (C) VJY Associates LLC, 1998-1999
 * Released under the terms of the GPL
 *
 */

#ifndef __RTL__SCHED__
#define __RTL__SCHED__

#include <asm/spinlock.h>
#include <asm/ptrace.h>
#include <linux/tasks.h>
#include <linux/rtl.h>
#include <linux/malloc.h>
#include <linux/tqueue.h>

#include <rtl_conf.h>
#include <rtl_core.h>
#include <rtl_time.h>
#include <arch/rtl_fpu.h>
/* #include "../schedulers/x86/switch.h" */

extern void rtl_tq_sync (struct tq_struct *tq_s);

enum rtl_task_states {
	RTL_THREAD_READY = 1, RTL_THREAD_DELAYED = 2, RTL_THREAD_DORMANT = 4, RTL_THREAD_SUSPENDED = 8, RTL_THREAD_ACTIVE = 16, RTL_THREAD_ZOMBIE = 32, RTL_THREAD_WAIT_NEEDED = 64
};

/* for sched_param and others */
#include <linux/sched.h>

typedef struct sched_param rtl_sched_param;

#define TIMER_ABSTIME 1
#define RTL_MAX_TIMERS 32



typedef struct rtl_timer_struct *timer_t;

/* threads have no clocks. Clocks belong to schedulers.  We can add scheduling
   policies in which a scheduler juggles multiple clocks, but there is no advantage
   that I can see in allowing a thread to specify its  hardware clock
   */
   
struct rtl_thread_struct {
	int *stack;	/* hardcoded */
	int uses_fp;
	enum rtl_task_states state;
	int *stack_bottom;
	rtl_sched_param sched_param;
	struct rtl_thread_struct *next;
	RTL_FPU_CONTEXT fpu_regs;
	int cpu;
	hrtime_t resume_time;
	hrtime_t period;
	void *retval;
	int pending_signals;
	struct tq_struct free_task;
	void *user[4];
	int errno_val;
	int pad [64];
};

#define RTL_SIGNAL_DELETE 0
#define RTL_SIGNAL_WAKEUP 1
#define RTL_SIGNAL_SUSPEND 2

extern void rtl_schedule (void);

typedef struct rtl_thread_struct RTL_THREAD_STRUCT;

typedef RTL_THREAD_STRUCT *pthread_t;
 

#define rtl_is_linux_task(cpu, a) (a == &sched_data(cpu)->rtl_linux_task)

struct rtl_sched_cpu_struct {
	RTL_THREAD_STRUCT *rtl_current;
	RTL_THREAD_STRUCT rtl_linux_task;
	RTL_THREAD_STRUCT idle_task;
	RTL_THREAD_STRUCT *rtl_task_fpu_owner;	/* the task whose FP context is currently in the FPU unit */
	RTL_THREAD_STRUCT *rtl_tasks; /* the queue of  RT tasks */
	task_queue rtl_tq_cpu;
	clockid_t clock;
	hrtime_t timerset;
	int sched_user[4];	/* on x86 sched_user[0] is the Linux TS flag */
}/* __attribute__ ((aligned (64)))*/;

typedef struct rtl_sched_cpu_struct  schedule_t;

#ifdef __SMP__
extern struct rtl_sched_cpu_struct rtl_sched [NR_CPUS];
#define sched_data(cpu) (&rtl_sched [cpu])
#define LOCAL_SCHED (&rtl_sched[rtl_getcpuid()])
#else
extern struct rtl_sched_cpu_struct rtl_sched [1];
#define sched_data(cpu) (&rtl_sched[0])
#define LOCAL_SCHED (&rtl_sched[0])
#endif

#define RTL_CURRENT (LOCAL_SCHED->rtl_current)

#define RTL_TQ(cpu) (sched_data(cpu)->rtl_tq_cpu)

/* RTL-specific function TODO: write POSIX equivalents for these */


extern int pthread_delete_np (pthread_t thread);

extern int pthread_setfp_np (pthread_t thread, int flag);

extern int pthread_wakeup_np (pthread_t thread);

extern int pthread_suspend_np (pthread_t thread);

/* end RTL-specific */


/* POSIX interface */



extern inline int sched_get_priority_max(int policy) { return 1000000; }
extern inline int sched_get_priority_min(int policy) { return 0; }

extern inline pthread_t pthread_self(void) {
	return (LOCAL_SCHED)-> rtl_current;
}

extern inline int pthread_equal(pthread_t thread1, pthread_t thread2)
{
	return thread1 == thread2;
}

typedef struct STRUCT_PTHREAD_ATTR {
	int stack_size;
	rtl_sched_param sched_param;
	int cpu;
	int use_fp;
} pthread_attr_t;

extern inline int pthread_attr_init(pthread_attr_t *attr)
{
	attr->stack_size = 3000;
	attr->sched_param.sched_priority = sched_get_priority_min(0);
	attr->cpu = rtl_getcpuid();
	attr->use_fp = 0;
	return 0;
}

extern inline int pthread_attr_destroy(pthread_attr_t *attr)
{
	return 0;
}

/*
extern inline int pthread_attr_setfp_np (pthread_attr_t *attr, int flag)
{
	attr->use_fp = flag;
	return 0;
}
*/

extern inline int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
{
	attr->stack_size = stacksize;
	return 0;
}

extern inline int pthread_attr_getcpu_np(pthread_attr_t *attr, int * cpu)
{
	*cpu = attr->cpu;
	return 0;
}

extern int pthread_attr_setcpu_np(pthread_attr_t *attr, int cpu);

extern int pthread_wait_np(void);

extern int pthread_make_periodic_np (pthread_t p, hrtime_t start_time, hrtime_t period);

/* this one is deprecated */
extern int pthread_setperiod_np(pthread_t p,const struct itimerspec *t);

extern inline clockid_t rtl_getschedclock(void)
{
	return LOCAL_SCHED->clock;
}

extern int rtl_setclockmode (clockid_t clock, int mode, hrtime_t period);


extern inline void pthread_yield(void)
{
/* TODO */
}


extern inline int pthread_setschedparam(pthread_t thread, int policy,
		    const rtl_sched_param *param) {
	thread->sched_param = *param;
	return 0;
}
 
extern inline int pthread_getschedparam(pthread_t thread, int *policy,
		    rtl_sched_param *param) {
	*param = thread->sched_param;
	return 0;
}

extern inline int pthread_attr_setschedparam(pthread_attr_t *attr,
		    const rtl_sched_param *param) {
	attr->sched_param = *param;
	return 0;
}

extern inline int pthread_attr_getschedparam(const pthread_attr_t *attr,
		    rtl_sched_param *param) {
	*param = attr->sched_param;
	return 0;
}
 


extern int pthread_create (pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);

#define PTHREAD_CANCELED ((void *) -1)

extern void pthread_exit(void *retval);

/* end of POSIX interface */


#ifdef CONFIG_X86_REMOTE_DEBUG
extern void breakpoint(void);
#endif

#include <rtl_compat.h>

#ifdef CONFIG_RTL_USE_V1_API
#define pthread_make_periodic_np (PleaseUse_rt_task_make_periodic_In_V1_EmulationMode=1)

#endif

#endif
