[PATCH] GlobalEDF Scheduler for Aperiodic Tasks

Sree Harsha Konduri sreehars at buffalo.edu
Wed Sep 25 05:40:07 UTC 2013


---
 cpukit/sapi/include/confdefs.h                     |   22 ++
 cpukit/score/Makefile.am                           |    2 +
 .../score/include/rtems/score/schedulerglobaledf.h |  137 ++++++++
 cpukit/score/src/schedulerglobaledf.c              |  369 ++++++++++++++++++++
 doc/user/schedule.t                                |    9 +
 testsuites/smptests/smpedf01/Makefile.am           |   22 ++
 testsuites/smptests/smpedf01/init.c                |   46 +++
 testsuites/smptests/smpedf01/smpedf01.doc          |   18 +
 testsuites/smptests/smpedf01/smpedf01.scn          |    8 +
 testsuites/smptests/smpedf01/system.h              |   39 +++
 10 files changed, 672 insertions(+)
 create mode 100644 cpukit/score/include/rtems/score/schedulerglobaledf.h
 create mode 100644 cpukit/score/src/schedulerglobaledf.c
 create mode 100644 testsuites/smptests/smpedf01/Makefile.am
 create mode 100644 testsuites/smptests/smpedf01/init.c
 create mode 100644 testsuites/smptests/smpedf01/smpedf01.doc
 create mode 100644 testsuites/smptests/smpedf01/smpedf01.scn
 create mode 100644 testsuites/smptests/smpedf01/system.h

diff --git a/cpukit/sapi/include/confdefs.h b/cpukit/sapi/include/confdefs.h
index 24c768f..50744c5 100644
--- a/cpukit/sapi/include/confdefs.h
+++ b/cpukit/sapi/include/confdefs.h
@@ -625,6 +625,7 @@ const rtems_libio_helper rtems_fs_init_helper =
 
 #if !defined(RTEMS_SMP)
   #undef CONFIGURE_SCHEDULER_SIMPLE_SMP
+  #undef CONFIGURE_SCHEDULER_GLOBALEDF
 #endif
 
 /* If no scheduler is specified, the priority scheduler is default. */
@@ -633,6 +634,7 @@ const rtems_libio_helper rtems_fs_init_helper =
     !defined(CONFIGURE_SCHEDULER_PRIORITY_SMP) && \
     !defined(CONFIGURE_SCHEDULER_SIMPLE) && \
     !defined(CONFIGURE_SCHEDULER_SIMPLE_SMP) && \
+    !defined(CONFIGURE_SCHEDULER_GLOBALEDF) &&	\
     !defined(CONFIGURE_SCHEDULER_EDF) && \
     !defined(CONFIGURE_SCHEDULER_CBS)
   #if defined(RTEMS_SMP) && defined(CONFIGURE_SMP_APPLICATION)
@@ -681,6 +683,26 @@ const rtems_libio_helper rtems_fs_init_helper =
 #endif
 
 /*
+ * If the GlobalEDF SMP Scheduler is selected, then configure for
+ * it.
+ */
+#if defined(CONFIGURE_SCHEDULER_GLOBALEDF)
+  #include <rtems/score/schedulerglobaledf.h>
+  #define CONFIGURE_SCHEDULER_ENTRY_POINTS SCHEDULER_GLOBAL_EDF_ENTRY_POINTS
+
+  /**
+   * This defines the memory used by the priority scheduler.
+   */
+
+  #define CONFIGURE_MEMORY_FOR_SCHEDULER ( \
+  _Configure_From_workspace(sizeof(Scheduler_global_EDF_Control)) )
+
+  #define CONFIGURE_MEMORY_PER_TASK_FOR_SCHEDULER ( \
+    _Configure_From_workspace(sizeof(Scheduler_global_EDF_Per_thread)) )
+#endif
+
+
+/*
  * If the Simple Priority Scheduler is selected, then configure for it.
  */
 #if defined(CONFIGURE_SCHEDULER_SIMPLE)
diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am
index c9d2d47..afe25a1 100644
--- a/cpukit/score/Makefile.am
+++ b/cpukit/score/Makefile.am
@@ -106,6 +106,7 @@ endif
 
 if HAS_SMP
 include_rtems_score_HEADERS += include/rtems/score/schedulersimplesmp.h
+include_rtems_score_HEADERS += include/rtems/score/schedulerglobaledf.h
 endif
 
 ## src
@@ -121,6 +122,7 @@ endif
 
 if HAS_SMP
 libscore_a_SOURCES += src/schedulerprioritysmp.c
+libscore_a_SOURCES += src/schedulerglobaledf.c
 libscore_a_SOURCES += src/schedulersimplesmp.c
 libscore_a_SOURCES += src/schedulersmpstartidle.c
 libscore_a_SOURCES += src/smp.c
diff --git a/cpukit/score/include/rtems/score/schedulerglobaledf.h b/cpukit/score/include/rtems/score/schedulerglobaledf.h
new file mode 100644
index 0000000..5bbfbea
--- /dev/null
+++ b/cpukit/score/include/rtems/score/schedulerglobaledf.h
@@ -0,0 +1,137 @@
+/**
+ * @file
+ *
+ * @brief Global EDF Scheduler API
+ *
+ * @ingroup ScoreSchedulerGlobalEDF
+ */
+
+/*
+ *  Copyright (C) 2011 On-Line Applications Research Corporation (OAR).
+ *
+ *  Copyright (c) 2013 embedded brains GmbH.
+ *
+ *  Copyright (c) 2013 Sree Harsha Konduri
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#ifndef _RTEMS_SCORE_SCHEDULERGLOBAL_EDF_H
+#define _RTEMS_SCORE_SCHEDULERGLOBAL_EDF_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rtems/score/scheduler.h>
+#include <rtems/score/schedulersimple.h>
+#include <rtems/score/schedulerpriority.h>
+#include <rtems/score/scheduleredf.h>
+#include <rtems/score/smplock.h>
+/**
+ * @defgroup ScoreSchedulerGlobalEDF Global EDF Scheduler
+ *
+ * @ingroup ScoreScheduler
+ *
+ * The G-EDF Scheduler extends the EDF Scheduler for a SMP System with more than
+ * one Processor/Core. It allocates a processor for the processor count
+ * ready threads based on their deadlines/priorities.  The thread priority/deadline is
+ * the only information to determine the scheduling decision.
+ * Threads with an allocated processor are in the scheduled chain.  After
+ * initialization the scheduled chain has exactly processor count nodes.  Each
+ * processor has exactly one allocated thread after initialization. 
+ * The ready queue is a Red-Black Tree that is built on the deadline/priority of the threads.
+ * All enqueue and extract operations may exchange threads with the scheduled
+ * chain.  One thread will be added and another will be removed.  The scheduled chain
+ * and ready queue are ordered according to the thread priority order.  The
+ * insert operations for the scheduled chain are O(count of number of cores), and the
+ * ready queue insert operations take O(logarithm(number of ready threads)).
+ *
+ * The thread preempt mode will be ignored.
+ *
+ * @{
+ */
+
+typedef enum {
+    THREAD_IN_READY_QUEUE, 
+    THREAD_IN_SCHEDULED_QUEUE,
+  } THREAD_PLACED_IN;
+
+typedef struct {
+  /* Ready Queue using the RedBlack Tree Structure*/
+  RBTree_Control ready;
+  /* Chain Control that uses the scheduled tasks */
+  Chain_Control scheduled;
+   /* THREAD LOCATION IDENTIFICATION*/
+  THREAD_PLACED_IN thread_location;
+  /*Instance of SMP_lock for locking ready queue*/
+  SMP_lock_Control smp_lock_ready_queue;
+
+} Scheduler_global_EDF_Control;
+
+  typedef struct {
+  /* Use an integer to identify whether a task is on ready or scheduled queues */
+  /* THREAD LOCATION IDENTIFICATION*/
+  THREAD_PLACED_IN thread_location;
+
+  /* The state of tasks in the queue */
+  Scheduler_EDF_Queue_state queue_state;
+
+  /* RBTree Node information*/
+  RBTree_Node Node;  /* Use an integer to identify whether a task is on ready or scheduled queues */
+
+    /* Thread information of every thread*/
+  Thread_Control *thread;
+
+  } Scheduler_global_EDF_Per_thread;
+
+/**
+ * @brief Entry points for the Global EDF Scheduler.
+ */
+#define SCHEDULER_GLOBAL_EDF_ENTRY_POINTS \
+  { \
+    _Scheduler_global_EDF_Initialize, \
+    _Scheduler_global_EDF_Schedule, \
+    _Scheduler_global_EDF_Yield, \
+    _Scheduler_global_EDF_Extract, \
+    _Scheduler_global_EDF_Allocate, \
+    _Scheduler_EDF_Free, \
+    _Scheduler_EDF_Update, \
+    _Scheduler_global_EDF_Enqueue_priority_fifo, \
+    _Scheduler_global_EDF_Enqueue_priority_lifo, \
+    _Scheduler_global_EDF_Extract, \
+    _Scheduler_EDF_Priority_compare, \
+    _Scheduler_EDF_Release_job, \
+    _Scheduler_default_Tick, \
+    _Scheduler_global_EDF_Start_idle \
+  }
+
+void _Scheduler_global_EDF_Initialize( void );
+
+void _Scheduler_global_EDF_Enqueue_priority_fifo( Thread_Control *thread );
+
+void _Scheduler_global_EDF_Enqueue_priority_lifo( Thread_Control *thread );
+
+void _Scheduler_global_EDF_Extract( Thread_Control *thread );
+
+void *_Scheduler_global_EDF_Allocate( Thread_Control *thread);// added Allocate to smp scheduler.
+
+void _Scheduler_global_EDF_Yield( Thread_Control *thread );
+
+void _Scheduler_global_EDF_Schedule( Thread_Control *thread );
+
+void _Scheduler_global_EDF_Start_idle(
+  Thread_Control *thread,
+  Per_CPU_Control *cpu
+);
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/* end of include file */
diff --git a/cpukit/score/src/schedulerglobaledf.c b/cpukit/score/src/schedulerglobaledf.c
new file mode 100644
index 0000000..a4ff9a2
--- /dev/null
+++ b/cpukit/score/src/schedulerglobaledf.c
@@ -0,0 +1,369 @@
+/**
+ * @file
+ *
+ * @brief Global EDF Scheduler Implementation
+ *
+ * @ingroup ScoreSchedulerGlobalEDF
+ */
+
+/*
+ * Copyright (c) 2013 embedded brains GmbH.
+ *
+ * Copyright (c) Sree Harsha Konduri
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#if HAVE_CONFIG_H
+  #include "config.h"
+#endif
+
+#include <rtems/score/schedulerglobaledf.h>
+#include <rtems/score/schedulersimple.h>
+#include <rtems/score/schedulerpriorityimpl.h>
+#include <rtems/score/schedulersmpimpl.h>
+#include <rtems/score/rbtree.h>
+#include <rtems/score/rbtreeimpl.h>
+#include <rtems/score/scheduleredfimpl.h>
+#include <rtems/score/wkspace.h>
+static Scheduler_global_EDF_Control *_Scheduler_global_EDF_Instance( void )
+{
+  return _Scheduler.information;
+}
+
+static int _Scheduler_EDF_RBTree_compare_function
+(
+  const RBTree_Node* n1,
+  const RBTree_Node* n2
+)
+{
+  Priority_Control value1 = _RBTree_Container_of
+    (n1,Scheduler_global_EDF_Per_thread,Node)->thread->current_priority;
+  Priority_Control value2 = _RBTree_Container_of
+    (n2,Scheduler_global_EDF_Per_thread,Node)->thread->current_priority;
+  /*
+   * This function compares only numbers for the red-black tree,
+   * but priorities have an opposite sense.
+   */
+  return (-1)*_Scheduler_Priority_compare(value1, value2);
+}
+
+
+void _Scheduler_global_EDF_Initialize( void )
+{
+  Scheduler_global_EDF_Control *self =  _Workspace_Allocate_or_fatal_error( sizeof( *self ));
+
+  _RBTree_Initialize_empty( &self->ready,
+			    &_Scheduler_EDF_RBTree_compare_function,
+			    0
+			  );
+  _Chain_Initialize_empty( &self->scheduled );
+  _SMP_lock_Initialize(&self->smp_lock_ready_queue);
+  _Scheduler.information = self;
+}
+
+static void _Scheduler_global_EDF_Allocate_processor(
+  Thread_Control *scheduled,
+  Thread_Control *victim
+)
+{
+  Per_CPU_Control *cpu_of_scheduled = scheduled->cpu;
+  Per_CPU_Control *cpu_of_victim = victim->cpu;
+  Thread_Control *heir;
+
+  scheduled->is_scheduled = true;
+  victim->is_scheduled = false;
+
+   _Per_CPU_Acquire( cpu_of_scheduled );
+
+  if ( scheduled->is_executing ) {
+    heir = cpu_of_scheduled->heir;
+    cpu_of_scheduled->heir = scheduled;
+  } else {
+    heir = scheduled;
+  }
+
+   _Per_CPU_Release( cpu_of_scheduled );
+
+  if ( heir != victim ) {
+      const Per_CPU_Control *cpu_of_executing = _Per_CPU_Get();
+    heir->cpu = cpu_of_victim;
+    cpu_of_victim->heir = heir;
+    cpu_of_victim->dispatch_necessary = true;
+    if ( cpu_of_victim != cpu_of_executing ) {
+      _Per_CPU_Send_interrupt( cpu_of_victim );
+    }
+  }
+}
+
+static Thread_Control *_Scheduler_global_EDF_Get_lowest_scheduled(
+  Scheduler_global_EDF_Control *self
+)
+{
+  Thread_Control *lowest_ready = NULL;
+  Chain_Control *scheduled = &self->scheduled;
+
+  if ( !_Chain_Is_empty( scheduled ) ) {
+    lowest_ready = (Thread_Control *) _Chain_Last( scheduled );
+  }
+
+  return lowest_ready;
+}
+
+static Thread_Control *_Scheduler_global_EDF_Get_highest_ready(
+  Scheduler_global_EDF_Control *self
+)
+{
+  Thread_Control *highest_ready = NULL;
+
+  _SMP_lock_Acquire(&self->smp_lock_ready_queue);
+  if ( !_RBTree_Is_null(&self->ready) ) {
+
+    RBTree_Node *first = _RBTree_First(&self->ready, RBT_LEFT);
+    Scheduler_global_EDF_Per_thread *sched_info =  _RBTree_Container_of(first,
+								      Scheduler_global_EDF_Per_thread, Node);
+
+    highest_ready = sched_info->thread;
+  }
+  _SMP_lock_Release(&self->smp_lock_ready_queue);
+  return highest_ready;
+}
+
+static void _Scheduler_global_EDF_Move_from_scheduled_to_ready(
+  Scheduler_global_EDF_Control *self, 
+  RBTree_Control *ready_chain,
+  Thread_Control *scheduled_to_ready
+)
+{
+ Scheduler_global_EDF_Per_thread *sched_info =
+    (Scheduler_global_EDF_Per_thread*) scheduled_to_ready->scheduler_info;
+   RBTree_Node *node = &(sched_info->Node); 
+ _Chain_Extract_unprotected( &scheduled_to_ready->Object.Node );
+  _SMP_lock_Acquire(&self->smp_lock_ready_queue);
+
+ _RBTree_Insert( ready_chain, node );
+  sched_info->queue_state = SCHEDULER_EDF_QUEUE_STATE_YES;
+  _SMP_lock_Release(&self->smp_lock_ready_queue);
+ }
+
+static void _Scheduler_global_EDF_Move_from_ready_to_scheduled(
+  Scheduler_global_EDF_Control *self,
+  Chain_Control *scheduled_chain,
+  Thread_Control *ready_to_scheduled
+)
+{
+    Scheduler_global_EDF_Per_thread *sched_info =
+    (Scheduler_global_EDF_Per_thread*) ready_to_scheduled->scheduler_info;
+  _SMP_lock_Acquire(&self->smp_lock_ready_queue);
+   RBTree_Node *node = &(sched_info->Node);
+   _RBTree_Extract_unprotected(&self->ready, node );
+   sched_info->queue_state = SCHEDULER_EDF_QUEUE_STATE_NOT_PRESENTLY;
+  _SMP_lock_Release(&self->smp_lock_ready_queue);
+   _Scheduler_simple_Insert_priority_fifo( scheduled_chain, ready_to_scheduled );
+}
+
+static void _Scheduler_global_EDF_Insert(
+  RBTree_Control *chain,
+  Thread_Control *thread,
+  RBTree_Node *node
+)
+{
+  Scheduler_global_EDF_Control *self = _Scheduler_global_EDF_Instance();
+   Scheduler_global_EDF_Per_thread *sched_info =
+    (Scheduler_global_EDF_Per_thread*) thread->scheduler_info;
+   sched_info->thread_location = THREAD_IN_READY_QUEUE;
+  _SMP_lock_Acquire(&self->smp_lock_ready_queue);
+   _RBTree_Insert( chain, node);
+  sched_info->queue_state = SCHEDULER_EDF_QUEUE_STATE_YES;
+  _SMP_lock_Release(&self->smp_lock_ready_queue);
+}
+
+static void _Scheduler_global_EDF_ChainInsert(
+  Chain_Control *chain,
+  Thread_Control *thread,
+  Chain_Node_order order
+)
+{
+ Scheduler_global_EDF_Per_thread *sched_info =
+    (Scheduler_global_EDF_Per_thread*) thread->scheduler_info;
+
+  sched_info->thread_location = THREAD_IN_SCHEDULED_QUEUE;
+  _Chain_Insert_ordered_unprotected( chain, &thread->Object.Node, order );
+}
+
+
+
+static void _Scheduler_global_EDF_Enqueue_ordered(
+  Scheduler_global_EDF_Control *self,
+  Thread_Control *thread,
+  Chain_Node_order order,
+  RBTree_Node *node
+)
+{
+
+  /*
+   * The scheduled chain has exactly processor count nodes after
+   * initialization, thus the lowest priority scheduled thread exists.
+   */
+  Scheduler_global_EDF_Per_thread *sched_info =
+   (Scheduler_global_EDF_Per_thread*) thread->scheduler_info;
+  RBTree_Node *node_thread = &(sched_info->Node);
+  if(thread->is_in_the_air) {
+    Thread_Control *highest_ready = _Scheduler_global_EDF_Get_highest_ready(self);
+    thread->is_in_the_air = false;
+    if (
+      highest_ready != NULL
+      && (_Scheduler_EDF_RBTree_compare_function(node_thread,node))
+    ) {
+      _Scheduler_SMP_Allocate_processor( highest_ready, thread );
+
+       _Scheduler_global_EDF_Insert(&self->ready, thread, node );
+      _Scheduler_global_EDF_Move_from_ready_to_scheduled( self,&self->scheduled, highest_ready );
+    } else {
+      thread->is_scheduled = true;
+
+      _Scheduler_global_EDF_ChainInsert(&self->scheduled, thread, order );
+    }
+  } else {
+    Thread_Control *lowest_scheduled =  _Scheduler_global_EDF_Get_lowest_scheduled(self);
+
+     if ( ( *order )( &thread->Object.Node, &lowest_scheduled->Object.Node ) ) {
+    _Scheduler_global_EDF_Allocate_processor( thread, lowest_scheduled );
+
+    _Scheduler_global_EDF_ChainInsert( &self->scheduled, thread, order );
+
+    _Scheduler_global_EDF_Move_from_scheduled_to_ready(
+       self,
+      &self->ready,
+      lowest_scheduled
+    );
+     } else {
+      _Scheduler_global_EDF_Insert( &self->ready, thread, node);
+      }
+  }
+}
+
+void *_Scheduler_global_EDF_Allocate( Thread_Control *the_thread)
+{
+  void *sched;
+  Scheduler_global_EDF_Per_thread *schinfo;
+
+  sched = _Workspace_Allocate( sizeof(Scheduler_global_EDF_Per_thread) );
+
+  if ( sched ) {
+    the_thread->scheduler_info = sched;
+    schinfo = (Scheduler_global_EDF_Per_thread *)(the_thread->scheduler_info);
+    schinfo->thread = the_thread;
+    schinfo->queue_state = SCHEDULER_EDF_QUEUE_STATE_NEVER_HAS_BEEN;
+  }
+
+  return sched;
+}
+
+void _Scheduler_global_EDF_Enqueue_priority_lifo( Thread_Control *thread )
+{
+  _Scheduler_global_EDF_Enqueue_priority_fifo(thread);
+}
+
+void _Scheduler_global_EDF_Enqueue_priority_fifo( Thread_Control *thread )
+{
+  Scheduler_global_EDF_Control *self = _Scheduler_global_EDF_Instance();
+ Scheduler_global_EDF_Per_thread *sched_info =
+    (Scheduler_global_EDF_Per_thread*) thread->scheduler_info;
+  RBTree_Node *node = &(sched_info->Node);
+
+  _Scheduler_global_EDF_Enqueue_ordered(self,//Global EDF Control
+				       thread,//Thread
+				       _Scheduler_simple_Insert_priority_fifo_order,//Chain Order
+				       node // RB Tree Node
+				       );
+}
+
+void _Scheduler_global_EDF_Extract( Thread_Control *thread )
+{
+  Scheduler_global_EDF_Control *self = _Scheduler_global_EDF_Instance();
+
+  _Chain_Extract_unprotected( &thread->Object.Node );
+  _SMP_lock_Acquire(&self->smp_lock_ready_queue);
+
+  if ( thread->is_scheduled ) {
+    RBTree_Node *first = _RBTree_First(&self->ready, RBT_LEFT);
+    Scheduler_global_EDF_Per_thread *sched_info =  _RBTree_Container_of(first, Scheduler_global_EDF_Per_thread, Node);
+
+  _SMP_lock_Release(&self->smp_lock_ready_queue);
+    Thread_Control *highest_ready = sched_info->thread;
+
+    _Scheduler_global_EDF_Allocate_processor( highest_ready, thread );
+
+    _Scheduler_global_EDF_Move_from_ready_to_scheduled(
+	self,
+      	&self->scheduled,
+      	highest_ready
+    );
+  }
+}
+
+void _Scheduler_global_EDF_Yield( Thread_Control *thread )
+{
+  ISR_Level level;
+
+  _ISR_Disable( level );
+
+  _Scheduler_global_EDF_Extract( thread );
+  _Scheduler_global_EDF_Enqueue_priority_fifo( thread );
+
+  _ISR_Enable( level );
+}
+static void  _Scheduler_global_EDF_Schedule_highest_ready(
+Scheduler_global_EDF_Control *self,
+Thread_Control *victim
+)
+{
+ Thread_Control *highest_ready =  _Scheduler_global_EDF_Get_highest_ready(self);
+
+ _Scheduler_global_EDF_Allocate_processor(highest_ready, victim);
+ _Scheduler_global_EDF_Move_from_ready_to_scheduled(
+  self,
+  &self->scheduled,
+  highest_ready);
+}
+static void _Scheduler_global_EDF_helper_Schedule(
+  Scheduler_global_EDF_Control *self,
+  Thread_Control *thread
+)
+{
+  /*  if ( thread->is_in_the_air ) {
+    thread->is_in_the_air = false;
+
+    _Scheduler_global_EDF_Schedule_highest_ready(
+      self,
+      thread
+    );
+    }*/
+
+   _Scheduler_global_EDF_Schedule_highest_ready(
+      self,
+      thread
+    );
+}
+
+void _Scheduler_global_EDF_Schedule( Thread_Control *thread )
+{
+  Scheduler_global_EDF_Control *self = _Scheduler_global_EDF_Instance();
+  _Scheduler_global_EDF_helper_Schedule(self,
+				thread
+				);
+}
+
+void _Scheduler_global_EDF_Start_idle(
+  Thread_Control *thread,
+  Per_CPU_Control *cpu
+)
+{
+  Scheduler_global_EDF_Control *self = _Scheduler_global_EDF_Instance();
+  thread->is_scheduled = true;
+  thread->cpu = cpu;
+  _Chain_Append_unprotected( &self->scheduled, &thread->Object.Node );
+}
diff --git a/doc/user/schedule.t b/doc/user/schedule.t
index 3742038..9b01ddb 100644
--- a/doc/user/schedule.t
+++ b/doc/user/schedule.t
@@ -139,6 +139,15 @@ This algorithm is non-deterministic. When scheduling, it must consider
 which tasks are to be executed on each core while avoiding superfluous
 task migrations.
 
