[Date Prev][Date Next] [Chronological] [Thread] [Top]

Re: [rtl] Release 9F Problems...



On Thu, Oct 01, 1998 at 05:13:02PM -0400, Donald Gaffney wrote:
> 
> Hello RTLers,
> 
> I've been playing around with release 2.0.35-9F a little bit and my
> feeling is that it is not quite as stable as 2.0.33-0.6 that I did

Could you try your tests with the two attached files replacing
rtl/include/rtl_sched.h and rtl/schedulrs/rtl_sched.c?
Appreciate it.

/* a primitive real-time scheduler 
copyright Victor Yodaiken, Michael Barabanov
History: Barabanov
         modified Oleg Subbotin, Ramesh Nalluri, April 1998
         modified Victor Yodaiken, August 1998
             Added compatability macros
             changed search loop
	     replaced old style r_cli with rtl_no_interrupt
	     removed x86 code
*/


/* This is the interrupt latency + scheduler latency,
   The user needs to determine this and hardcode it accordingly */



#define ADJUSTUP  23 /*if time to run is no more than this time ahead, run*/
#define ADJUSTDOWN  10 /*set timer to interrupt this time less than requested*/

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/errno.h>
#include <linux/malloc.h>
#include <linux/cons.h>

#include <asm/system.h>
#include <linux/timex.h>
#include <asm/rt_time.h>
#include <asm/rt_irq.h>
#include <rtl_sync.h>

static int linux_irq_state;
static int rtl_active = 0;
#define		rtl_make_unrtactive() { SFIF = linux_irq_state; rtl_active=0;}
#define 	rtl_make_rtactive() {linux_irq_state = SFIF; SFIF = 0; rtl_active=1;}
#define 	rtl_is_rtactive() (rtl_active)


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

#ifndef RTL_FPU
#define rtl_fpu_switch(a,b)  ;
#define rtl_fpu_task_init(a,b)  { printk("RTL error: tried to get the \
                                          non fp scheduling module to \
		                          create a fp real time task!\n");\
	                                  kfree(st); return -ENOMEM;}
#define rtl_fpu_init()  ;
#define rtl_fpu_task_delete(x)  ;
#else
static void rtl_fpu_task_init(RT_TASK *, RT_TASK *);
static void rtl_fpu_switch(RT_TASK *, RT_TASK *);
static void rtl_fpu_init(void);
static void rtl_fpu_task_delete(RT_TASK *);
#endif

#ifdef RTL_DEBUG
void debug_resched(RT_TASK * ,RTIME );
#endif

#include <asm/segment.h>
#include "x86/switch.h"



RT_TASK *rt_tasks;

RT_TASK *rtl_current;

RT_TASK rtl_linux_task;
#define rtl_is_linux_task(a) (a == &rtl_linux_task)

int rt_startup(void (*fn)(int), int data)
{
	r_sti();
	(*fn)(data);
	rt_task_delete(rtl_current);
	
	/* should never reach this line */
	return 0;
}
	

int rtl_task_init(RT_TASK *task, void (*fn)(int), int data, int stack_size, 
			int priority,int fp) 
{
	int *st;
	long interrupt_state;

	if (task->magic == RT_TASK_MAGIC) {
		return -EINVAL;
	}

	st = (int *) kmalloc(stack_size, GFP_KERNEL);	
	if (!st) {
		return -ENOMEM;
	}

	task->priority = priority; 
	task->magic = RT_TASK_MAGIC; 
	task->state = RT_TASK_DORMANT; 
	task->stack_bottom = st;
	task->stack = st + stack_size / sizeof(int);
        if(fp){
		rtl_fpu_task_init(task,rtl_current);
		}
	else task->uses_fp = 0;
	x86_init_stack(task,data,rt_startup);
	rtl_no_interrupts(interrupt_state);
	task->next = rt_tasks;
	rt_tasks = task;
	rtl_restore_interrupts(interrupt_state);
	return 0;
}



void rt_schedule(void)
{
	RTIME now;
	RT_TASK *t;
	RT_TASK *newt = 0; /* new task to run, if any */
	RT_TASK *nextt = 0; /* task that will preempt, if any */
	unsigned long interrupt_state;

	rtl_no_interrupts(interrupt_state);
	now = rt_get_time();

        /* find a task that can be run  */
	for (t = rt_tasks; t; t = t->next) {
		if( (t->state == RT_TASK_DELAYED)&&
				( t->resume_time < now + ADJUSTUP)){
		   t->state = RT_TASK_READY;
		}
		if(t->state == RT_TASK_READY)
			if (!newt || (t->priority < newt->priority)) {
				newt = t;
			}
	}
	/* find the pre-empting task */
	for (t = rt_tasks; t; t = t->next) {
		if( (t->state == RT_TASK_DELAYED) &&
				(!newt || (t->priority < newt->priority)) &&
				(!nextt ||(t->resume_time < nextt->resume_time))
				)
			nextt = t;
	}

				

	/* DEBUG */
	{
		static int nolinux = 0;
		if(newt) nolinux++;
		else nolinux = 0;
		if(nolinux > 100000){
			conpr("HELP NO LINUX EVER!!!");
			nolinux = 0;
			newt->resume_time = now+100000;
		}
	}
	/* END DEUBG */


	/* if nextt there is a preemptor so set timer to preempt
	   if !nextt
	        if there is a rt task, turn off the timer
		if there is no rt task, linux needs a clock interrupt
		*/
	if (nextt) {
		rt_set_timer(nextt->resume_time - ADJUSTDOWN ); 
	} else{
	       	if(newt) { rt_no_timer(); }
		else { rt_set_timer(now+LATCH);}
	}

	/* if there is no rt task to run, then run linux */
	if(!newt){
		newt = &rtl_linux_task;
		rtl_make_unrtactive();
	}
	else {
		rtl_make_rtactive();
	}
	/* if the new task is the current task nothing to do */
	if ( newt == rtl_current) {
			rtl_restore_interrupts(interrupt_state);
			return;
		}
	else{ /* switch out old, switch in new */
		if (newt->uses_fp)rtl_fpu_switch(newt,rtl_current);
		rt_switch_to(newt);
		rtl_restore_interrupts(interrupt_state);
	}
}



