Index: rtai-3.6-cv.new-fast-should-yield/base/include/rtai_lxrt.h
===================================================================
--- rtai-3.6-cv.new-fast-should-yield.orig/base/include/rtai_lxrt.h	2009-05-29 14:01:50.000000000 +0200
+++ rtai-3.6-cv.new-fast-should-yield/base/include/rtai_lxrt.h	2009-07-09 14:09:12.000000000 +0200
@@ -331,7 +331,14 @@
 #define RT_SIGNAL_DISABLE	       226
 #define RT_SIGNAL_TRIGGER	       227
 
-#define MAX_LXRT_FUN		       230
+#define TASK_PREEMPTIBLE	       228        
+
+// System requests used for FPDS
+#define RT_FPDS_YIELD		       230
+#define RT_ASSIGN_VAR		       231
+#define RT_RELEASE_VAR		       232
+
+#define MAX_LXRT_FUN		       235
 
 // not recovered yet 
 // Qblk's 
@@ -411,6 +418,9 @@
 
 #define FORCE_SOFT 0x80000000
 
+// FPDS support
+#define RT_VAR_SHOULD_YIELD	1
+
 // Keep LXRT call enc/decoding together, so you are sure to act consistently.
 // This is the encoding, note " | GT_NR_SYSCALLS" to ensure not a Linux syscall, ...
 #define GT_NR_SYSCALLS  (1 << 11)
@@ -1085,6 +1095,31 @@
 	return rtai_lxrt(BIDX, SIZARG, LINUX_USE_FPU, &arg).i[LOW];
 }
 */