+ at subsection Global-Earliest Deadline First Scheduler
+
+This scheduler is an extension of the EDF scheduler to run on 
+multiple cores. This scheduler maintains the tasks with highest priority
+ or deadline proportional to @i{O(number of cores)} in a scheduled chain
+ and all the tasks are in a Red Black Tree. This scheduler is designed to
+ provide the same performance of the EDF Scheduler on a multi-core
+ environment.
+
 @subsection Earliest Deadline First Scheduler
 
 @cindex earliest deadline first scheduling
diff --git a/testsuites/smptests/smpedf01/Makefile.am b/testsuites/smptests/smpedf01/Makefile.am
new file mode 100644
index 0000000..7e11f72
--- /dev/null
+++ b/testsuites/smptests/smpedf01/Makefile.am
@@ -0,0 +1,22 @@
+
+rtems_tests_PROGRAMS = smpedf01
+smpedf_SOURCES = init.c system.h ../../support/src/locked_print.c
+
+dist_rtems_tests_DATA = smpedf.scn
+dist_rtems_tests_DATA += smpedf.doc
+
+include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP at .cfg
+include $(top_srcdir)/../automake/compile.am
+include $(top_srcdir)/../automake/leaf.am
+
+AM_CPPFLAGS += -I$(top_srcdir)/../support/include
+AM_CPPFLAGS += -DSMPTEST 
+
+LINK_OBJS = $(smpedf_OBJECTS)
+LINK_LIBS = $(smpedf_LDLIBS)
+
+smpedf$(EXEEXT): $(smpedf_OBJECTS) $(smpedf_DEPENDENCIES)
+	@rm -f smpedf$(EXEEXT)
+	$(make-exe)
+
+include $(top_srcdir)/../automake/local.am
diff --git a/testsuites/smptests/smpedf01/init.c b/testsuites/smptests/smpedf01/init.c
new file mode 100644
index 0000000..3a09ff8
--- /dev/null
+++ b/testsuites/smptests/smpedf01/init.c
@@ -0,0 +1,46 @@
+/*
+ *  COPYRIGHT (c) 1989-2011.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define CONFIGURE_INIT
+#include "system.h"
+
+#include <inttypes.h>
+rtems_task Init(rtems_task_argument arg)
+{
+  rtems_name        name;
+  rtems_id          period;
+  rtems_status_code status;
+
+  name = rtems_build_name( 'P', 'E', 'R', 'D' );
+
+  status = rtems_rate_monotonic_create( name, &period );
+  if ( status != RTEMS_SUCCESSFUL ) {
+       printf( "rtems_monotonic_create failed with status of %d.\n", status );
+    exit( 1 );
+  }
+
+  while ( 1 ) {
+    if ( rtems_rate_monotonic_period( period, 100 ) == RTEMS_TIMEOUT )
+      break; 
+  }
+
+  status = rtems_rate_monotonic_delete( period );   /* missed period so delete period and SELF */
+  if ( status != RTEMS_SUCCESSFUL ) {
+    printf( "rtems_rate_monotonic_delete failed with status of %d.\n", status );
+    exit( 1 );
+  }
+
+  status = rtems_task_delete( RTEMS_SELF );    
+  printf( "rtems_task_delete returned with status of %d.\n", status );
+  exit( 1 );
+}
diff --git a/testsuites/smptests/smpedf01/smpedf01.doc b/testsuites/smptests/smpedf01/smpedf01.doc
new file mode 100644
index 0000000..8b88ff3
--- /dev/null
+++ b/testsuites/smptests/smpedf01/smpedf01.doc
@@ -0,0 +1,18 @@
+#  COPYRIGHT (c) 1989-2011.
+#  On-Line Applications Research Corporation (OAR).
+#
+#  The license and distribution terms for this file may be
+#  found in the file LICENSE in this distribution or at
+#  http://www.rtems.com/license/LICENSE.
+#
+
+This is a simple test that verifies that each of the smp
+processors can run a task.  The init task creates and starts
+a test_task for each prcessor.  With a small delay between
+the start of each processor to allow for the processor to
+print its status.  Note:  This may need to change to a semaphore
+locked print routine at some point in the furture.
+
+After the tasks have been started the init task waits for flags
+to be set by each task indicating that they are running.  Once all
+flags are set the program terminates.
diff --git a/testsuites/smptests/smpedf01/smpedf01.scn b/testsuites/smptests/smpedf01/smpedf01.scn
new file mode 100644
index 0000000..8d54499
--- /dev/null
+++ b/testsuites/smptests/smpedf01/smpedf01.scn
@@ -0,0 +1,8 @@
+***  SMP01 TEST ***
+CPU 0 start task TA1
+CPU 1 running Task TA1
+CPU 0 start task TA2
+CPU 2 running Task TA2
+CPU 0 start task TA3
+CPU 3 running Task TA3
+*** END OF SMP 01 TEST ***
diff --git a/testsuites/smptests/smpedf01/system.h b/testsuites/smptests/smpedf01/system.h
new file mode 100644
index 0000000..02bf231
--- /dev/null
+++ b/testsuites/smptests/smpedf01/system.h
@@ -0,0 +1,39 @@
+/*
+ *  COPYRIGHT (c) 1989-2011.
+ *  On-Line Applications Research Corporation (OAR).
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.com/license/LICENSE.
+ */
+
+#include "tmacros.h"
+#include "test_support.h"
+
+/* functions */
+
+rtems_task Init(
+  rtems_task_argument argument
+);
+
+/* configuration information */
+
+#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+#define CONFIGURE_SCHEDULER_GLOBALEDF
+#define CONFIGURE_SMP_APPLICATION
+#define CONFIGURE_SMP_MAXIMUM_PROCESSORS   4 
+
+#define CONFIGURE_MAXIMUM_TASKS            \
+    (1 + CONFIGURE_SMP_MAXIMUM_PROCESSORS)
+#define CONFIGURE_MAXIMUM_SEMAPHORES 2
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#include <rtems/confdefs.h>
+
+/* global variables */
+
+/*
+ *  Keep the names and IDs in global variables so another task can use them.
+ */
-- 
1.7.9.5




More information about the devel mailing list