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:
Sebastian Huber
2014-04-09 15:07:54 +02:00
parent 27270b0d6c
commit c5831a3f9a
49 changed files with 1589 additions and 114 deletions

View File

@@ -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 */

View File

@@ -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

View File

@@ -48,7 +48,6 @@ int pthread_setaffinity_np(
case OBJECTS_LOCAL:
ok = _Scheduler_Set_affinity(
_Scheduler_Get( the_thread ),
the_thread,
cpusetsize,
cpuset

View File

@@ -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();

View File

@@ -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,

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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 )

View File

@@ -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.

View File

@@ -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(

View File

@@ -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
*

View File

@@ -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__

View File

@@ -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,

View File

@@ -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 );
}
}

View File

@@ -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 );
}
}

View File

@@ -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

View File

@@ -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();

View File

@@ -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 );
}
}
}

View File

@@ -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;

View File

@@ -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 );

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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

View 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>

View 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.

View File

@@ -0,0 +1,2 @@
*** BEGIN OF TEST SMPFATAL 4 ***
*** END OF TEST SMPFATAL 4 ***

View 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

View 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>

View 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.

View File

@@ -0,0 +1,2 @@
*** BEGIN OF TEST SMPFATAL 5 ***
*** END OF TEST SMPFATAL 5 ***

View 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

View 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>

View 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.

View File

@@ -0,0 +1,2 @@
*** TEST SMPFATAL 6 ***
*** END OF TEST SMPFATAL 6 ***

View 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

View 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>

View 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.

View File

@@ -0,0 +1,2 @@
*** TEST SMPFATAL 7 ***
*** END OF TEST SMPFATAL 7 ***

View 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

View 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>

View 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.

View File

@@ -0,0 +1,2 @@
*** TEST SMPFATAL 7 ***
*** END OF TEST SMPFATAL 7 ***

View 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

View 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>

View 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.

View File

@@ -0,0 +1,2 @@
*** BEGIN OF TEST SMPSCHEDULER 2 ***
*** END OF TEST SMPSCHEDULER 2 ***

View File

@@ -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);