int rt_task_delete(RT_TASK *task)
{
	RT_TASK *t;
	int found = 0, count = 0;
	long interrupt_state;

	rtl_no_interrupts(interrupt_state);
        
	if (task->magic != RT_TASK_MAGIC) {
		rtl_restore_interrupts(interrupt_state);
		return -EINVAL;
	}
	
	if (task != rt_tasks) {
		for (t = rt_tasks; t; t = t->next) {
			if (t->next == task) {
				t->next = task->next;
				found = 1;
				break;
			}
		}
		if (!found) {
			rtl_restore_interrupts(interrupt_state);
			return -EINVAL;
		}
	} else {
		conpr("RTL Delete first task\n");
		rt_tasks = task->next;
	}
	task->state = RTL_TASK_ZOMBIE;

	
	/* 
	 *If the current task is the task that is being freed, dont free it
	 * but wait for the scheduler to run and switch it for you 
	 */

	if ( rtl_current == task ){
		rt_set_timer(rt_get_time());
		rtl_restore_interrupts(interrupt_state);
		/* 
		 * wait for the scheduler to switch the current task and then free
		 */
		while (rtl_current == task){
			if (count++ >= 1000000) {
				conpr("RT_SCHED:PANIC: The task with priority ");
				conprn(task->priority);
				conpr(" has not been switched yet\n");
				return -EINVAL;
			}
		}
	}
		/*
		 * Now happily free it
		 */

	rtl_fpu_task_delete(task);
	if(!rtl_is_rtactive())
		kfree(task->stack_bottom);
	else conpr("RTL Delete while active!");
	rtl_restore_interrupts(interrupt_state);
	return 0;
}


int rt_task_suspend(RT_TASK *task)
{
	task->state = RT_TASK_DORMANT;
	rt_schedule();
	return 0;
}


int rt_task_wakeup(RT_TASK *task)
{
	task->state = RT_TASK_READY;
	rt_schedule();
	return 0;
}


int rt_task_wait(void)
{
	long interrupt_state;
	rtl_no_interrupts(interrupt_state);
	rtl_current->state = RT_TASK_DELAYED;
	rtl_current->resume_time += rtl_current->period; 
	rt_schedule();
	rtl_no_interrupts(interrupt_state);
	return 0;
}

int rt_task_make_periodic(RT_TASK *task, RTIME start_time, RTIME period)
{
	long interrupt_state;
	if (task->magic != RT_TASK_MAGIC) {
		return -EINVAL;
	}
	rtl_no_interrupts(interrupt_state);
	task->resume_time = start_time;
	task->period = period;
	task->state = RT_TASK_DELAYED;
	rt_set_timer(rt_get_time());
	rtl_restore_interrupts(interrupt_state);
	return 0;
}

int init_module(void)
{
	long interrupt_state;
	rtl_no_interrupts(interrupt_state);
	rt_no_timer();
	rt_tasks = 0;
	rtl_current = &rtl_linux_task;
	rtl_linux_task.priority = RT_LOWEST_PRIORITY;
	rtl_linux_task.next = 0;
	rtl_linux_task.state = RT_TASK_READY;
	rtl_fpu_init();
	rt_request_timer(&rt_schedule);
	rtl_restore_interrupts(interrupt_state);
	return 0;
}


void cleanup_module(void)
{
	RT_TASK *t;
	RT_TASK *next_t;
	rt_free_timer();
	for (t = rt_tasks; t; t = next_t) {
		next_t = t->next;
		if (t != &rtl_linux_task) {
			rt_task_delete(t);
		}
	}
}


#ifndef __RT__SCHED__
#define __RT__SCHED__

#include <asm/rt_time.h>
#define RT_TASK_MAGIC 0x754d2774

#define RT_LOWEST_PRIORITY 1000000
#ifndef RTL_FPU
#define RTL_FPU_STRUCT 
#endif


enum {RT_TASK_READY, RT_TASK_DELAYED, RT_TASK_DORMANT,RT_TASK_ACTIVE,RTL_TASK_ZOMBIE};

struct rt_task_struct {
	int *stack; 	/* hardcoded */
	int uses_fp;	/* this one is too   */
	int magic;
	int state;
	int *stack_bottom;
	int priority;
	RTIME period;
	RTIME resume_time;
	struct rt_task_struct *next;
	RTL_FPU_STRUCT   /*if RTL_FPU is not defined this is null */
};

typedef struct rt_task_struct RT_TASK;

extern RT_TASK *rt_current;

#define rt_task_init(a,b,c,d,e) rtl_task_init(a,b,c,d,e,0)
#define rt_fptask_init(a,b,c,d,e) rtl_task_init(a,b,c,d,e,1)
extern int rtl_task_init(RT_TASK *task, void (*fn)(int data), int data, int stack_size,  int priority, int use_fpu);

extern int rt_task_delete(RT_TASK *task);
extern int rt_task_wait(void);

extern int rt_task_suspend(RT_TASK *task);
extern int rt_task_wakeup(RT_TASK *task);

extern int rt_task_make_periodic(RT_TASK *task, RTIME start_time, RTIME period);

extern inline void rt_use_fp(int flag)
{
	rt_current->uses_fp = flag;
}


#endif