[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