forked from Imagelibrary/rtems
score: Add clustered/partitioned scheduling
Clustered/partitioned scheduling helps to control the worst-case latencies in the system. The goal is to reduce the amount of shared state in the system and thus prevention of lock contention. Modern multi-processor systems tend to have several layers of data and instruction caches. With clustered/partitioned scheduling it is possible to honour the cache topology of a system and thus avoid expensive cache synchronization traffic. We have clustered scheduling in case the set of processors of a system is partitioned into non-empty pairwise-disjoint subsets. These subsets are called clusters. Clusters with a cardinality of one are partitions. Each cluster is owned by exactly one scheduler instance.
This commit is contained in:
@@ -57,6 +57,7 @@
|
||||
#include <bsp/smp-imps.h>
|
||||
#include <bsp/irq.h>
|
||||
#include <rtems/score/smpimpl.h>
|
||||
#include <rtems/score/schedulerimpl.h>
|
||||
|
||||
/*
|
||||
* XXXXX The following absolutely must be defined!!!
|
||||
@@ -386,7 +387,12 @@ imps_read_config_table(unsigned start, int count)
|
||||
switch (*((unsigned char *)start)) {
|
||||
case IMPS_BCT_PROCESSOR:
|
||||
if ( imps_num_cpus < rtems_configuration_get_maximum_processors() ) {
|
||||
add_processor((imps_processor *)start);
|
||||
const Scheduler_Assignment *assignment =
|
||||
_Scheduler_Get_assignment((uint32_t) imps_num_cpus);
|
||||
|
||||
if (_Scheduler_Should_start_processor(assignment)) {
|
||||
add_processor((imps_processor *)start);
|
||||
}
|
||||
} else
|
||||
imps_num_cpus++;
|
||||
start += 12; /* 20 total */
|
||||
|
||||
@@ -60,6 +60,7 @@ int pthread_create(
|
||||
bool is_fp;
|
||||
bool status;
|
||||
Thread_Control *the_thread;
|
||||
Thread_Control *executing;
|
||||
POSIX_API_Control *api;
|
||||
int schedpolicy = SCHED_RR;
|
||||
struct sched_param schedparam;
|
||||
@@ -89,6 +90,8 @@ int pthread_create(
|
||||
rtems_set_errno_and_return_minus_one( ENOSYS );
|
||||
#endif
|
||||
|
||||
executing = _Thread_Get_executing();
|
||||
|
||||
/*
|
||||
* P1003.1c/Draft 10, p. 121.
|
||||
*
|
||||
@@ -99,7 +102,7 @@ int pthread_create(
|
||||
*/
|
||||
switch ( the_attr->inheritsched ) {
|
||||
case PTHREAD_INHERIT_SCHED:
|
||||
api = _Thread_Get_executing()->API_Extensions[ THREAD_API_POSIX ];
|
||||
api = executing->API_Extensions[ THREAD_API_POSIX ];
|
||||
schedpolicy = api->schedpolicy;
|
||||
schedparam = api->schedparam;
|
||||
break;
|
||||
@@ -176,6 +179,7 @@ int pthread_create(
|
||||
status = _Thread_Initialize(
|
||||
&_POSIX_Threads_Information,
|
||||
the_thread,
|
||||
_Scheduler_Get( executing ),
|
||||
the_attr->stackaddr,
|
||||
_POSIX_Threads_Ensure_minimum_stack(the_attr->stacksize),
|
||||
is_fp,
|
||||
@@ -194,7 +198,6 @@ int pthread_create(
|
||||
|
||||
#if defined(RTEMS_SMP) && __RTEMS_HAVE_SYS_CPUSET_H__
|
||||
status = _Scheduler_Set_affinity(
|
||||
_Scheduler_Get( the_thread ),
|
||||
the_thread,
|
||||
the_attr->affinitysetsize,
|
||||
the_attr->affinityset
|
||||
|
||||
@@ -48,7 +48,6 @@ int pthread_setaffinity_np(
|
||||
|
||||
case OBJECTS_LOCAL:
|
||||
ok = _Scheduler_Set_affinity(
|
||||
_Scheduler_Get( the_thread ),
|
||||
the_thread,
|
||||
cpusetsize,
|
||||
cpuset
|
||||
|
||||
@@ -34,7 +34,7 @@ rtems_status_code rtems_clock_tick( void )
|
||||
|
||||
_Watchdog_Tickle_ticks();
|
||||
|
||||
_Scheduler_Tick( _Scheduler_Get( NULL ) );
|
||||
_Scheduler_Tick();
|
||||
|
||||
#if defined( RTEMS_SMP )
|
||||
_Thread_Enable_dispatch();
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <rtems/rtems/modesimpl.h>
|
||||
#include <rtems/rtems/support.h>
|
||||
#include <rtems/score/apimutex.h>
|
||||
#include <rtems/score/schedulerimpl.h>
|
||||
#include <rtems/score/sysstate.h>
|
||||
#include <rtems/score/threadimpl.h>
|
||||
|
||||
@@ -140,6 +141,7 @@ rtems_status_code rtems_task_create(
|
||||
status = _Thread_Initialize(
|
||||
&_RTEMS_tasks_Information,
|
||||
the_thread,
|
||||
_Scheduler_Get_by_CPU_index( _SMP_Get_current_processor() ),
|
||||
NULL,
|
||||
stack_size,
|
||||
is_fp,
|
||||
|
||||
@@ -43,7 +43,6 @@ rtems_status_code rtems_task_set_affinity(
|
||||
|
||||
case OBJECTS_LOCAL:
|
||||
ok = _Scheduler_Set_affinity(
|
||||
_Scheduler_Get( the_thread ),
|
||||
the_thread,
|
||||
cpusetsize,
|
||||
cpuset
|
||||
|
||||
@@ -820,6 +820,119 @@ const rtems_libio_helper rtems_fs_init_helper =
|
||||
#if defined(RTEMS_SMP)
|
||||
const size_t _Scheduler_Count =
|
||||
RTEMS_ARRAY_SIZE( _Scheduler_Table );
|
||||
|
||||
const Scheduler_Assignment _Scheduler_Assignments[] = {
|
||||
#if defined(CONFIGURE_SMP_SCHEDULER_ASSIGNMENTS)
|
||||
CONFIGURE_SMP_SCHEDULER_ASSIGNMENTS
|
||||
#else
|
||||
#define CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT \
|
||||
RTEMS_SCHEDULER_ASSIGN( \
|
||||
0, \
|
||||
RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL \
|
||||
)
|
||||
CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 2
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 3
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 4
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 5
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 6
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 7
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 8
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 9
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 10
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 11
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 12
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 13
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 14
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 15
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 16
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 17
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 18
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 19
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 20
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 21
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 22
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 23
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 24
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 25
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 26
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 27
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 28
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 29
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 30
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 31
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#if CONFIGURE_SMP_MAXIMUM_PROCESSORS >= 32
|
||||
, CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
#undef CONFIGURE_SMP_SCHEDULER_ASSIGN_OPT
|
||||
#endif
|
||||
};
|
||||
|
||||
RTEMS_STATIC_ASSERT(
|
||||
CONFIGURE_SMP_MAXIMUM_PROCESSORS
|
||||
== RTEMS_ARRAY_SIZE( _Scheduler_Assignments ),
|
||||
_Scheduler_Assignments
|
||||
);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIGURE_SCHEDULER_EDF)
|
||||
|
||||
@@ -26,6 +26,29 @@
|
||||
#define RTEMS_SCHEDULER_CONTEXT_NAME( name ) \
|
||||
_Configuration_Scheduler_ ## name
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
/* This object doesn't exist and indicates a configuration error */
|
||||
extern const Scheduler_Control RTEMS_SCHEDULER_INVALID_INDEX;
|
||||
|
||||
#define RTEMS_SCHEDULER_ASSIGN_DEFAULT \
|
||||
SCHEDULER_ASSIGN_DEFAULT
|
||||
|
||||
#define RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL \
|
||||
SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL
|
||||
|
||||
#define RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY \
|
||||
SCHEDULER_ASSIGN_PROCESSOR_MANDATORY
|
||||
|
||||
#define RTEMS_SCHEDULER_ASSIGN( index, attr ) \
|
||||
{ \
|
||||
( index ) < RTEMS_ARRAY_SIZE( _Scheduler_Table ) ? \
|
||||
&_Scheduler_Table[ ( index ) ] : &RTEMS_SCHEDULER_INVALID_INDEX, \
|
||||
( attr ) \
|
||||
}
|
||||
|
||||
#define RTEMS_SCHEDULER_ASSIGN_NO_SCHEDULER { NULL, 0 }
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This file should be only included in the context of <rtems/confdefs.h>.
|
||||
* Define the scheduler configuration macros only in case the corresponding
|
||||
|
||||
@@ -316,6 +316,12 @@ typedef struct {
|
||||
* @see _Per_CPU_State_change().
|
||||
*/
|
||||
Per_CPU_State state;
|
||||
|
||||
/**
|
||||
* @brief Indicates if the processor has been successfully started via
|
||||
* _CPU_SMP_Start_processor().
|
||||
*/
|
||||
bool started;
|
||||
#endif
|
||||
|
||||
Per_CPU_Stats Stats;
|
||||
@@ -462,6 +468,19 @@ static inline uint32_t _Per_CPU_Get_index( const Per_CPU_Control *per_cpu )
|
||||
return ( uint32_t ) ( per_cpu_envelope - &_Per_CPU_Information[ 0 ] );
|
||||
}
|
||||
|
||||
static inline bool _Per_CPU_Is_processor_started(
|
||||
const Per_CPU_Control *per_cpu
|
||||
)
|
||||
{
|
||||
#if defined( RTEMS_SMP )
|
||||
return per_cpu->started;
|
||||
#else
|
||||
(void) per_cpu;
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined( RTEMS_SMP )
|
||||
|
||||
static inline void _Per_CPU_Send_interrupt( const Per_CPU_Control *per_cpu )
|
||||
|
||||
@@ -102,7 +102,7 @@ typedef struct {
|
||||
);
|
||||
|
||||
/** perform scheduler update actions required at each clock tick */
|
||||
void ( *tick )( const Scheduler_Control * );
|
||||
void ( *tick )( const Scheduler_Control *, Thread_Control * );
|
||||
|
||||
/**
|
||||
* @brief Starts the idle thread for a particular processor.
|
||||
@@ -149,7 +149,12 @@ typedef struct {
|
||||
* this structure at the begin of its context structure.
|
||||
*/
|
||||
typedef struct {
|
||||
/* No fields yet */
|
||||
#if defined(RTEMS_SMP)
|
||||
/**
|
||||
* @brief Count of processors owned by this scheduler instance.
|
||||
*/
|
||||
uint32_t processor_count;
|
||||
#endif
|
||||
} Scheduler_Context;
|
||||
|
||||
/**
|
||||
@@ -198,6 +203,55 @@ extern const Scheduler_Control _Scheduler_Table[];
|
||||
#define _Scheduler_Count ( (size_t) 1 )
|
||||
#endif
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
/**
|
||||
* @brief The scheduler assignment default attributes.
|
||||
*/
|
||||
#define SCHEDULER_ASSIGN_DEFAULT UINT32_C(0x0)
|
||||
|
||||
/**
|
||||
* @brief The presence of this processor is optional.
|
||||
*/
|
||||
#define SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL SCHEDULER_ASSIGN_DEFAULT
|
||||
|
||||
/**
|
||||
* @brief The presence of this processor is mandatory.
|
||||
*/
|
||||
#define SCHEDULER_ASSIGN_PROCESSOR_MANDATORY UINT32_C(0x1)
|
||||
|
||||
/**
|
||||
* @brief Scheduler assignment.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief The scheduler for this processor.
|
||||
*/
|
||||
const Scheduler_Control *scheduler;
|
||||
|
||||
/**
|
||||
* @brief The scheduler assignment attributes.
|
||||
*
|
||||
* Use @ref SCHEDULER_ASSIGN_DEFAULT to select default attributes.
|
||||
*
|
||||
* The presence of a processor can be
|
||||
* - @ref SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL, or
|
||||
* - @ref SCHEDULER_ASSIGN_PROCESSOR_MANDATORY.
|
||||
*/
|
||||
uint32_t attributes;
|
||||
} Scheduler_Assignment;
|
||||
|
||||
/**
|
||||
* @brief The scheduler assignments.
|
||||
*
|
||||
* The length of this array must be equal to the maximum processors.
|
||||
*
|
||||
* Application provided via <rtems/confdefs.h>.
|
||||
*
|
||||
* @see _Scheduler_Table and rtems_configuration_get_maximum_processors().
|
||||
*/
|
||||
extern const Scheduler_Assignment _Scheduler_Assignments[];
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Returns an arbitrary non-NULL value.
|
||||
*
|
||||
@@ -253,8 +307,12 @@ void _Scheduler_default_Release_job(
|
||||
* This routine is invoked as part of processing each clock tick.
|
||||
*
|
||||
* @param[in] scheduler The scheduler.
|
||||
* @param[in] execution An executing thread.
|
||||
*/
|
||||
void _Scheduler_default_Tick( const Scheduler_Control *scheduler );
|
||||
void _Scheduler_default_Tick(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *executing
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Starts an idle thread.
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include <rtems/score/scheduler.h>
|
||||
#include <rtems/score/cpusetimpl.h>
|
||||
#include <rtems/score/smpimpl.h>
|
||||
#include <rtems/score/threadimpl.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -41,6 +42,28 @@ extern "C" {
|
||||
*/
|
||||
void _Scheduler_Handler_initialization( void );
|
||||
|
||||
RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get_by_CPU_index(
|
||||
uint32_t cpu_index
|
||||
)
|
||||
{
|
||||
#if defined(RTEMS_SMP)
|
||||
return _Scheduler_Assignments[ cpu_index ].scheduler;
|
||||
#else
|
||||
(void) cpu_index;
|
||||
|
||||
return &_Scheduler_Table[ 0 ];
|
||||
#endif
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get_by_CPU(
|
||||
const Per_CPU_Control *cpu
|
||||
)
|
||||
{
|
||||
uint32_t cpu_index = _Per_CPU_Get_index( cpu );
|
||||
|
||||
return _Scheduler_Get_by_CPU_index( cpu_index );
|
||||
}
|
||||
|
||||
/**
|
||||
* The preferred method to add a new scheduler is to define the jump table
|
||||
* entries and add a case to the _Scheduler_Initialize routine.
|
||||
@@ -234,11 +257,19 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Release_job(
|
||||
* scheduler which support standard RTEMS features, this includes
|
||||
* time-slicing management.
|
||||
*/
|
||||
RTEMS_INLINE_ROUTINE void _Scheduler_Tick(
|
||||
const Scheduler_Control *scheduler
|
||||
)
|
||||
RTEMS_INLINE_ROUTINE void _Scheduler_Tick( void )
|
||||
{
|
||||
( *scheduler->Operations.tick )( scheduler );
|
||||
uint32_t cpu_count = _SMP_Get_processor_count();
|
||||
uint32_t cpu_index;
|
||||
|
||||
for ( cpu_index = 0 ; cpu_index < cpu_count ; ++cpu_index ) {
|
||||
const Per_CPU_Control *cpu = _Per_CPU_Get_by_index( cpu_index );
|
||||
const Scheduler_Control *scheduler = _Scheduler_Get_by_CPU( cpu );
|
||||
|
||||
if ( scheduler != NULL ) {
|
||||
( *scheduler->Operations.tick )( scheduler, cpu->executing );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -258,6 +289,47 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Start_idle(
|
||||
( *scheduler->Operations.start_idle )( scheduler, the_thread, cpu );
|
||||
}
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
RTEMS_INLINE_ROUTINE const Scheduler_Assignment *_Scheduler_Get_assignment(
|
||||
uint32_t cpu_index
|
||||
)
|
||||
{
|
||||
return &_Scheduler_Assignments[ cpu_index ];
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE bool _Scheduler_Is_mandatory_processor(
|
||||
const Scheduler_Assignment *assignment
|
||||
)
|
||||
{
|
||||
return (assignment->attributes & SCHEDULER_ASSIGN_PROCESSOR_MANDATORY) != 0;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE bool _Scheduler_Should_start_processor(
|
||||
const Scheduler_Assignment *assignment
|
||||
)
|
||||
{
|
||||
return assignment->scheduler != NULL;
|
||||
}
|
||||
#endif /* defined(RTEMS_SMP) */
|
||||
|
||||
RTEMS_INLINE_ROUTINE bool _Scheduler_Has_processor_ownership(
|
||||
const Scheduler_Control *scheduler,
|
||||
uint32_t cpu_index
|
||||
)
|
||||
{
|
||||
#if defined(RTEMS_SMP)
|
||||
const Scheduler_Assignment *assignment =
|
||||
_Scheduler_Get_assignment( cpu_index );
|
||||
|
||||
return assignment->scheduler == scheduler;
|
||||
#else
|
||||
(void) scheduler;
|
||||
(void) cpu_index;
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__RTEMS_HAVE_SYS_CPUSET_H__)
|
||||
|
||||
RTEMS_INLINE_ROUTINE void _Scheduler_Get_processor_set(
|
||||
@@ -269,12 +341,18 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Get_processor_set(
|
||||
uint32_t cpu_count = _SMP_Get_processor_count();
|
||||
uint32_t cpu_index;
|
||||
|
||||
(void) scheduler;
|
||||
|
||||
CPU_ZERO_S( cpusetsize, cpuset );
|
||||
|
||||
for ( cpu_index = 0 ; cpu_index < cpu_count ; ++cpu_index ) {
|
||||
#if defined(RTEMS_SMP)
|
||||
if ( _Scheduler_Has_processor_ownership( scheduler, cpu_index ) ) {
|
||||
CPU_SET_S( (int) cpu_index, cpusetsize, cpuset );
|
||||
}
|
||||
#else
|
||||
(void) scheduler;
|
||||
|
||||
CPU_SET_S( (int) cpu_index, cpusetsize, cpuset );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,6 +377,44 @@ bool _Scheduler_Get_affinity(
|
||||
cpu_set_t *cpuset
|
||||
);
|
||||
|
||||
RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get(
|
||||
Thread_Control *the_thread
|
||||
)
|
||||
{
|
||||
#if defined(RTEMS_SMP)
|
||||
return the_thread->scheduler;
|
||||
#else
|
||||
(void) the_thread;
|
||||
|
||||
return &_Scheduler_Table[ 0 ];
|
||||
#endif
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE bool _Scheduler_Set(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread
|
||||
)
|
||||
{
|
||||
bool ok;
|
||||
|
||||
if ( _States_Is_dormant( the_thread->current_state ) ) {
|
||||
#if defined(RTEMS_SMP)
|
||||
_Scheduler_Free( _Scheduler_Get( the_thread ), the_thread );
|
||||
the_thread->scheduler = scheduler;
|
||||
_Scheduler_Allocate( scheduler, the_thread );
|
||||
_Scheduler_Update( scheduler, the_thread );
|
||||
#else
|
||||
(void) scheduler;
|
||||
#endif
|
||||
|
||||
ok = true;
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE bool _Scheduler_default_Set_affinity_body(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
@@ -311,22 +427,35 @@ RTEMS_INLINE_ROUTINE bool _Scheduler_default_Set_affinity_body(
|
||||
uint32_t cpu_index;
|
||||
bool ok = true;
|
||||
|
||||
(void) scheduler;
|
||||
(void) the_thread;
|
||||
|
||||
for ( cpu_index = 0 ; cpu_index < cpu_count ; ++cpu_index ) {
|
||||
#if defined(RTEMS_SMP)
|
||||
const Scheduler_Control *scheduler_of_cpu =
|
||||
_Scheduler_Get_by_CPU_index( cpu_index );
|
||||
|
||||
ok = ok
|
||||
&& ( ( CPU_ISSET_S( (int) cpu_index, cpusetsize, cpuset )
|
||||
&& scheduler == scheduler_of_cpu )
|
||||
|| ( !CPU_ISSET_S( (int) cpu_index, cpusetsize, cpuset )
|
||||
&& scheduler != scheduler_of_cpu ) );
|
||||
#else
|
||||
(void) scheduler;
|
||||
|
||||
ok = ok && CPU_ISSET_S( (int) cpu_index, cpusetsize, cpuset );
|
||||
#endif
|
||||
}
|
||||
|
||||
for ( ; cpu_index < cpu_max ; ++cpu_index ) {
|
||||
ok = ok && !CPU_ISSET_S( (int) cpu_index, cpusetsize, cpuset );
|
||||
}
|
||||
|
||||
if ( ok ) {
|
||||
ok = _Scheduler_Set( scheduler, the_thread );
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool _Scheduler_Set_affinity(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
size_t cpusetsize,
|
||||
const cpu_set_t *cpuset
|
||||
@@ -442,33 +571,6 @@ RTEMS_INLINE_ROUTINE void _Scheduler_Change_priority_if_higher(
|
||||
}
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE const Scheduler_Control *_Scheduler_Get(
|
||||
Thread_Control *the_thread
|
||||
)
|
||||
{
|
||||
(void) the_thread;
|
||||
|
||||
return &_Scheduler_Table[ 0 ];
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE bool _Scheduler_Set(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread
|
||||
)
|
||||
{
|
||||
bool ok;
|
||||
|
||||
(void) scheduler;
|
||||
|
||||
if ( _States_Is_dormant( the_thread->current_state ) ) {
|
||||
ok = true;
|
||||
} else {
|
||||
ok = false;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
RTEMS_INLINE_ROUTINE Objects_Id _Scheduler_Build_id( uint32_t scheduler_index )
|
||||
{
|
||||
return _Objects_Build_id(
|
||||
|
||||
@@ -49,9 +49,18 @@ extern "C" {
|
||||
typedef enum {
|
||||
SMP_FATAL_SHUTDOWN,
|
||||
SMP_FATAL_SHUTDOWN_EARLY,
|
||||
SMP_FATAL_BOOT_PROCESSOR_NOT_ASSIGNED_TO_SCHEDULER,
|
||||
SMP_FATAL_MANDATORY_PROCESSOR_NOT_PRESENT,
|
||||
SMP_FATAL_MULTITASKING_START_ON_UNASSIGNED_PROCESSOR,
|
||||
SMP_FATAL_SCHEDULER_WITHOUT_PROCESSORS,
|
||||
SMP_FATAL_START_OF_MANDATORY_PROCESSOR_FAILED
|
||||
} SMP_Fatal_code;
|
||||
|
||||
static inline void _SMP_Fatal( SMP_Fatal_code code )
|
||||
{
|
||||
_Terminate( RTEMS_FATAL_SOURCE_SMP, false, code );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize SMP Handler
|
||||
*
|
||||
|
||||
@@ -33,13 +33,12 @@
|
||||
#include <rtems/score/threadq.h>
|
||||
#include <rtems/score/watchdog.h>
|
||||
|
||||
#ifdef RTEMS_SMP
|
||||
#if __RTEMS_HAVE_SYS_CPUSET_H__
|
||||
#include <sys/cpuset.h>
|
||||
#include <rtems/score/cpuset.h>
|
||||
#endif
|
||||
#if defined(RTEMS_SMP)
|
||||
#include <rtems/score/cpuset.h>
|
||||
#endif
|
||||
|
||||
struct Scheduler_Control;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -517,6 +516,11 @@ struct Thread_Control_struct {
|
||||
* _Thread_Kill_zombies().
|
||||
*/
|
||||
volatile bool is_executing;
|
||||
|
||||
/**
|
||||
* @brief The scheduler of this thread.
|
||||
*/
|
||||
const struct Scheduler_Control *scheduler;
|
||||
#endif
|
||||
|
||||
#if __RTEMS_ADA__
|
||||
|
||||
@@ -141,6 +141,7 @@ void _Thread_Stack_Free(
|
||||
bool _Thread_Initialize(
|
||||
Objects_Information *information,
|
||||
Thread_Control *the_thread,
|
||||
const struct Scheduler_Control *scheduler,
|
||||
void *stack_area,
|
||||
size_t stack_size,
|
||||
bool is_fp,
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include <rtems/score/assert.h>
|
||||
#include <rtems/score/smpimpl.h>
|
||||
#include <rtems/config.h>
|
||||
#include <rtems/fatal.h>
|
||||
|
||||
#if defined(RTEMS_SMP)
|
||||
|
||||
@@ -154,7 +153,7 @@ void _Per_CPU_State_change(
|
||||
next_state == PER_CPU_STATE_SHUTDOWN
|
||||
&& new_state != PER_CPU_STATE_SHUTDOWN
|
||||
) {
|
||||
rtems_fatal( RTEMS_FATAL_SOURCE_SMP, SMP_FATAL_SHUTDOWN );
|
||||
_SMP_Fatal( SMP_FATAL_SHUTDOWN );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <rtems/score/smp.h>
|
||||
#include <rtems/config.h>
|
||||
|
||||
static void _Scheduler_default_Tick_for_executing(
|
||||
void _Scheduler_default_Tick(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *executing
|
||||
)
|
||||
@@ -83,15 +83,3 @@ static void _Scheduler_default_Tick_for_executing(
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void _Scheduler_default_Tick( const Scheduler_Control *scheduler )
|
||||
{
|
||||
uint32_t processor_count = _SMP_Get_processor_count();
|
||||
uint32_t processor;
|
||||
|
||||
for ( processor = 0 ; processor < processor_count ; ++processor ) {
|
||||
const Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( processor );
|
||||
|
||||
_Scheduler_default_Tick_for_executing( scheduler, per_cpu->executing );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#if defined(__RTEMS_HAVE_SYS_CPUSET_H__)
|
||||
|
||||
bool _Scheduler_Set_affinity(
|
||||
const Scheduler_Control *scheduler,
|
||||
Thread_Control *the_thread,
|
||||
size_t cpusetsize,
|
||||
const cpu_set_t *cpuset
|
||||
@@ -31,15 +30,31 @@ bool _Scheduler_Set_affinity(
|
||||
|
||||
if ( _CPU_set_Is_large_enough( cpusetsize ) ) {
|
||||
#if defined(RTEMS_SMP)
|
||||
ok = ( *scheduler->Operations.set_affinity )(
|
||||
scheduler,
|
||||
the_thread,
|
||||
cpusetsize,
|
||||
cpuset
|
||||
);
|
||||
uint32_t cpu_count = _SMP_Get_processor_count();
|
||||
uint32_t cpu_index;
|
||||
|
||||
ok = false;
|
||||
|
||||
for ( cpu_index = 0 ; cpu_index < cpu_count ; ++cpu_index ) {
|
||||
if ( CPU_ISSET_S( (int) cpu_index, cpusetsize, cpuset ) ) {
|
||||
const Scheduler_Control *scheduler_of_cpu =
|
||||
_Scheduler_Get_by_CPU_index( cpu_index );
|
||||
|
||||
if ( scheduler_of_cpu != NULL ) {
|
||||
ok = ( *scheduler_of_cpu->Operations.set_affinity )(
|
||||
scheduler_of_cpu,
|
||||
the_thread,
|
||||
cpusetsize,
|
||||
cpuset
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
ok = _Scheduler_default_Set_affinity_body(
|
||||
scheduler,
|
||||
_Scheduler_Get( the_thread ),
|
||||
the_thread,
|
||||
cpusetsize,
|
||||
cpuset
|
||||
|
||||
@@ -20,14 +20,68 @@
|
||||
|
||||
#include <rtems/score/smpimpl.h>
|
||||
#include <rtems/score/assert.h>
|
||||
#include <rtems/score/schedulerimpl.h>
|
||||
#include <rtems/score/threaddispatch.h>
|
||||
#include <rtems/score/threadimpl.h>
|
||||
#include <rtems/config.h>
|
||||
|
||||
static void _SMP_Check_scheduler_configuration( void )
|
||||
{
|
||||
size_t n = _Scheduler_Count;
|
||||
size_t i;
|
||||
|
||||
for ( i = 0 ; i < n ; ++i ) {
|
||||
const Scheduler_Control *scheduler = &_Scheduler_Table[ i ];
|
||||
|
||||
if ( scheduler->context->processor_count == 0 ) {
|
||||
_SMP_Fatal( SMP_FATAL_SCHEDULER_WITHOUT_PROCESSORS );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _SMP_Start_processors( uint32_t cpu_count )
|
||||
{
|
||||
uint32_t cpu_self = _SMP_Get_current_processor();
|
||||
uint32_t cpu_index;
|
||||
|
||||
|
||||
for ( cpu_index = 0 ; cpu_index < cpu_count; ++cpu_index ) {
|
||||
const Scheduler_Assignment *assignment =
|
||||
_Scheduler_Get_assignment( cpu_index );
|
||||
Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( cpu_index );
|
||||
bool started;
|
||||
|
||||
if ( cpu_index != cpu_self ) {
|
||||
if ( _Scheduler_Should_start_processor( assignment ) ) {
|
||||
started = _CPU_SMP_Start_processor( cpu_index );
|
||||
|
||||
if ( !started && _Scheduler_Is_mandatory_processor( assignment ) ) {
|
||||
_SMP_Fatal( SMP_FATAL_START_OF_MANDATORY_PROCESSOR_FAILED );
|
||||
}
|
||||
} else {
|
||||
started = false;
|
||||
}
|
||||
} else {
|
||||
started = true;
|
||||
|
||||
if ( !_Scheduler_Should_start_processor( assignment ) ) {
|
||||
_SMP_Fatal( SMP_FATAL_BOOT_PROCESSOR_NOT_ASSIGNED_TO_SCHEDULER );
|
||||
}
|
||||
}
|
||||
|
||||
per_cpu->started = started;
|
||||
|
||||
if ( started ) {
|
||||
++assignment->scheduler->context->processor_count;
|
||||
}
|
||||
}
|
||||
|
||||
_SMP_Check_scheduler_configuration();
|
||||
}
|
||||
|
||||
void _SMP_Handler_initialize( void )
|
||||
{
|
||||
uint32_t cpu_max = rtems_configuration_get_maximum_processors();
|
||||
uint32_t cpu_self;
|
||||
uint32_t cpu_count;
|
||||
uint32_t cpu_index;
|
||||
|
||||
@@ -45,22 +99,17 @@ void _SMP_Handler_initialize( void )
|
||||
cpu_count = cpu_count < cpu_max ? cpu_count : cpu_max;
|
||||
_SMP_Processor_count = cpu_count;
|
||||
|
||||
cpu_self = _SMP_Get_current_processor();
|
||||
for ( cpu_index = cpu_count ; cpu_index < cpu_max; ++cpu_index ) {
|
||||
const Scheduler_Assignment *assignment =
|
||||
_Scheduler_Get_assignment( cpu_index );
|
||||
|
||||
for ( cpu_index = 0 ; cpu_index < cpu_count; ++cpu_index ) {
|
||||
if ( cpu_index != cpu_self ) {
|
||||
bool ok = _CPU_SMP_Start_processor( cpu_index );
|
||||
|
||||
if ( !ok ) {
|
||||
_Terminate(
|
||||
RTEMS_FATAL_SOURCE_SMP,
|
||||
false,
|
||||
SMP_FATAL_START_OF_MANDATORY_PROCESSOR_FAILED
|
||||
);
|
||||
}
|
||||
if ( _Scheduler_Is_mandatory_processor( assignment ) ) {
|
||||
_SMP_Fatal( SMP_FATAL_MANDATORY_PROCESSOR_NOT_PRESENT );
|
||||
}
|
||||
}
|
||||
|
||||
_SMP_Start_processors( cpu_count );
|
||||
|
||||
_CPU_SMP_Finalize_initialization( cpu_count );
|
||||
}
|
||||
|
||||
@@ -83,6 +132,10 @@ void _SMP_Start_multitasking_on_secondary_processor( void )
|
||||
{
|
||||
Per_CPU_Control *self_cpu = _Per_CPU_Get();
|
||||
|
||||
if ( !_Per_CPU_Is_processor_started( self_cpu ) ) {
|
||||
_SMP_Fatal( SMP_FATAL_MULTITASKING_START_ON_UNASSIGNED_PROCESSOR );
|
||||
}
|
||||
|
||||
_Per_CPU_State_change( self_cpu, PER_CPU_STATE_READY_TO_START_MULTITASKING );
|
||||
|
||||
_Thread_Start_multitasking();
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#endif
|
||||
|
||||
#include <rtems/score/threadimpl.h>
|
||||
#include <rtems/score/schedulerimpl.h>
|
||||
#include <rtems/score/stackimpl.h>
|
||||
#include <rtems/config.h>
|
||||
|
||||
@@ -39,6 +40,7 @@ static void _Thread_Create_idle_for_cpu( Per_CPU_Control *per_cpu )
|
||||
_Thread_Initialize(
|
||||
&_Thread_Internal_information,
|
||||
idle,
|
||||
_Scheduler_Get_by_CPU( per_cpu ),
|
||||
NULL, /* allocate the stack */
|
||||
_Stack_Ensure_minimum( rtems_configuration_get_idle_task_stack_size() ),
|
||||
CPU_IDLE_TASK_IS_FP,
|
||||
@@ -75,6 +77,8 @@ void _Thread_Create_idle( void )
|
||||
for ( processor = 0 ; processor < processor_count ; ++processor ) {
|
||||
Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index( processor );
|
||||
|
||||
_Thread_Create_idle_for_cpu( per_cpu );
|
||||
if ( _Per_CPU_Is_processor_started( per_cpu ) ) {
|
||||
_Thread_Create_idle_for_cpu( per_cpu );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
bool _Thread_Initialize(
|
||||
Objects_Information *information,
|
||||
Thread_Control *the_thread,
|
||||
const Scheduler_Control *scheduler,
|
||||
void *stack_area,
|
||||
size_t stack_size,
|
||||
bool is_fp,
|
||||
@@ -50,7 +51,6 @@ bool _Thread_Initialize(
|
||||
bool extension_status;
|
||||
size_t i;
|
||||
bool scheduler_allocated = false;
|
||||
const Scheduler_Control *scheduler;
|
||||
|
||||
/*
|
||||
* Do not use _TLS_Size here since this will lead GCC to assume that this
|
||||
@@ -188,6 +188,7 @@ bool _Thread_Initialize(
|
||||
the_thread->is_scheduled = false;
|
||||
the_thread->is_in_the_air = false;
|
||||
the_thread->is_executing = false;
|
||||
the_thread->scheduler = scheduler;
|
||||
#endif
|
||||
|
||||
/* Initialize the CPU for the non-SMP schedulers */
|
||||
@@ -199,7 +200,6 @@ bool _Thread_Initialize(
|
||||
the_thread->real_priority = priority;
|
||||
the_thread->Start.initial_priority = priority;
|
||||
|
||||
scheduler = _Scheduler_Get( _Thread_Get_executing() );
|
||||
scheduler_allocated = _Scheduler_Allocate( scheduler, the_thread );
|
||||
if ( !scheduler_allocated ) {
|
||||
goto failed;
|
||||
|
||||
@@ -46,8 +46,12 @@ bool _Thread_Start(
|
||||
if ( cpu == NULL ) {
|
||||
_Thread_Ready( the_thread );
|
||||
} else {
|
||||
the_thread->current_state = STATES_READY;
|
||||
_Scheduler_Start_idle( _Scheduler_Get( the_thread ), the_thread, cpu );
|
||||
const Scheduler_Control *scheduler = _Scheduler_Get_by_CPU( cpu );
|
||||
|
||||
if ( scheduler != NULL ) {
|
||||
the_thread->current_state = STATES_READY;
|
||||
_Scheduler_Start_idle( scheduler, the_thread, cpu );
|
||||
}
|
||||
}
|
||||
|
||||
_User_extensions_Thread_start( the_thread );
|
||||
|
||||
207
doc/user/conf.t
207
doc/user/conf.t
@@ -3501,7 +3501,7 @@ configuration parameter is redundant.
|
||||
|
||||
@subheading DESCRIPTION:
|
||||
The Deterministic Priority Scheduler is the default scheduler in RTEMS
|
||||
for single core applications and is designed for predictable performance
|
||||
for uni-processor applications and is designed for predictable performance
|
||||
under the highest loads. It can block or unblock a thread in a constant
|
||||
amount of time. This scheduler requires a variable amount of memory
|
||||
based upon the number of priorities configured in the system.
|
||||
@@ -3572,7 +3572,7 @@ This is not defined by default.
|
||||
|
||||
@subheading DESCRIPTION:
|
||||
The Earliest Deadline First Scheduler (EDF) is an alternative scheduler in
|
||||
RTEMS for single core applications. The EDF schedules tasks with dynamic
|
||||
RTEMS for uni-processor applications. The EDF schedules tasks with dynamic
|
||||
priorities equal to deadlines. The deadlines are declared using only
|
||||
Rate Monotonic manager which handles periodic behavior. Period is always
|
||||
equal to deadline. If a task does not have any deadline declared or the
|
||||
@@ -3612,7 +3612,7 @@ This is not defined by default.
|
||||
|
||||
@subheading DESCRIPTION:
|
||||
The Constant Bandwidth Server Scheduler (CBS) is an alternative scheduler
|
||||
in RTEMS for single core applications. The CBS is a budget aware extension
|
||||
in RTEMS for uni-processor applications. The CBS is a budget aware extension
|
||||
of EDF scheduler. The goal of this scheduler is to ensure temporal
|
||||
isolation of tasks. The CBS is equipped with a set of additional rules
|
||||
and provides with an extensive API.
|
||||
@@ -3685,14 +3685,14 @@ This is not defined by default.
|
||||
|
||||
@subheading DESCRIPTION:
|
||||
The Simple SMP Priority Scheduler is derived from the Simple Priority
|
||||
Scheduler but is capable of scheduling threads across multiple cores.
|
||||
Scheduler but is capable of scheduling threads across multiple processors.
|
||||
It is designed to provide the same task scheduling behaviour as the
|
||||
Deterministic Priority Scheduler while distributing threads across
|
||||
multiple cores. Being based upon the Simple Priority Scheduler, it also
|
||||
multiple processors. Being based upon the Simple Priority Scheduler, it also
|
||||
maintains a single sorted list of all ready threads. Thus blocking or
|
||||
unblocking a thread is not a constant time operation with this scheduler.
|
||||
|
||||
In addition, when allocating threads to cores, the algorithm is not
|
||||
In addition, when allocating threads to processors, the algorithm is not
|
||||
constant time. This algorithm was not designed with efficiency as a
|
||||
primary design goal. Its primary design goal was to provide an SMP-aware
|
||||
scheduling algorithm that is simple to understand.
|
||||
@@ -3791,6 +3791,187 @@ guidance. For guidance on the configuration macros, please examine
|
||||
@code{cpukit/sapi/include/confdefs.h} for how these are defined for the
|
||||
Deterministic Priority Scheduler.
|
||||
|
||||
@c
|
||||
@c === Configuring Clustered/Partitioned Schedulers ===
|
||||
@c
|
||||
@subsection Configuring Clustered/Partitioned Schedulers
|
||||
|
||||
Clustered/partitioned scheduling helps to control the worst-case latencies in
|
||||
the system. The goal is to reduce the amount of shared state in the system and
|
||||
thus prevention of lock contention. Modern multi-processor systems tend to
|
||||
have several layers of data and instruction caches. With clustered/partitioned
|
||||
scheduling it is possible to honour the cache topology of a system and thus
|
||||
avoid expensive cache synchronization traffic.
|
||||
|
||||
We have clustered scheduling in case the set of processors of a system is
|
||||
partitioned into non-empty pairwise-disjoint subsets. These subsets are called
|
||||
clusters. Clusters with a cardinality of one are partitions. Each cluster is
|
||||
owned by exactly one scheduler instance. In order to use clustered/partitioned
|
||||
scheduling the application designer has to answer two questions.
|
||||
|
||||
@enumerate
|
||||
@item How is the set of processors partitioned into clusters/partitions?
|
||||
@item Which scheduler is used for which cluster/partition?
|
||||
@end enumerate
|
||||
|
||||
@subheading CONFIGURATION:
|
||||
|
||||
The schedulers in an SMP system are statically configured on RTEMS. Firstly
|
||||
the application must select which scheduling algorithms are available with the
|
||||
following defines
|
||||
|
||||
@itemize @bullet
|
||||
@item @code{CONFIGURE_SCHEDULER_PRIORITY_SMP},
|
||||
@item @code{CONFIGURE_SCHEDULER_SIMPLE_SMP}, and
|
||||
@item @code{CONFIGURE_SCHEDULER_PRIORITY_AFFINITY_SMP}.
|
||||
@end itemize
|
||||
|
||||
This is necessary to calculate the per-thread overhead introduced by the
|
||||
schedulers. After these definitions the configuration file must @code{#include
|
||||
<rtems/scheduler.h>} to have access to scheduler specific configuration macros.
|
||||
Each scheduler needs a context to store state information at run-time. To
|
||||
provide a context for each scheduler is the next step. Use the following
|
||||
macros to create scheduler contexts
|
||||
|
||||
@itemize @bullet
|
||||
@item @code{RTEMS_SCHEDULER_CONTEXT_PRIORITY_SMP(name, prio_count)},
|
||||
@item @code{RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(name)}, and
|
||||
@item @code{RTEMS_SCHEDULER_CONTEXT_PRIORITY_AFFINITY_SMP(name, prio_count)}.
|
||||
@end itemize
|
||||
|
||||
The @code{name} parameter is used as part of a designator for a global
|
||||
variable, so the usual C/C++ designator rules apply. Additional parameters are
|
||||
scheduler specific. The schedulers are registered in the system via the
|
||||
scheduler table. To create the scheduler table define
|
||||
@code{CONFIGURE_SCHEDULER_CONTROLS} to a list of the following scheduler
|
||||
control initializers
|
||||
|
||||
@itemize @bullet
|
||||
@item @code{RTEMS_SCHEDULER_CONTROL_PRIORITY_SMP(name, obj_name)},
|
||||
@item @code{RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(name, obj_name)}, and
|
||||
@item @code{RTEMS_SCHEDULER_CONTROL_PRIORITY_AFFINITY_SMP(name, obj_name)}.
|
||||
@end itemize
|
||||
|
||||
The @code{name} parameter must correspond to the parameter defining the
|
||||
scheduler context. The @code{obj_name} determines the scheduler object name
|
||||
and can be used in @code{rtems_scheduler_ident()} to get the scheduler object
|
||||
identifier.
|
||||
|
||||
The last step is to define which processor uses which scheduler.
|
||||
For this purpose a scheduler assignment table must be defined. The entry count
|
||||
of this table must be equal to the configured maximum processors
|
||||
(@code{CONFIGURE_SMP_MAXIMUM_PROCESSORS}). A processor assignment to a
|
||||
scheduler can be optional or mandatory. The boot processor must have a
|
||||
scheduler assigned. In case the system needs more mandatory processors than
|
||||
available then a fatal run-time error will occur. To specify the scheduler
|
||||
assignments define @code{CONFIGURE_SMP_SCHEDULER_ASSIGNMENTS} to a list of
|
||||
@code{RTEMS_SCHEDULER_ASSIGN(index, attr)} and
|
||||
@code{RTEMS_SCHEDULER_ASSIGN_NO_SCHEDULER} macros. The @code{index} parameter
|
||||
must be a valid index into the scheduler table. The @code{attr} parameter
|
||||
defines the scheduler assignment attributes. By default a scheduler assignment
|
||||
to a processor is optional. For the scheduler assignment attribute use one of
|
||||
the mutually exclusive variants
|
||||
|
||||
@itemize @bullet
|
||||
@item @code{RTEMS_SCHEDULER_ASSIGN_DEFAULT},
|
||||
@item @code{RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY}, and
|
||||
@item @code{RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL}.
|
||||
@end itemize
|
||||
|
||||
@subheading ERRORS:
|
||||
|
||||
In case one of the scheduler indices in
|
||||
@code{CONFIGURE_SMP_SCHEDULER_ASSIGNMENTS} is invalid a link-time error will
|
||||
occur with an undefined reference to @code{RTEMS_SCHEDULER_INVALID_INDEX}.
|
||||
|
||||
Some fatal errors may occur in case of scheduler configuration inconsistencies or a lack
|
||||
of processors on the system. The fatal source is
|
||||
@code{RTEMS_FATAL_SOURCE_SMP}. None of the errors is internal.
|
||||
|
||||
@itemize @bullet
|
||||
@item @code{SMP_FATAL_BOOT_PROCESSOR_NOT_ASSIGNED_TO_SCHEDULER} - the boot
|
||||
processor must have a scheduler assigned.
|
||||
@item @code{SMP_FATAL_MANDATORY_PROCESSOR_NOT_PRESENT} - there exists a
|
||||
mandatory processor beyond the range of physically or virtually available
|
||||
processors. The processor demand must be reduced for this system.
|
||||
@item @code{SMP_FATAL_START_OF_MANDATORY_PROCESSOR_FAILED} - the start of a
|
||||
mandatory processor failed during system initialization. The system may not
|
||||
have this processor at all or it could be a problem with a boot loader for
|
||||
example.
|
||||
the @code{CONFIGURE_SMP_SCHEDULER_ASSIGNMENTS} definition.
|
||||
@item @code{SMP_FATAL_SCHEDULER_WITHOUT_PROCESSORS} - it is prohibited to have
|
||||
a scheduler managing the empty processor set.
|
||||
@item @code{SMP_FATAL_MULTITASKING_START_ON_UNASSIGNED_PROCESSOR} - it is not
|
||||
allowed to start multitasking on a processor with no scheduler assigned.
|
||||
@end itemize
|
||||
|
||||
@subheading EXAMPLE:
|
||||
|
||||
The following example shows a scheduler configuration for a hypothetical
|
||||
product using two chip variants. One variant has four processors which is used
|
||||
for the normal product line and another provides eight processors for the
|
||||
high-performance product line. The first processor performs hard-real time
|
||||
control of actuators and sensors. The second processor is not used by RTEMS at
|
||||
all and runs a Linux instance to provide a graphical user interface. The
|
||||
additional processors are used for a worker thread pool to perform data
|
||||
processing operations.
|
||||
|
||||
The processors managed by RTEMS use two Deterministic Priority scheduler
|
||||
instances capable of dealing with 256 priority levels. The scheduler with
|
||||
index zero has the name @code{"IO "}. The scheduler with index one has the
|
||||
name @code{"WORK"}. The scheduler assignments of the first, third and fourth
|
||||
processor are mandatory, so the system must have at least four processors,
|
||||
otherwise a fatal run-time error will occur during system startup. The
|
||||
processor assignments for the fifth up to the eighth processor are optional so
|
||||
that the same application can be used for the normal and high-performance
|
||||
product lines. The second processor has no scheduler assigned and runs Linux.
|
||||
A hypervisor will ensure that the two systems cannot interfere in an
|
||||
undesirable way.
|
||||
|
||||
@example
|
||||
@group
|
||||
#define CONFIGURE_SMP_MAXIMUM_PROCESSORS 8
|
||||
|
||||
#define CONFIGURE_MAXIMUM_PRIORITY 255
|
||||
|
||||
/* Make the scheduler algorithm available */
|
||||
|
||||
#define CONFIGURE_SCHEDULER_PRIORITY_SMP
|
||||
|
||||
#include <rtems/scheduler.h>
|
||||
|
||||
/* Create contexts for the two scheduler instances */
|
||||
|
||||
RTEMS_SCHEDULER_CONTEXT_PRIORITY_SMP(io, CONFIGURE_MAXIMUM_PRIORITY + 1);
|
||||
|
||||
RTEMS_SCHEDULER_CONTEXT_PRIORITY_SMP(work, CONFIGURE_MAXIMUM_PRIORITY + 1);
|
||||
|
||||
/* Define the scheduler table */
|
||||
|
||||
#define CONFIGURE_SCHEDULER_CONTROLS \
|
||||
RTEMS_SCHEDULER_CONTROL_PRIORITY_SMP( \
|
||||
io, \
|
||||
rtems_build_name('I', 'O', ' ', ' ') \
|
||||
), \
|
||||
RTEMS_SCHEDULER_CONTROL_PRIORITY_SMP( \
|
||||
work, \
|
||||
rtems_build_name('W', 'O', 'R', 'K') \
|
||||
)
|
||||
|
||||
/* Define the processor to scheduler assignments */
|
||||
|
||||
#define CONFIGURE_SMP_SCHEDULER_ASSIGNMENTS \
|
||||
RTEMS_SCHEDULER_ASSIGN(0, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY), \
|
||||
RTEMS_SCHEDULER_ASSIGN_NO_SCHEDULER, \
|
||||
RTEMS_SCHEDULER_ASSIGN(1, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY), \
|
||||
RTEMS_SCHEDULER_ASSIGN(1, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY), \
|
||||
RTEMS_SCHEDULER_ASSIGN(1, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
|
||||
RTEMS_SCHEDULER_ASSIGN(1, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
|
||||
RTEMS_SCHEDULER_ASSIGN(1, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL), \
|
||||
RTEMS_SCHEDULER_ASSIGN(1, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL)
|
||||
@end group
|
||||
@end example
|
||||
|
||||
@c
|
||||
@c === SMP Specific Configuration Parameters ===
|
||||
@c
|
||||
@@ -3804,7 +3985,7 @@ configuration parameters which apply.
|
||||
@c
|
||||
@c === CONFIGURE_SMP_APPLICATION ===
|
||||
@c
|
||||
@subsection Specify Application Uses Multiple Cores (is SMP)
|
||||
@subsection Enable SMP Support for Applications
|
||||
|
||||
@findex CONFIGURE_SMP_APPLICATION
|
||||
|
||||
@@ -3819,16 +4000,16 @@ Boolean feature macro.
|
||||
Defined or undefined.
|
||||
|
||||
@item DEFAULT VALUE:
|
||||
The default value is 1, (if CONFIGURE_SMP_APPLICATION is defined).
|
||||
This is not defined by default.
|
||||
|
||||
@end table
|
||||
|
||||
@subheading DESCRIPTION:
|
||||
@code{CONFIGURE_SMP_APPLICATION} must be defined if the application is
|
||||
to make use of multiple CPU cores in an SMP target system.
|
||||
@code{CONFIGURE_SMP_APPLICATION} must be defined to enable SMP support for the
|
||||
application.
|
||||
|
||||
@subheading NOTES:
|
||||
None.
|
||||
This define may go away in the future in case all RTEMS components are SMP ready.
|
||||
|
||||
@c
|
||||
@c === CONFIGURE_SMP_MAXIMUM_PROCESSORS ===
|
||||
@@ -3854,10 +4035,10 @@ The default value is 1, (if CONFIGURE_SMP_APPLICATION is defined).
|
||||
|
||||
@subheading DESCRIPTION:
|
||||
@code{CONFIGURE_SMP_MAXIMUM_PROCESSORS} must be set to the number of
|
||||
CPU cores in the SMP configuration.
|
||||
processors in the SMP configuration.
|
||||
|
||||
@subheading NOTES:
|
||||
If there are more cores available than configured, the rest will be
|
||||
If there are more processors available than configured, the rest will be
|
||||
ignored.
|
||||
|
||||
@c
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
ACLOCAL_AMFLAGS = -I ../aclocal
|
||||
|
||||
SUBDIRS =
|
||||
SUBDIRS += smpload01
|
||||
|
||||
if SMPTESTS
|
||||
SUBDIRS += smp01
|
||||
SUBDIRS += smp02
|
||||
@@ -16,9 +14,16 @@ SUBDIRS += smpatomic01
|
||||
SUBDIRS += smpfatal01
|
||||
SUBDIRS += smpfatal02
|
||||
SUBDIRS += smpfatal03
|
||||
SUBDIRS += smpfatal04
|
||||
SUBDIRS += smpfatal05
|
||||
SUBDIRS += smpfatal06
|
||||
SUBDIRS += smpfatal07
|
||||
SUBDIRS += smpfatal08
|
||||
SUBDIRS += smpload01
|
||||
SUBDIRS += smplock01
|
||||
SUBDIRS += smpmigration01
|
||||
SUBDIRS += smpscheduler01
|
||||
SUBDIRS += smpscheduler02
|
||||
SUBDIRS += smpsignal01
|
||||
SUBDIRS += smpswitchextension01
|
||||
SUBDIRS += smpthreadlife01
|
||||
|
||||
@@ -57,7 +57,6 @@ AM_CONDITIONAL(HAS_CPUSET,test x"${ac_cv_header_sys_cpuset_h}" = x"yes")
|
||||
|
||||
# Explicitly list all Makefiles here
|
||||
AC_CONFIG_FILES([Makefile
|
||||
smpload01/Makefile
|
||||
smp01/Makefile
|
||||
smp02/Makefile
|
||||
smp03/Makefile
|
||||
@@ -70,12 +69,19 @@ smpatomic01/Makefile
|
||||
smpfatal01/Makefile
|
||||
smpfatal02/Makefile
|
||||
smpfatal03/Makefile
|
||||
smpfatal04/Makefile
|
||||
smpfatal05/Makefile
|
||||
smpfatal06/Makefile
|
||||
smpfatal07/Makefile
|
||||
smpfatal08/Makefile
|
||||
smpload01/Makefile
|
||||
smplock01/Makefile
|
||||
smpmigration01/Makefile
|
||||
smppsxaffinity01/Makefile
|
||||
smppsxaffinity02/Makefile
|
||||
smppsxsignal01/Makefile
|
||||
smpscheduler01/Makefile
|
||||
smpscheduler02/Makefile
|
||||
smpsignal01/Makefile
|
||||
smpswitchextension01/Makefile
|
||||
smpthreadlife01/Makefile
|
||||
|
||||
19
testsuites/smptests/smpfatal04/Makefile.am
Normal file
19
testsuites/smptests/smpfatal04/Makefile.am
Normal file
@@ -0,0 +1,19 @@
|
||||
rtems_tests_PROGRAMS = smpfatal04
|
||||
smpfatal04_SOURCES = init.c
|
||||
|
||||
dist_rtems_tests_DATA = smpfatal04.scn smpfatal04.doc
|
||||
|
||||
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
|
||||
include $(top_srcdir)/../automake/compile.am
|
||||
include $(top_srcdir)/../automake/leaf.am
|
||||
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/../support/include
|
||||
|
||||
LINK_OBJS = $(smpfatal04_OBJECTS)
|
||||
LINK_LIBS = $(smpfatal04_LDLIBS)
|
||||
|
||||
smpfatal04$(EXEEXT): $(smpfatal04_OBJECTS) $(smpfatal04_DEPENDENCIES)
|
||||
@rm -f smpfatal04$(EXEEXT)
|
||||
$(make-exe)
|
||||
|
||||
include $(top_srcdir)/../automake/local.am
|
||||
71
testsuites/smptests/smpfatal04/init.c
Normal file
71
testsuites/smptests/smpfatal04/init.c
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2014 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/test.h>
|
||||
#include <rtems/score/smpimpl.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
const char rtems_test_name[] = "SMPFATAL 4";
|
||||
|
||||
static void Init(rtems_task_argument arg)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
static void fatal_extension(
|
||||
rtems_fatal_source source,
|
||||
bool is_internal,
|
||||
rtems_fatal_code code
|
||||
)
|
||||
{
|
||||
rtems_test_begink();
|
||||
|
||||
if (
|
||||
source == RTEMS_FATAL_SOURCE_SMP
|
||||
&& !is_internal
|
||||
&& code == SMP_FATAL_BOOT_PROCESSOR_NOT_ASSIGNED_TO_SCHEDULER
|
||||
) {
|
||||
rtems_test_endk();
|
||||
}
|
||||
}
|
||||
|
||||
#define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER
|
||||
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
|
||||
|
||||
#define CONFIGURE_INITIAL_EXTENSIONS \
|
||||
{ .fatal = fatal_extension }, \
|
||||
RTEMS_TEST_INITIAL_EXTENSION
|
||||
|
||||
#define CONFIGURE_SMP_APPLICATION
|
||||
|
||||
#define CONFIGURE_SMP_MAXIMUM_PROCESSORS 1
|
||||
|
||||
#define CONFIGURE_SCHEDULER_CONTROLS
|
||||
|
||||
#define CONFIGURE_SMP_SCHEDULER_ASSIGNMENTS RTEMS_SCHEDULER_ASSIGN_NO_SCHEDULER
|
||||
|
||||
#define CONFIGURE_MAXIMUM_TASKS 1
|
||||
|
||||
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
|
||||
|
||||
#define CONFIGURE_INIT
|
||||
|
||||
#include <rtems/confdefs.h>
|
||||
11
testsuites/smptests/smpfatal04/smpfatal04.doc
Normal file
11
testsuites/smptests/smpfatal04/smpfatal04.doc
Normal file
@@ -0,0 +1,11 @@
|
||||
This file describes the directives and concepts tested by this test set.
|
||||
|
||||
test set name: smpfatal04
|
||||
|
||||
directives:
|
||||
|
||||
- _SMP_Handler_initialize()
|
||||
|
||||
concepts:
|
||||
|
||||
- Ensure that the boot processor has a scheduler assigned.
|
||||
2
testsuites/smptests/smpfatal04/smpfatal04.scn
Normal file
2
testsuites/smptests/smpfatal04/smpfatal04.scn
Normal file
@@ -0,0 +1,2 @@
|
||||
*** BEGIN OF TEST SMPFATAL 4 ***
|
||||
*** END OF TEST SMPFATAL 4 ***
|
||||
19
testsuites/smptests/smpfatal05/Makefile.am
Normal file
19
testsuites/smptests/smpfatal05/Makefile.am
Normal file
@@ -0,0 +1,19 @@
|
||||
rtems_tests_PROGRAMS = smpfatal05
|
||||
smpfatal05_SOURCES = init.c
|
||||
|
||||
dist_rtems_tests_DATA = smpfatal05.scn smpfatal05.doc
|
||||
|
||||
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
|
||||
include $(top_srcdir)/../automake/compile.am
|
||||
include $(top_srcdir)/../automake/leaf.am
|
||||
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/../support/include
|
||||
|
||||
LINK_OBJS = $(smpfatal05_OBJECTS)
|
||||
LINK_LIBS = $(smpfatal05_LDLIBS)
|
||||
|
||||
smpfatal05$(EXEEXT): $(smpfatal05_OBJECTS) $(smpfatal05_DEPENDENCIES)
|
||||
@rm -f smpfatal05$(EXEEXT)
|
||||
$(make-exe)
|
||||
|
||||
include $(top_srcdir)/../automake/local.am
|
||||
90
testsuites/smptests/smpfatal05/init.c
Normal file
90
testsuites/smptests/smpfatal05/init.c
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2014 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/test.h>
|
||||
#include <rtems/score/smpimpl.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
const char rtems_test_name[] = "SMPFATAL 5";
|
||||
|
||||
static void Init(rtems_task_argument arg)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
static void fatal_extension(
|
||||
rtems_fatal_source source,
|
||||
bool is_internal,
|
||||
rtems_fatal_code code
|
||||
)
|
||||
{
|
||||
rtems_test_begink();
|
||||
|
||||
if (
|
||||
source == RTEMS_FATAL_SOURCE_SMP
|
||||
&& !is_internal
|
||||
&& code == SMP_FATAL_MANDATORY_PROCESSOR_NOT_PRESENT
|
||||
) {
|
||||
rtems_test_endk();
|
||||
}
|
||||
}
|
||||
|
||||
#define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER
|
||||
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
|
||||
|
||||
#define CONFIGURE_INITIAL_EXTENSIONS \
|
||||
{ .fatal = fatal_extension }, \
|
||||
RTEMS_TEST_INITIAL_EXTENSION
|
||||
|
||||
#define CONFIGURE_SMP_APPLICATION
|
||||
|
||||
/* Lets see when the first RTEMS system hits this limit */
|
||||
#define CONFIGURE_SMP_MAXIMUM_PROCESSORS 64
|
||||
|
||||
#define CONFIGURE_SCHEDULER_SIMPLE_SMP
|
||||
|
||||
#include <rtems/scheduler.h>
|
||||
|
||||
RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(a);
|
||||
|
||||
#define CONFIGURE_SCHEDULER_CONTROLS \
|
||||
RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(a, rtems_build_name('S', 'I', 'M', 'P'))
|
||||
|
||||
#define ASSIGN \
|
||||
RTEMS_SCHEDULER_ASSIGN(0, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY)
|
||||
|
||||
#define CONFIGURE_SMP_SCHEDULER_ASSIGNMENTS \
|
||||
ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, \
|
||||
ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, \
|
||||
ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, \
|
||||
ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, \
|
||||
ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, \
|
||||
ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, \
|
||||
ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, \
|
||||
ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN, ASSIGN
|
||||
|
||||
#define CONFIGURE_MAXIMUM_TASKS 1
|
||||
|
||||
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
|
||||
|
||||
#define CONFIGURE_INIT
|
||||
|
||||
#include <rtems/confdefs.h>
|
||||
11
testsuites/smptests/smpfatal05/smpfatal05.doc
Normal file
11
testsuites/smptests/smpfatal05/smpfatal05.doc
Normal file
@@ -0,0 +1,11 @@
|
||||
This file describes the directives and concepts tested by this test set.
|
||||
|
||||
test set name: smpfatal05
|
||||
|
||||
directives:
|
||||
|
||||
- _SMP_Handler_initialize()
|
||||
|
||||
concepts:
|
||||
|
||||
- Ensure that all mandatory processors are present.
|
||||
2
testsuites/smptests/smpfatal05/smpfatal05.scn
Normal file
2
testsuites/smptests/smpfatal05/smpfatal05.scn
Normal file
@@ -0,0 +1,2 @@
|
||||
*** BEGIN OF TEST SMPFATAL 5 ***
|
||||
*** END OF TEST SMPFATAL 5 ***
|
||||
19
testsuites/smptests/smpfatal06/Makefile.am
Normal file
19
testsuites/smptests/smpfatal06/Makefile.am
Normal file
@@ -0,0 +1,19 @@
|
||||
rtems_tests_PROGRAMS = smpfatal06
|
||||
smpfatal06_SOURCES = init.c
|
||||
|
||||
dist_rtems_tests_DATA = smpfatal06.scn smpfatal06.doc
|
||||
|
||||
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
|
||||
include $(top_srcdir)/../automake/compile.am
|
||||
include $(top_srcdir)/../automake/leaf.am
|
||||
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/../support/include
|
||||
|
||||
LINK_OBJS = $(smpfatal06_OBJECTS)
|
||||
LINK_LIBS = $(smpfatal06_LDLIBS)
|
||||
|
||||
smpfatal06$(EXEEXT): $(smpfatal06_OBJECTS) $(smpfatal06_DEPENDENCIES)
|
||||
@rm -f smpfatal06$(EXEEXT)
|
||||
$(make-exe)
|
||||
|
||||
include $(top_srcdir)/../automake/local.am
|
||||
81
testsuites/smptests/smpfatal06/init.c
Normal file
81
testsuites/smptests/smpfatal06/init.c
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2014 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/test.h>
|
||||
#include <rtems/score/smpimpl.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
const char rtems_test_name[] = "SMPFATAL 6";
|
||||
|
||||
static void Init(rtems_task_argument arg)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
static void fatal_extension(
|
||||
rtems_fatal_source source,
|
||||
bool is_internal,
|
||||
rtems_fatal_code code
|
||||
)
|
||||
{
|
||||
rtems_test_begink();
|
||||
|
||||
if (
|
||||
source == RTEMS_FATAL_SOURCE_SMP
|
||||
&& !is_internal
|
||||
&& code == SMP_FATAL_SCHEDULER_WITHOUT_PROCESSORS
|
||||
) {
|
||||
rtems_test_endk();
|
||||
}
|
||||
}
|
||||
|
||||
#define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER
|
||||
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
|
||||
|
||||
#define CONFIGURE_INITIAL_EXTENSIONS \
|
||||
{ .fatal = fatal_extension }, \
|
||||
RTEMS_TEST_INITIAL_EXTENSION
|
||||
|
||||
#define CONFIGURE_SMP_APPLICATION
|
||||
|
||||
#define CONFIGURE_SMP_MAXIMUM_PROCESSORS 1
|
||||
|
||||
#define CONFIGURE_SCHEDULER_SIMPLE_SMP
|
||||
|
||||
#include <rtems/scheduler.h>
|
||||
|
||||
RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(a);
|
||||
RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(b);
|
||||
|
||||
#define CONFIGURE_SCHEDULER_CONTROLS \
|
||||
RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(a, rtems_build_name('S', 'I', 'M', 'P')), \
|
||||
RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(b, rtems_build_name('S', 'I', 'M', 'P'))
|
||||
|
||||
#define CONFIGURE_SMP_SCHEDULER_ASSIGNMENTS \
|
||||
RTEMS_SCHEDULER_ASSIGN(0, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY)
|
||||
|
||||
#define CONFIGURE_MAXIMUM_TASKS 1
|
||||
|
||||
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
|
||||
|
||||
#define CONFIGURE_INIT
|
||||
|
||||
#include <rtems/confdefs.h>
|
||||
11
testsuites/smptests/smpfatal06/smpfatal06.doc
Normal file
11
testsuites/smptests/smpfatal06/smpfatal06.doc
Normal file
@@ -0,0 +1,11 @@
|
||||
This file describes the directives and concepts tested by this test set.
|
||||
|
||||
test set name: smpfatal06
|
||||
|
||||
directives:
|
||||
|
||||
- _SMP_Handler_initialize()
|
||||
|
||||
concepts:
|
||||
|
||||
- Ensure that a scheduler without processor leads to a fatal error.
|
||||
2
testsuites/smptests/smpfatal06/smpfatal06.scn
Normal file
2
testsuites/smptests/smpfatal06/smpfatal06.scn
Normal file
@@ -0,0 +1,2 @@
|
||||
*** TEST SMPFATAL 6 ***
|
||||
*** END OF TEST SMPFATAL 6 ***
|
||||
19
testsuites/smptests/smpfatal07/Makefile.am
Normal file
19
testsuites/smptests/smpfatal07/Makefile.am
Normal file
@@ -0,0 +1,19 @@
|
||||
rtems_tests_PROGRAMS = smpfatal07
|
||||
smpfatal07_SOURCES = init.c
|
||||
|
||||
dist_rtems_tests_DATA = smpfatal07.scn smpfatal07.doc
|
||||
|
||||
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
|
||||
include $(top_srcdir)/../automake/compile.am
|
||||
include $(top_srcdir)/../automake/leaf.am
|
||||
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/../support/include
|
||||
|
||||
LINK_OBJS = $(smpfatal07_OBJECTS)
|
||||
LINK_LIBS = $(smpfatal07_LDLIBS)
|
||||
|
||||
smpfatal07$(EXEEXT): $(smpfatal07_OBJECTS) $(smpfatal07_DEPENDENCIES)
|
||||
@rm -f smpfatal07$(EXEEXT)
|
||||
$(make-exe)
|
||||
|
||||
include $(top_srcdir)/../automake/local.am
|
||||
75
testsuites/smptests/smpfatal07/init.c
Normal file
75
testsuites/smptests/smpfatal07/init.c
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2014 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/test.h>
|
||||
#include <rtems/score/smpimpl.h>
|
||||
#include <rtems/score/threadimpl.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
const char rtems_test_name[] = "SMPFATAL 7";
|
||||
|
||||
static void Init(rtems_task_argument arg)
|
||||
{
|
||||
Per_CPU_Control *cpu_self;
|
||||
|
||||
_Thread_Disable_dispatch();
|
||||
cpu_self = _Per_CPU_Get();
|
||||
cpu_self->started = false;
|
||||
_SMP_Start_multitasking_on_secondary_processor();
|
||||
|
||||
assert(0);
|
||||
}
|
||||
|
||||
static void fatal_extension(
|
||||
rtems_fatal_source source,
|
||||
bool is_internal,
|
||||
rtems_fatal_code code
|
||||
)
|
||||
{
|
||||
rtems_test_begink();
|
||||
|
||||
if (
|
||||
source == RTEMS_FATAL_SOURCE_SMP
|
||||
&& !is_internal
|
||||
&& code == SMP_FATAL_MULTITASKING_START_ON_UNASSIGNED_PROCESSOR
|
||||
) {
|
||||
rtems_test_endk();
|
||||
}
|
||||
}
|
||||
|
||||
#define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER
|
||||
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
|
||||
|
||||
#define CONFIGURE_INITIAL_EXTENSIONS \
|
||||
{ .fatal = fatal_extension }, \
|
||||
RTEMS_TEST_INITIAL_EXTENSION
|
||||
|
||||
#define CONFIGURE_SMP_APPLICATION
|
||||
|
||||
#define CONFIGURE_SMP_MAXIMUM_PROCESSORS 1
|
||||
|
||||
#define CONFIGURE_MAXIMUM_TASKS 1
|
||||
|
||||
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
|
||||
|
||||
#define CONFIGURE_INIT
|
||||
|
||||
#include <rtems/confdefs.h>
|
||||
12
testsuites/smptests/smpfatal07/smpfatal07.doc
Normal file
12
testsuites/smptests/smpfatal07/smpfatal07.doc
Normal file
@@ -0,0 +1,12 @@
|
||||
This file describes the directives and concepts tested by this test set.
|
||||
|
||||
test set name: smpfatal07
|
||||
|
||||
directives:
|
||||
|
||||
- _SMP_Start_multitasking_on_secondary_processor()
|
||||
|
||||
concepts:
|
||||
|
||||
- Ensure that a multitasking start on an unassigned processor leads to a
|
||||
fatal error.
|
||||
2
testsuites/smptests/smpfatal07/smpfatal07.scn
Normal file
2
testsuites/smptests/smpfatal07/smpfatal07.scn
Normal file
@@ -0,0 +1,2 @@
|
||||
*** TEST SMPFATAL 7 ***
|
||||
*** END OF TEST SMPFATAL 7 ***
|
||||
19
testsuites/smptests/smpfatal08/Makefile.am
Normal file
19
testsuites/smptests/smpfatal08/Makefile.am
Normal file
@@ -0,0 +1,19 @@
|
||||
rtems_tests_PROGRAMS = smpfatal08
|
||||
smpfatal08_SOURCES = init.c
|
||||
|
||||
dist_rtems_tests_DATA = smpfatal08.scn smpfatal08.doc
|
||||
|
||||
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
|
||||
include $(top_srcdir)/../automake/compile.am
|
||||
include $(top_srcdir)/../automake/leaf.am
|
||||
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/../support/include
|
||||
|
||||
LINK_OBJS = $(smpfatal08_OBJECTS)
|
||||
LINK_LIBS = $(smpfatal08_LDLIBS)
|
||||
|
||||
smpfatal08$(EXEEXT): $(smpfatal08_OBJECTS) $(smpfatal08_DEPENDENCIES)
|
||||
@rm -f smpfatal08$(EXEEXT)
|
||||
$(make-exe)
|
||||
|
||||
include $(top_srcdir)/../automake/local.am
|
||||
132
testsuites/smptests/smpfatal08/init.c
Normal file
132
testsuites/smptests/smpfatal08/init.c
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (c) 2014 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/test.h>
|
||||
#include <rtems/score/smpimpl.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
const char rtems_test_name[] = "SMPFATAL 8";
|
||||
|
||||
/*
|
||||
* This test is a hack since there is no easy way to test this fatal error path
|
||||
* without BSP support.
|
||||
*/
|
||||
|
||||
#if defined(__PPC__)
|
||||
void qoriq_secondary_cpu_initialize(void)
|
||||
{
|
||||
/* Provided to avoid multiple definitions of the CPU SMP support functions */
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__sparc__)
|
||||
void leon3_secondary_cpu_initialize(uint32_t cpu_index)
|
||||
{
|
||||
(void) cpu_index;
|
||||
|
||||
/* Provided to avoid multiple definitions of the CPU SMP support functions */
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t _CPU_SMP_Initialize(void)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
bool _CPU_SMP_Start_processor(uint32_t cpu_index)
|
||||
{
|
||||
(void) cpu_index;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void _CPU_SMP_Finalize_initialization(uint32_t cpu_count)
|
||||
{
|
||||
(void) cpu_count;
|
||||
|
||||
assert(0);
|
||||
}
|
||||
|
||||
#if !defined(__leon__) && !defined(__PPC__) && !defined(__arm__)
|
||||
uint32_t _CPU_SMP_Get_current_processor(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void _CPU_SMP_Send_interrupt(uint32_t target_processor_index)
|
||||
{
|
||||
(void) target_processor_index;
|
||||
}
|
||||
|
||||
static void Init(rtems_task_argument arg)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
|
||||
static void fatal_extension(
|
||||
rtems_fatal_source source,
|
||||
bool is_internal,
|
||||
rtems_fatal_code code
|
||||
)
|
||||
{
|
||||
rtems_test_begink();
|
||||
|
||||
if (
|
||||
source == RTEMS_FATAL_SOURCE_SMP
|
||||
&& !is_internal
|
||||
&& code == SMP_FATAL_START_OF_MANDATORY_PROCESSOR_FAILED
|
||||
) {
|
||||
rtems_test_endk();
|
||||
}
|
||||
}
|
||||
|
||||
#define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER
|
||||
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
|
||||
|
||||
#define CONFIGURE_INITIAL_EXTENSIONS \
|
||||
{ .fatal = fatal_extension }, \
|
||||
RTEMS_TEST_INITIAL_EXTENSION
|
||||
|
||||
#define CONFIGURE_SMP_APPLICATION
|
||||
|
||||
#define CONFIGURE_SMP_MAXIMUM_PROCESSORS 2
|
||||
|
||||
#define CONFIGURE_SCHEDULER_SIMPLE_SMP
|
||||
|
||||
#include <rtems/scheduler.h>
|
||||
|
||||
RTEMS_SCHEDULER_CONTEXT_SIMPLE_SMP(a);
|
||||
|
||||
#define CONFIGURE_SCHEDULER_CONTROLS \
|
||||
RTEMS_SCHEDULER_CONTROL_SIMPLE_SMP(a, rtems_build_name('S', 'I', 'M', 'P'))
|
||||
|
||||
#define CONFIGURE_SMP_SCHEDULER_ASSIGNMENTS \
|
||||
RTEMS_SCHEDULER_ASSIGN(0, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY), \
|
||||
RTEMS_SCHEDULER_ASSIGN(0, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY)
|
||||
|
||||
#define CONFIGURE_MAXIMUM_TASKS 1
|
||||
|
||||
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
|
||||
|
||||
#define CONFIGURE_INIT
|
||||
|
||||
#include <rtems/confdefs.h>
|
||||
11
testsuites/smptests/smpfatal08/smpfatal08.doc
Normal file
11
testsuites/smptests/smpfatal08/smpfatal08.doc
Normal file
@@ -0,0 +1,11 @@
|
||||
This file describes the directives and concepts tested by this test set.
|
||||
|
||||
test set name: smpfatal08
|
||||
|
||||
directives:
|
||||
|
||||
- _SMP_Handler_initialize()
|
||||
|
||||
concepts:
|
||||
|
||||
- Ensure that a failed start of a mandatory processor leads to a fatal error.
|
||||
2
testsuites/smptests/smpfatal08/smpfatal08.scn
Normal file
2
testsuites/smptests/smpfatal08/smpfatal08.scn
Normal file
@@ -0,0 +1,2 @@
|
||||
*** TEST SMPFATAL 7 ***
|
||||
*** END OF TEST SMPFATAL 7 ***
|
||||
19
testsuites/smptests/smpscheduler02/Makefile.am
Normal file
19
testsuites/smptests/smpscheduler02/Makefile.am
Normal file
@@ -0,0 +1,19 @@
|
||||
rtems_tests_PROGRAMS = smpscheduler02
|
||||
smpscheduler02_SOURCES = init.c
|
||||
|
||||
dist_rtems_tests_DATA = smpscheduler02.scn smpscheduler02.doc
|
||||
|
||||
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
|
||||
include $(top_srcdir)/../automake/compile.am
|
||||
include $(top_srcdir)/../automake/leaf.am
|
||||
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/../support/include
|
||||
|
||||
LINK_OBJS = $(smpscheduler02_OBJECTS)
|
||||
LINK_LIBS = $(smpscheduler02_LDLIBS)
|
||||
|
||||
smpscheduler02$(EXEEXT): $(smpscheduler02_OBJECTS) $(smpscheduler02_DEPENDENCIES)
|
||||
@rm -f smpscheduler02$(EXEEXT)
|
||||
$(make-exe)
|
||||
|
||||
include $(top_srcdir)/../automake/local.am
|
||||
222
testsuites/smptests/smpscheduler02/init.c
Normal file
222
testsuites/smptests/smpscheduler02/init.c
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright (c) 2014 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.org/license/LICENSE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <rtems.h>
|
||||
#include <rtems/libcsupport.h>
|
||||
|
||||
#include "tmacros.h"
|
||||
|
||||
const char rtems_test_name[] = "SMPSCHEDULER 2";
|
||||
|
||||
#if defined(__RTEMS_HAVE_SYS_CPUSET_H__)
|
||||
|
||||
#define CPU_COUNT 2
|
||||
|
||||
#define SCHED_A rtems_build_name(' ', ' ', ' ', 'A')
|
||||
|
||||
#define SCHED_B rtems_build_name(' ', ' ', ' ', 'B')
|
||||
|
||||
static rtems_id main_task_id;
|
||||
|
||||
static void task(rtems_task_argument arg)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
|
||||
(void) arg;
|
||||
|
||||
rtems_test_assert(rtems_get_current_processor() == 1);
|
||||
|
||||
sc = rtems_event_transient_send(main_task_id);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
while (1) {
|
||||
/* Do nothing */
|
||||
}
|
||||
}
|
||||
|
||||
static void test(void)
|
||||
{
|
||||
rtems_status_code sc;
|
||||
rtems_id task_id;
|
||||
rtems_id scheduler_id;
|
||||
rtems_id scheduler_a_id;
|
||||
rtems_id scheduler_b_id;
|
||||
cpu_set_t cpuset;
|
||||
cpu_set_t first_cpu;
|
||||
cpu_set_t second_cpu;
|
||||
cpu_set_t all_cpus;
|
||||
|
||||
main_task_id = rtems_task_self();
|
||||
|
||||
CPU_ZERO(&first_cpu);
|
||||
CPU_SET(0, &first_cpu);
|
||||
|
||||
CPU_ZERO(&second_cpu);
|
||||
CPU_SET(1, &second_cpu);
|
||||
|
||||
CPU_ZERO(&all_cpus);
|
||||
CPU_SET(0, &all_cpus);
|
||||
CPU_SET(1, &all_cpus);
|
||||
|
||||
rtems_test_assert(rtems_get_current_processor() == 0);
|
||||
|
||||
sc = rtems_scheduler_ident(SCHED_A, &scheduler_a_id);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
sc = rtems_scheduler_ident(SCHED_B, &scheduler_b_id);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
rtems_test_assert(scheduler_a_id != scheduler_b_id);
|
||||
|
||||
CPU_ZERO(&cpuset);
|
||||
sc = rtems_scheduler_get_processor_set(
|
||||
scheduler_a_id,
|
||||
sizeof(cpuset),
|
||||
&cpuset
|
||||
);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
rtems_test_assert(CPU_EQUAL(&cpuset, &first_cpu));
|
||||
|
||||
CPU_ZERO(&cpuset);
|
||||
sc = rtems_scheduler_get_processor_set(
|
||||
scheduler_b_id,
|
||||
sizeof(cpuset),
|
||||
&cpuset
|
||||
);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
rtems_test_assert(CPU_EQUAL(&cpuset, &second_cpu));
|
||||
|
||||
sc = rtems_task_create(
|
||||
rtems_build_name('T', 'A', 'S', 'K'),
|
||||
1,
|
||||
RTEMS_MINIMUM_STACK_SIZE,
|
||||
RTEMS_DEFAULT_MODES,
|
||||
RTEMS_DEFAULT_ATTRIBUTES,
|
||||
&task_id
|
||||
);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
sc = rtems_task_get_scheduler(task_id, &scheduler_id);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
rtems_test_assert(scheduler_id == scheduler_a_id);
|
||||
|
||||
CPU_ZERO(&cpuset);
|
||||
sc = rtems_task_get_affinity(task_id, sizeof(cpuset), &cpuset);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
rtems_test_assert(CPU_EQUAL(&cpuset, &first_cpu));
|
||||
|
||||
sc = rtems_task_set_scheduler(task_id, scheduler_b_id);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
sc = rtems_task_get_scheduler(task_id, &scheduler_id);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
rtems_test_assert(scheduler_id == scheduler_b_id);
|
||||
|
||||
CPU_ZERO(&cpuset);
|
||||
sc = rtems_task_get_affinity(task_id, sizeof(cpuset), &cpuset);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
rtems_test_assert(CPU_EQUAL(&cpuset, &second_cpu));
|
||||
|
||||
sc = rtems_task_set_affinity(task_id, sizeof(all_cpus), &all_cpus);
|
||||
rtems_test_assert(sc == RTEMS_INVALID_NUMBER);
|
||||
|
||||
sc = rtems_task_set_affinity(task_id, sizeof(first_cpu), &first_cpu);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
sc = rtems_task_get_scheduler(task_id, &scheduler_id);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
rtems_test_assert(scheduler_id == scheduler_a_id);
|
||||
|
||||
sc = rtems_task_set_affinity(task_id, sizeof(second_cpu), &second_cpu);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
sc = rtems_task_get_scheduler(task_id, &scheduler_id);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
rtems_test_assert(scheduler_id == scheduler_b_id);
|
||||
|
||||
sc = rtems_task_start(task_id, task, 0);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
sc = rtems_task_set_scheduler(task_id, scheduler_a_id);
|
||||
rtems_test_assert(sc == RTEMS_INCORRECT_STATE);
|
||||
|
||||
sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
sc = rtems_task_delete(task_id);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
}
|
||||
|
||||
#else /* defined(__RTEMS_HAVE_SYS_CPUSET_H__) */
|
||||
|
||||
static void test(void)
|
||||
{
|
||||
/* Nothing to do */
|
||||
}
|
||||
|
||||
#endif /* defined(__RTEMS_HAVE_SYS_CPUSET_H__) */
|
||||
|
||||
static void Init(rtems_task_argument arg)
|
||||
{
|
||||
rtems_resource_snapshot snapshot;
|
||||
|
||||
TEST_BEGIN();
|
||||
|
||||
rtems_resource_snapshot_take(&snapshot);
|
||||
|
||||
test();
|
||||
|
||||
rtems_test_assert(rtems_resource_snapshot_check(&snapshot));
|
||||
|
||||
TEST_END();
|
||||
rtems_test_exit(0);
|
||||
}
|
||||
|
||||
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
|
||||
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
|
||||
|
||||
#define CONFIGURE_SMP_APPLICATION
|
||||
|
||||
#define CONFIGURE_SMP_MAXIMUM_PROCESSORS CPU_COUNT
|
||||
|
||||
#define CONFIGURE_MAXIMUM_PRIORITY 255
|
||||
|
||||
#define CONFIGURE_SCHEDULER_PRIORITY_SMP
|
||||
|
||||
#include <rtems/scheduler.h>
|
||||
|
||||
RTEMS_SCHEDULER_CONTEXT_PRIORITY_SMP(a, CONFIGURE_MAXIMUM_PRIORITY + 1);
|
||||
|
||||
RTEMS_SCHEDULER_CONTEXT_PRIORITY_SMP(b, CONFIGURE_MAXIMUM_PRIORITY + 1);
|
||||
|
||||
#define CONFIGURE_SCHEDULER_CONTROLS \
|
||||
RTEMS_SCHEDULER_CONTROL_PRIORITY_SMP(a, SCHED_A), \
|
||||
RTEMS_SCHEDULER_CONTROL_PRIORITY_SMP(b, SCHED_B)
|
||||
|
||||
#define CONFIGURE_SMP_SCHEDULER_ASSIGNMENTS \
|
||||
RTEMS_SCHEDULER_ASSIGN(0, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY), \
|
||||
RTEMS_SCHEDULER_ASSIGN(1, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY)
|
||||
|
||||
#define CONFIGURE_MAXIMUM_TASKS CPU_COUNT
|
||||
|
||||
#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
|
||||
|
||||
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
|
||||
|
||||
#define CONFIGURE_INIT
|
||||
|
||||
#include <rtems/confdefs.h>
|
||||
12
testsuites/smptests/smpscheduler02/smpscheduler02.doc
Normal file
12
testsuites/smptests/smpscheduler02/smpscheduler02.doc
Normal file
@@ -0,0 +1,12 @@
|
||||
This file describes the directives and concepts tested by this test set.
|
||||
|
||||
test set name: smpscheduler02
|
||||
|
||||
directives:
|
||||
|
||||
- rtems_task_set_scheduler()
|
||||
- rtems_task_start()
|
||||
|
||||
concepts:
|
||||
|
||||
- Ensure that start of a thread for another partition works.
|
||||
2
testsuites/smptests/smpscheduler02/smpscheduler02.scn
Normal file
2
testsuites/smptests/smpscheduler02/smpscheduler02.scn
Normal file
@@ -0,0 +1,2 @@
|
||||
*** BEGIN OF TEST SMPSCHEDULER 2 ***
|
||||
*** END OF TEST SMPSCHEDULER 2 ***
|
||||
@@ -35,6 +35,7 @@ static void test_task_get_set_affinity(void)
|
||||
{
|
||||
#if defined(__RTEMS_HAVE_SYS_CPUSET_H__)
|
||||
rtems_id self_id = rtems_task_self();
|
||||
rtems_id task_id;
|
||||
rtems_status_code sc;
|
||||
cpu_set_t cpusetone;
|
||||
cpu_set_t cpuset;
|
||||
@@ -46,6 +47,16 @@ static void test_task_get_set_affinity(void)
|
||||
CPU_ZERO(&cpusetone);
|
||||
CPU_SET(0, &cpusetone);
|
||||
|
||||
sc = rtems_task_create(
|
||||
rtems_build_name('T', 'A', 'S', 'K'),
|
||||
2,
|
||||
RTEMS_MINIMUM_STACK_SIZE,
|
||||
RTEMS_DEFAULT_MODES,
|
||||
RTEMS_DEFAULT_ATTRIBUTES,
|
||||
&task_id
|
||||
);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
sc = rtems_task_get_affinity(RTEMS_SELF, sizeof(cpuset), NULL);
|
||||
rtems_test_assert(sc == RTEMS_INVALID_ADDRESS);
|
||||
|
||||
@@ -70,16 +81,19 @@ static void test_task_get_set_affinity(void)
|
||||
rtems_test_assert(CPU_EQUAL(&cpuset, &cpusetone));
|
||||
|
||||
sc = rtems_task_set_affinity(RTEMS_SELF, sizeof(cpuset), &cpuset);
|
||||
rtems_test_assert(sc == RTEMS_INVALID_NUMBER);
|
||||
|
||||
sc = rtems_task_set_affinity(self_id, sizeof(cpuset), &cpuset);
|
||||
rtems_test_assert(sc == RTEMS_INVALID_NUMBER);
|
||||
|
||||
sc = rtems_task_set_affinity(task_id, sizeof(cpuset), &cpuset);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
sc = rtems_task_get_affinity(self_id, sizeof(cpuset), &cpuset);
|
||||
sc = rtems_task_get_affinity(task_id, sizeof(cpuset), &cpuset);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
rtems_test_assert(CPU_EQUAL(&cpuset, &cpusetone));
|
||||
|
||||
sc = rtems_task_set_affinity(self_id, sizeof(cpuset), &cpuset);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
cpusetbigone = CPU_ALLOC(big);
|
||||
rtems_test_assert(cpusetbigone != NULL);
|
||||
|
||||
@@ -89,12 +103,15 @@ static void test_task_get_set_affinity(void)
|
||||
CPU_ZERO_S(cpusetbigsize, cpusetbigone);
|
||||
CPU_SET_S(0, cpusetbigsize, cpusetbigone);
|
||||
|
||||
sc = rtems_task_get_affinity(RTEMS_SELF, cpusetbigsize, cpusetbig);
|
||||
sc = rtems_task_get_affinity(task_id, cpusetbigsize, cpusetbig);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
rtems_test_assert(CPU_EQUAL_S(cpusetbigsize, cpusetbig, cpusetbigone));
|
||||
|
||||
sc = rtems_task_set_affinity(RTEMS_SELF, cpusetbigsize, cpusetbig);
|
||||
sc = rtems_task_set_affinity(task_id, cpusetbigsize, cpusetbig);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
sc = rtems_task_delete(task_id);
|
||||
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
|
||||
|
||||
CPU_FREE(cpusetbig);
|
||||
|
||||
Reference in New Issue
Block a user