+
+RTAI_PROTO(int,rt_task_preemptible,(RT_TASK *task, int preemptible_flag))
+{
+	struct { RT_TASK *task; long preemptible_flag; } arg = { task, preemptible_flag };
+	return rtai_lxrt(BIDX, SIZARG, TASK_PREEMPTIBLE, &arg).i[LOW];
+}
+
+RTAI_PROTO(void, rt_fpds_yield, (void))
+{
+	struct { unsigned long dummy; } arg;
+	(void)rtai_lxrt(BIDX, SIZARG, RT_FPDS_YIELD, &arg);	
+}
+
+RTAI_PROTO(int, rt_assign_var, (int variable, int *address, int size))
+{
+	struct { int variable; int *address; int size; } arg = { variable, address, size };
+	return rtai_lxrt(BIDX, SIZARG, RT_ASSIGN_VAR, &arg).i[LOW];
+}
+
+RTAI_PROTO(int, rt_release_var, (int variable))
+{
+	struct { int variable; } arg = { variable };
+	return rtai_lxrt(BIDX, SIZARG, RT_RELEASE_VAR, &arg).i[LOW];
+}
+
 RTAI_PROTO(int, rt_get_priorities, (RT_TASK *task, int *priority, int *base_priority))
 {
 	int lpriority, lbase_priority, retval;
Index: rtai-3.6-cv.new-fast-should-yield/base/include/rtai_sched.h
===================================================================
--- rtai-3.6-cv.new-fast-should-yield.orig/base/include/rtai_sched.h	2009-05-29 14:01:50.000000000 +0200
+++ rtai-3.6-cv.new-fast-should-yield/base/include/rtai_sched.h	2009-06-02 17:05:37.000000000 +0200
@@ -48,6 +48,7 @@
 #define RT_SCHED_MBXSUSP    256
 #define RT_SCHED_SFTRDY     512
 #define RT_SCHED_SIGSUSP    (1 << 15)
+#define RT_FPDS_YIELDING	(1 << 16)
 
 #define RT_RWLINV     (11)  // keep this the highest
 #define RT_CHGPORTERR (10)
@@ -164,6 +165,7 @@
 	long *stack_bottom;
 	volatile int priority;
 	int base_priority;
+	int preemptible;
 	int policy;
 	int sched_lock_priority;
 	struct rt_task_struct *prio_passed_to;
@@ -223,6 +225,9 @@
 	struct rt_heap_t heap[2];
 
 	volatile int scheduler;
+	
+	/* FPDS */
+	volatile int *should_yield;
 
 #ifdef CONFIG_RTAI_LONG_TIMED_LIST
 	rb_root_t rbr;
@@ -314,6 +319,15 @@
   
 void rt_linux_use_fpu(int use_fpu_flag);
 
+RTAI_SYSCALL_MODE int rt_task_preemptible(struct rt_task_struct *task,
+			int preemptible_flag);
+
+RTAI_SYSCALL_MODE void rt_fpds_yield(void);
+
+RTAI_SYSCALL_MODE int rt_assign_var(int variable, void *address, int size);
+
+RTAI_SYSCALL_MODE int rt_release_var(int variable);
+
 RTAI_SYSCALL_MODE int rt_hard_timer_tick_count(void);
 
 RTAI_SYSCALL_MODE int rt_hard_timer_tick_count_cpuid(int cpuid);
Index: rtai-3.6-cv.new-fast-should-yield/base/sched/api.c
===================================================================
--- rtai-3.6-cv.new-fast-should-yield.orig/base/sched/api.c	2009-05-29 14:01:50.000000000 +0200
+++ rtai-3.6-cv.new-fast-should-yield/base/sched/api.c	2009-07-09 14:06:15.000000000 +0200
@@ -588,6 +588,123 @@
 
 
 /**
+ * @anchor rt_task_preemptible
+ * @brief
+ *
+ * rt_task_preemptible sets a @e task to be preemptible (default) or not.
+ *
+ * @param task is a pointer to the real time task.
+ *
+ * @param preemptible_flag If this parameter has a nonzero value, the
+ * task can be preempted by higher priority tasks. If the value is zero,
+ * the task will not be preempted and will continue running until it
+ * blocks or explicitly calls the scheduler.
+ *
+ * @return 0 on succes. A negative value on failure as described below:
+ * - @b EINVAL: task does not refer to a valid task.
+ */
+RTAI_SYSCALL_MODE int rt_task_preemptible(RT_TASK *task, int preemptible_flag)
+{
+	if (task->magic != RT_TASK_MAGIC) {
+		return -EINVAL;
+	}
+	task->preemptible = !!preemptible_flag;
+	return 0;
+}
+
+/**
+ * @anchor rt_fpds_yield
+ * @brief
+ *
+ * rt_fpds_yield gives control of the CPU to other READY processes
+ * that have either equal or higher priority, unlike rt_task_yield().
+ */
+RTAI_SYSCALL_MODE void rt_fpds_yield(void)
+{
+	RT_TASK *rt_current;
+	unsigned long flags;
+
+	flags = rt_global_save_flags_and_cli();
+	rt_current = RT_CURRENT;
+	
+	/*
+	 * Set the current task's state to be YIELDING, to inform the
+	 * scheduler that a context switch to a higher priority task
+	 * is allowed
+	 */
+	rt_current->state |= RT_FPDS_YIELDING;
+	rt_schedule(); /* Will not return until next context switch in */
+	rt_current->state &= ~RT_FPDS_YIELDING;
+
+	rt_global_restore_flags(flags);
+}
+
+/**
+ * @anchor rt_assign_var
+ * @brief
+ *
+ * rt_assign_var registers a user-space @address variable for access
+ * by the RTAI kernel, for fast data transfer without system call
+ * overhead.
+ *
+ * @param variable Variable identifier
+ *
+ * @param address Pointer to the variable in virtual user address space
+ *
+ * @param size Size of the variable, in bytes
+ *
+ * @return 0 on success. A negative value on failure as described below:
+ * - @b EINVAL: Invalid variable id, or invalid address
+ */
+RTAI_SYSCALL_MODE int rt_assign_var(int variable, void *address, int size)
+{
+	RT_TASK *rt_current;
+	
+	if (!access_ok(VERIFY_WRITE, address, size)) {
+		return -EINVAL;
+	}
+	
+	rt_current = RT_CURRENT;
+	
+	switch(variable) {
+	case RT_VAR_SHOULD_YIELD:
+		rt_current->should_yield = (int *)address;
+		break;
+	default:
+		return -EINVAL;
+	}
+	
+	return 0;
+}
+
+/**
+ * @anchor rt_release_var
+ * @brief
+ *
+ * rt_assign_var releases a user-space @address variable that was
+ * previously registered using rt_release_var
+ *
+ * @param variable Variable identifier
+ *
+ * @return 0 on success. A negative value on failure as described below:
+ * - @b EINVAL: Invalid variable id
+ */
+RTAI_SYSCALL_MODE int rt_release_var(int variable)
+{
+	RT_TASK *rt_current = RT_CURRENT;
+	
+	switch(variable) {
+	case RT_VAR_SHOULD_YIELD:
+		rt_current->should_yield = NULL;
+		break;
+	default:
+		return -EINVAL;
+	}
+	
+	return 0;
+}
+
+/**
  * @anchor rt_task_signal_handler
  * @brief Set the signal handler of a task.
  *
@@ -2064,6 +2181,9 @@
 EXPORT_SYMBOL(rt_get_task_state);
 EXPORT_SYMBOL(rt_linux_use_fpu);
 EXPORT_SYMBOL(rt_task_use_fpu);
+EXPORT_SYMBOL(rt_assign_var);
+EXPORT_SYMBOL(rt_release_var);
+EXPORT_SYMBOL(rt_fpds_yield);
 EXPORT_SYMBOL(rt_task_signal_handler);
 EXPORT_SYMBOL(rt_gettimeorig);
 EXPORT_SYMBOL(rt_task_make_periodic_relative_ns);
@@ -2154,6 +2274,8 @@
 EXPORT_SYMBOL(reset_rt_fun_ext_index);
 EXPORT_SYMBOL(max_slots);
 
+EXPORT_SYMBOL(rt_task_preemptible);
+
 #ifdef CONFIG_SMP
 #endif /* CONFIG_SMP */
 
Index: rtai-3.6-cv.new-fast-should-yield/base/sched/sched.c
===================================================================
--- rtai-3.6-cv.new-fast-should-yield.orig/base/sched/sched.c	2009-05-29 14:01:50.000000000 +0200
+++ rtai-3.6-cv.new-fast-should-yield/base/sched/sched.c	2009-07-09 14:11:58.000000000 +0200
@@ -289,6 +289,7 @@
 	(task->stack_bottom = (long *)&task->fpu_reg)[0] = 0;
 	task->magic = RT_TASK_MAGIC; 
 	task->policy = 0;
+	task->preemptible = 1;
 	task->owndres = 0;
 	task->prio_passed_to = 0;
 	task->period = 0;
@@ -315,6 +316,7 @@
 	task->msg_buf[0] = 0;
 	task->exectime[0] = task->exectime[1] = 0;
 	task->system_data_ptr = 0;
+	task->should_yield = NULL;
 	atomic_inc((atomic_t *)(tasks_per_cpu + cpuid));
 	if (relink) {
 		task->priority = task->base_priority = priority;
@@ -410,6 +412,7 @@
 	*(task->stack_bottom = st) = 0;
 	task->magic = RT_TASK_MAGIC; 
 	task->policy = 0;
+	task->preemptible = 1;
 	task->suspdepth = 1;
 	task->state = (RT_SCHED_SUSPENDED | RT_SCHED_READY);
 	task->owndres = 0;
@@ -446,6 +449,8 @@
 	task->exectime[0] = task->exectime[1] = 0;
 	task->system_data_ptr = 0;
 
+	task->should_yield = NULL;
+
 	task->max_msg_size[0] = (long)rt_thread;
 	task->max_msg_size[1] = data;
 	init_arch_stack();
@@ -794,6 +799,15 @@
 		RTAI_TASK_SWITCH_SIGNAL(); \
 	} while (0)
 
+
+inline int rt_fpds_preemptible(RT_TASK *task)
+{
+	return (task->priority == RT_SCHED_HIGHEST_PRIORITY
+		|| task->preemptible
+		|| (task->state & (RT_SCHED_DELAYED|RT_FPDS_YIELDING))
+		|| !(task->state & RT_SCHED_READY));
+}
+
 #ifdef CONFIG_SMP
 static void rt_schedule_on_schedule_ipi(void)
 {
@@ -945,12 +959,28 @@
 			rt_scheduling[cpuid].rqsted = 1;
 			goto sched_exit;
 		}
+		
+		/* If the current task is FPNS / non-preemptible,
+		 * don't preempt it but set a flag informing it that it should yield
+		 */
+		if (!rt_fpds_preemptible(rt_current)) {
+			/* Set a flag in the current task's TCB to signal that the current task
+			 * should yield to a higher priority task, and then exit the scheduler to
+			 * resume the current task.
+			 */
+			if (rt_current->should_yield != NULL) put_user(1, rt_current->should_yield);
+			goto sched_exit;
+		}
+		
 		if (USE_RTAI_TASKS && (!new_task->lnxtsk || !rt_current->lnxtsk)) {
 			if (!(new_task = switch_rtai_tasks(rt_current, new_task, cpuid))) {
+				/* Reset the should_yield flag for the new task just switched in */
+				if (new_task->should_yield != NULL) put_user(0, new_task->should_yield);
 				goto sched_exit;
 			}
 		}
 		rt_smp_current[cpuid] = new_task;
+
 		if (new_task->is_hard > 0 || rt_current->is_hard > 0) {
 			struct task_struct *prev;
 			unsigned long sflags;
@@ -964,6 +994,8 @@
 				SET_EXEC_TIME();
 			}
 			lxrt_context_switch(prev, new_task->lnxtsk, cpuid);
+			/* Reset the should_yield flag for the new task just switched in */
+			if (new_task->should_yield != NULL) put_user(0, new_task->should_yield);
 			if (rt_current->is_hard <= 0) {
 				RESTORE_UNLOCK_LINUX(cpuid);
 				if (rt_current->state != RT_SCHED_READY) {
@@ -1293,8 +1325,23 @@
 			rt_scheduling[cpuid].rqsted = 1;
 			goto sched_exit;
 		}
+
+		/* If the current task is FPNS / non-preemptible,
+		 * don't preempt it but set a flag informing it that it should yield
+		 */
+		if (!rt_fpds_preemptible(rt_current)) {
+			/* Set a flag in the current task's TCB to signal that the current task
+			 * should yield to a higher priority task, and then exit the scheduler to
+			 * resume the current task.
+			 */
+			if (rt_current->should_yield != NULL) put_user(1, rt_current->should_yield);
+			goto sched_exit;
+		}	
+
 		if (USE_RTAI_TASKS && (!new_task->lnxtsk || !rt_current->lnxtsk)) {
 			if (!(new_task = switch_rtai_tasks(rt_current, new_task, cpuid))) {
+				/* Reset the should_yield flag for the new task just switched in */
+				if (new_task->should_yield != NULL) put_user(0, new_task->should_yield);
 				goto sched_exit;
 			}
 		}
@@ -1312,6 +1359,8 @@
 			}
 			rt_smp_current[cpuid] = new_task;
 			lxrt_context_switch(prev, new_task->lnxtsk, cpuid);
+			/* Reset the should_yield flag for the new task just switched in */
+			if (new_task->should_yield != NULL) put_user(0, new_task->should_yield);
 			if (rt_current->is_hard <= 0) {
 				RESTORE_UNLOCK_LINUX_IN_IRQ(cpuid);
 			} else if (lnxtsk_uses_fpu(prev)) {
@@ -2643,8 +2692,8 @@
 
 	PROC_PRINT("Number of forced hard/soft/hard transitions: traps %lu, syscalls %lu\n\n", traptrans, systrans);
 
-	PROC_PRINT("Priority  Period(ns)  FPU  Sig  State  CPU  Task  HD/SF  PID  RT_TASK *  TIME\n" );
-	PROC_PRINT("------------------------------------------------------------------------------\n" );
+	PROC_PRINT("Priority  Period(ns)  Preempt  FPU  Sig  State  CPU  Task  HD/SF  PID  RT_TASK *  TIME\n" );
+	PROC_PRINT("--------------------------------------------------------------------------------------\n" );
         for (cpuid = 0; cpuid < num_online_cpus(); cpuid++) {
                 task = &rt_linux_task;
 /*
@@ -2666,9 +2715,10 @@
 					t = 1000UL*(unsigned long)llimd(task->exectime[0], 10, tuned.cpu_freq)/den;
 				}				
 			}
-			PROC_PRINT("%-10d %-11lu %-4s %-3s 0x%-3x  %1lu:%1lu   %-4d   %-4d %-4d  %p   %-lu\n",
+			PROC_PRINT("%-10d %-11lu %-9s %-4s %-3s 0x%-3x  %1lu:%1lu   %-4d   %-4d %-4d  %p   %-lu\n",
                                task->priority,
                                (unsigned long)count2nano_cpuid(task->period, task->runnable_on_cpus),
+                               task->preemptible ? "Yes" : "No",
                                task->uses_fpu || task->lnxtsk ? "Yes" : "No",
                                task->signal ? "Yes" : "No",
                                task->state,
@@ -2745,6 +2795,8 @@
 	{ { 0, stop_rt_timer },			    STOP_TIMER },
 	{ { 0, rt_task_signal_handler },	    SIGNAL_HANDLER  },
 	{ { 0, rt_task_use_fpu },		    TASK_USE_FPU },
+	{ { 0, rt_task_preemptible },	    TASK_PREEMPTIBLE },
+	{ { 1, rt_fpds_yield },			    RT_FPDS_YIELD },
 	{ { 0, rt_hard_timer_tick_count },	    HARD_TIMER_COUNT },
 	{ { 0, rt_hard_timer_tick_count_cpuid },    HARD_TIMER_COUNT_CPUID },
 	{ { 0, count2nano },			    COUNT2NANO },
@@ -2803,6 +2855,8 @@
 	{ { 1, rt_enable_signal },		    RT_SIGNAL_ENABLE },
 	{ { 1, rt_disable_signal },		    RT_SIGNAL_DISABLE },
 	{ { 1, rt_trigger_signal }, 		    RT_SIGNAL_TRIGGER },
+	{ { 1, rt_assign_var },			    RT_ASSIGN_VAR },
+	{ { 1, rt_release_var },		    RT_RELEASE_VAR },
 	{ { 0, 0 },			            000 }
 };
 
@@ -2973,6 +3027,7 @@
 	for (cpuid = 0; cpuid < NR_RT_CPUS; cpuid++) {
 		rt_linux_task.uses_fpu = 1;
 		rt_linux_task.magic = 0;
+		rt_linux_task.preemptible = 1;
 		rt_linux_task.policy = rt_linux_task.is_hard = 0;
 		rt_linux_task.runnable_on_cpus = cpuid;
 		rt_linux_task.state = RT_SCHED_READY;
