diff options
Diffstat (limited to 'cpukit')
-rw-r--r-- | cpukit/rtems/Makefile.am | 1 | ||||
-rw-r--r-- | cpukit/rtems/include/rtems/rtems/attr.h | 14 | ||||
-rw-r--r-- | cpukit/rtems/include/rtems/rtems/attrimpl.h | 31 | ||||
-rw-r--r-- | cpukit/rtems/include/rtems/rtems/sem.h | 46 | ||||
-rw-r--r-- | cpukit/rtems/include/rtems/rtems/semimpl.h | 9 | ||||
-rw-r--r-- | cpukit/rtems/src/semcreate.c | 38 | ||||
-rw-r--r-- | cpukit/rtems/src/semdelete.c | 21 | ||||
-rw-r--r-- | cpukit/rtems/src/semflush.c | 10 | ||||
-rw-r--r-- | cpukit/rtems/src/semobtain.c | 19 | ||||
-rw-r--r-- | cpukit/rtems/src/semrelease.c | 14 | ||||
-rw-r--r-- | cpukit/rtems/src/semsetpriority.c | 116 | ||||
-rw-r--r-- | cpukit/sapi/include/confdefs.h | 14 | ||||
-rw-r--r-- | cpukit/score/Makefile.am | 2 | ||||
-rw-r--r-- | cpukit/score/include/rtems/score/mrsp.h | 133 | ||||
-rw-r--r-- | cpukit/score/include/rtems/score/mrspimpl.h | 283 | ||||
-rw-r--r-- | cpukit/score/include/rtems/score/schedulerimpl.h | 10 | ||||
-rw-r--r-- | cpukit/score/preinstall.am | 8 |
17 files changed, 758 insertions, 11 deletions
diff --git a/cpukit/rtems/Makefile.am b/cpukit/rtems/Makefile.am index 4b84fa1343..eb9b16ee04 100644 --- a/cpukit/rtems/Makefile.am +++ b/cpukit/rtems/Makefile.am @@ -206,6 +206,7 @@ librtems_a_SOURCES += src/semrelease.c librtems_a_SOURCES += src/semflush.c librtems_a_SOURCES += src/semtranslatereturncode.c librtems_a_SOURCES += src/semdata.c +librtems_a_SOURCES += src/semsetpriority.c ## EVENT_C_FILES librtems_a_SOURCES += src/event.c diff --git a/cpukit/rtems/include/rtems/rtems/attr.h b/cpukit/rtems/include/rtems/rtems/attr.h index d326539714..7e8fa4818a 100644 --- a/cpukit/rtems/include/rtems/rtems/attr.h +++ b/cpukit/rtems/include/rtems/rtems/attr.h @@ -139,6 +139,20 @@ typedef uint32_t rtems_attribute; */ #define RTEMS_PRIORITY_CEILING 0x00000080 +/** + * This attribute constant indicates that the Classic API Semaphore instance + * created will NOT use the Multiprocessor Resource Sharing Protocol. + */ +#define RTEMS_NO_MULTIPROCESSOR_RESOURCE_SHARING 0x00000000 + +/** + * This attribute constant indicates that the Classic API Semaphore instance + * created will use the Multiprocessor Resource Sharing Protocol. + * + * @note The semaphore instance must be a binary semaphore. + */ +#define RTEMS_MULTIPROCESSOR_RESOURCE_SHARING 0x00000100 + /******************** RTEMS Barrier Specific Attributes ********************/ /** diff --git a/cpukit/rtems/include/rtems/rtems/attrimpl.h b/cpukit/rtems/include/rtems/rtems/attrimpl.h index 0f78c44672..a32c37096d 100644 --- a/cpukit/rtems/include/rtems/rtems/attrimpl.h +++ b/cpukit/rtems/include/rtems/rtems/attrimpl.h @@ -185,6 +185,23 @@ RTEMS_INLINE_ROUTINE bool _Attributes_Is_inherit_priority( } /** + * @brief Returns true if the attribute set has at most one protocol, and false + * otherwise. + * + * The protocols are RTEMS_INHERIT_PRIORITY, RTEMS_PRIORITY_CEILING and + * RTEMS_MULTIPROCESSOR_RESOURCE_SHARING. + */ +RTEMS_INLINE_ROUTINE bool _Attributes_Has_at_most_one_protocol( + rtems_attribute attribute_set +) +{ + attribute_set &= RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY_CEILING + | RTEMS_MULTIPROCESSOR_RESOURCE_SHARING; + + return ( attribute_set & ( attribute_set - 1 ) ) == 0; +} + +/** * @brief Checks if the priority ceiling attribute * is enabled in the attribute_set * @@ -199,6 +216,20 @@ RTEMS_INLINE_ROUTINE bool _Attributes_Is_priority_ceiling( } /** + * @brief Checks if the Multiprocessor Resource Sharing Protocol attribute + * is enabled in the attribute_set + * + * This function returns TRUE if the Multiprocessor Resource Sharing Protocol + * attribute is enabled in the attribute_set and FALSE otherwise. + */ +RTEMS_INLINE_ROUTINE bool _Attributes_Is_multiprocessor_resource_sharing( + rtems_attribute attribute_set +) +{ + return ( attribute_set & RTEMS_MULTIPROCESSOR_RESOURCE_SHARING ) != 0; +} + +/** * @brief Checks if the barrier automatic release * attribute is enabled in the attribute_set * diff --git a/cpukit/rtems/include/rtems/rtems/sem.h b/cpukit/rtems/include/rtems/rtems/sem.h index 782314d163..2442010113 100644 --- a/cpukit/rtems/include/rtems/rtems/sem.h +++ b/cpukit/rtems/include/rtems/rtems/sem.h @@ -38,6 +38,7 @@ #include <rtems/score/coremutex.h> #include <rtems/score/object.h> #include <rtems/score/coresem.h> +#include <rtems/score/mrsp.h> #ifdef __cplusplus extern "C" { @@ -88,6 +89,10 @@ typedef struct { * API Semaphore instance. */ CORE_semaphore_Control semaphore; + +#if defined(RTEMS_SMP) + MRSP_Control mrsp; +#endif } Core_control; } Semaphore_Control; @@ -208,6 +213,47 @@ rtems_status_code rtems_semaphore_flush( rtems_id id ); +/** + * @brief Sets the priority value with respect to the specified scheduler of a + * semaphore. + * + * The special priority value @ref RTEMS_CURRENT_PRIORITY can be used to get + * the current priority value without changing it. + * + * The interpretation of the priority value depends on the protocol of the + * semaphore object. + * + * - The Multiprocessor Resource Sharing Protocol needs a ceiling priority per + * scheduler instance. This operation can be used to specify these priority + * values. + * - For the Priority Ceiling Protocol the ceiling priority is used with this + * operation. + * - For other protocols this operation is not defined. + * + * @param[in] semaphore_id Identifier of the semaphore. + * @param[in] scheduler_id Identifier of the scheduler. + * @param[in] new_priority The new priority value. Use + * @ref RTEMS_CURRENT_PRIORITY to not set a new priority and only get the + * current priority. + * @param[out] old_priority Reference to store the old priority value. + * + * @retval RTEMS_SUCCESSFUL Successful operation. + * @retval RTEMS_INVALID_ID Invalid semaphore or scheduler identifier. + * @retval RTEMS_INVALID_ADDRESS The old priority reference is @c NULL. + * @retval RTEMS_INVALID_PRIORITY The new priority value is invalid. + * @retval RTEMS_NOT_DEFINED The set priority operation is not defined for the + * protocol of this semaphore object. + * @retval RTEMS_ILLEGAL_ON_REMOTE_OBJECT Not supported for remote semaphores. + * + * @see rtems_scheduler_ident() and rtems_task_set_priority(). + */ +rtems_status_code rtems_semaphore_set_priority( + rtems_id semaphore_id, + rtems_id scheduler_id, + rtems_task_priority new_priority, + rtems_task_priority *old_priority +); + /**@}*/ #ifdef __cplusplus diff --git a/cpukit/rtems/include/rtems/rtems/semimpl.h b/cpukit/rtems/include/rtems/rtems/semimpl.h index 51da4cdbcf..e0a35a2e33 100644 --- a/cpukit/rtems/include/rtems/rtems/semimpl.h +++ b/cpukit/rtems/include/rtems/rtems/semimpl.h @@ -20,6 +20,7 @@ #include <rtems/rtems/sem.h> #include <rtems/score/coremuteximpl.h> #include <rtems/score/coresemimpl.h> +#include <rtems/score/mrspimpl.h> #ifdef __cplusplus extern "C" { @@ -92,6 +93,14 @@ _Semaphore_Translate_core_mutex_return_code( return _Semaphore_Translate_core_mutex_return_code_[status]; } +#if defined(RTEMS_SMP) +RTEMS_INLINE_ROUTINE rtems_status_code +_Semaphore_Translate_MRSP_status_code( MRSP_Status mrsp_status ) +{ + return (rtems_status_code) mrsp_status; +} +#endif + /** * @brief Semaphore Translate Core Semaphore Return Code * diff --git a/cpukit/rtems/src/semcreate.c b/cpukit/rtems/src/semcreate.c index fb597d1cbd..5e93e02632 100644 --- a/cpukit/rtems/src/semcreate.c +++ b/cpukit/rtems/src/semcreate.c @@ -78,12 +78,19 @@ rtems_status_code rtems_semaphore_create( return RTEMS_MP_NOT_CONFIGURED; if ( _Attributes_Is_inherit_priority( attribute_set ) || - _Attributes_Is_priority_ceiling( attribute_set ) ) + _Attributes_Is_priority_ceiling( attribute_set ) || + _Attributes_Is_multiprocessor_resource_sharing( attribute_set ) ) return RTEMS_NOT_DEFINED; } else #endif + if ( _Attributes_Is_multiprocessor_resource_sharing( attribute_set ) && + !( _Attributes_Is_binary_semaphore( attribute_set ) && + !_Attributes_Is_priority( attribute_set ) ) ) { + return RTEMS_NOT_DEFINED; + } + if ( _Attributes_Is_inherit_priority( attribute_set ) || _Attributes_Is_priority_ceiling( attribute_set ) ) { @@ -93,13 +100,22 @@ rtems_status_code rtems_semaphore_create( } - if ( _Attributes_Is_inherit_priority( attribute_set ) && - _Attributes_Is_priority_ceiling( attribute_set ) ) + if ( !_Attributes_Has_at_most_one_protocol( attribute_set ) ) return RTEMS_NOT_DEFINED; if ( !_Attributes_Is_counting_semaphore( attribute_set ) && ( count > 1 ) ) return RTEMS_INVALID_NUMBER; +#if !defined(RTEMS_SMP) + /* + * On uni-processor configurations the Multiprocessor Resource Sharing + * Protocol is equivalent to the Priority Ceiling Protocol. + */ + if ( _Attributes_Is_multiprocessor_resource_sharing( attribute_set ) ) { + attribute_set |= RTEMS_PRIORITY_CEILING | RTEMS_PRIORITY; + } +#endif + the_semaphore = _Semaphore_Allocate(); if ( !the_semaphore ) { @@ -144,6 +160,22 @@ rtems_status_code rtems_semaphore_create( &the_semaphore_attr, count ); +#if defined(RTEMS_SMP) + } else if ( _Attributes_Is_multiprocessor_resource_sharing( attribute_set ) ) { + MRSP_Status mrsp_status = _MRSP_Initialize( + &the_semaphore->Core_control.mrsp, + priority_ceiling, + _Thread_Get_executing(), + count != 1 + ); + + if ( mrsp_status != MRSP_SUCCESSFUL ) { + _Semaphore_Free( the_semaphore ); + _Objects_Allocator_unlock(); + + return _Semaphore_Translate_MRSP_status_code( mrsp_status ); + } +#endif } else { /* * It is either simple binary semaphore or a more powerful mutex diff --git a/cpukit/rtems/src/semdelete.c b/cpukit/rtems/src/semdelete.c index 6e7c5eafad..52bb14e33c 100644 --- a/cpukit/rtems/src/semdelete.c +++ b/cpukit/rtems/src/semdelete.c @@ -43,6 +43,7 @@ rtems_status_code rtems_semaphore_delete( { Semaphore_Control *the_semaphore; Objects_Locations location; + rtems_attribute attribute_set; _Objects_Allocator_lock(); @@ -50,10 +51,22 @@ rtems_status_code rtems_semaphore_delete( switch ( location ) { case OBJECTS_LOCAL: - if ( !_Attributes_Is_counting_semaphore(the_semaphore->attribute_set) ) { + attribute_set = the_semaphore->attribute_set; +#if defined(RTEMS_SMP) + if ( _Attributes_Is_multiprocessor_resource_sharing( attribute_set ) ) { + MRSP_Status mrsp_status = _MRSP_Destroy( + &the_semaphore->Core_control.mrsp + ); + if ( mrsp_status != MRSP_SUCCESSFUL ) { + _Objects_Put( &the_semaphore->Object ); + _Objects_Allocator_unlock(); + return _Semaphore_Translate_MRSP_status_code( mrsp_status ); + } + } else +#endif + if ( !_Attributes_Is_counting_semaphore( attribute_set ) ) { if ( _CORE_mutex_Is_locked( &the_semaphore->Core_control.mutex ) && - !_Attributes_Is_simple_binary_semaphore( - the_semaphore->attribute_set ) ) { + !_Attributes_Is_simple_binary_semaphore( attribute_set ) ) { _Objects_Put( &the_semaphore->Object ); _Objects_Allocator_unlock(); return RTEMS_RESOURCE_IN_USE; @@ -74,7 +87,7 @@ rtems_status_code rtems_semaphore_delete( _Objects_Close( &_Semaphore_Information, &the_semaphore->Object ); #if defined(RTEMS_MULTIPROCESSING) - if ( _Attributes_Is_global( the_semaphore->attribute_set ) ) { + if ( _Attributes_Is_global( attribute_set ) ) { _Objects_MP_Close( &_Semaphore_Information, the_semaphore->Object.id ); diff --git a/cpukit/rtems/src/semflush.c b/cpukit/rtems/src/semflush.c index f73c92949d..b9b1ec6992 100644 --- a/cpukit/rtems/src/semflush.c +++ b/cpukit/rtems/src/semflush.c @@ -43,12 +43,20 @@ rtems_status_code rtems_semaphore_flush( { Semaphore_Control *the_semaphore; Objects_Locations location; + rtems_attribute attribute_set; the_semaphore = _Semaphore_Get( id, &location ); switch ( location ) { case OBJECTS_LOCAL: - if ( !_Attributes_Is_counting_semaphore(the_semaphore->attribute_set) ) { + attribute_set = the_semaphore->attribute_set; +#if defined(RTEMS_SMP) + if ( _Attributes_Is_multiprocessor_resource_sharing( attribute_set ) ) { + _Objects_Put( &the_semaphore->Object ); + return RTEMS_NOT_DEFINED; + } else +#endif + if ( !_Attributes_Is_counting_semaphore( attribute_set ) ) { _CORE_mutex_Flush( &the_semaphore->Core_control.mutex, SEND_OBJECT_WAS_DELETED, diff --git a/cpukit/rtems/src/semobtain.c b/cpukit/rtems/src/semobtain.c index c9433ca6d9..3608a00053 100644 --- a/cpukit/rtems/src/semobtain.c +++ b/cpukit/rtems/src/semobtain.c @@ -41,6 +41,7 @@ rtems_status_code rtems_semaphore_obtain( Objects_Locations location; ISR_Level level; Thread_Control *executing; + rtems_attribute attribute_set; bool wait; the_semaphore = _Semaphore_Get_interrupt_disable( id, &location, &level ); @@ -48,8 +49,24 @@ rtems_status_code rtems_semaphore_obtain( case OBJECTS_LOCAL: executing = _Thread_Executing; + attribute_set = the_semaphore->attribute_set; wait = !_Options_Is_no_wait( option_set ); - if ( !_Attributes_Is_counting_semaphore(the_semaphore->attribute_set) ) { +#if defined(RTEMS_SMP) + if ( _Attributes_Is_multiprocessor_resource_sharing( attribute_set ) ) { + MRSP_Status mrsp_status; + + _ISR_Enable( level ); + mrsp_status = _MRSP_Obtain( + &the_semaphore->Core_control.mrsp, + executing, + wait, + timeout + ); + _Objects_Put_for_get_isr_disable( &the_semaphore->Object ); + return _Semaphore_Translate_MRSP_status_code( mrsp_status ); + } else +#endif + if ( !_Attributes_Is_counting_semaphore( attribute_set ) ) { _CORE_mutex_Seize( &the_semaphore->Core_control.mutex, executing, diff --git a/cpukit/rtems/src/semrelease.c b/cpukit/rtems/src/semrelease.c index ff4e792b92..2c4be04c78 100644 --- a/cpukit/rtems/src/semrelease.c +++ b/cpukit/rtems/src/semrelease.c @@ -73,12 +73,24 @@ rtems_status_code rtems_semaphore_release( Objects_Locations location; CORE_mutex_Status mutex_status; CORE_semaphore_Status semaphore_status; + rtems_attribute attribute_set; the_semaphore = _Semaphore_Get( id, &location ); switch ( location ) { case OBJECTS_LOCAL: - if ( !_Attributes_Is_counting_semaphore(the_semaphore->attribute_set) ) { + attribute_set = the_semaphore->attribute_set; +#if defined(RTEMS_SMP) + if ( _Attributes_Is_multiprocessor_resource_sharing( attribute_set ) ) { + MRSP_Status mrsp_status = _MRSP_Release( + &the_semaphore->Core_control.mrsp, + _Thread_Get_executing() + ); + _Objects_Put( &the_semaphore->Object ); + return _Semaphore_Translate_MRSP_status_code( mrsp_status ); + } else +#endif + if ( !_Attributes_Is_counting_semaphore( attribute_set ) ) { mutex_status = _CORE_mutex_Surrender( &the_semaphore->Core_control.mutex, id, diff --git a/cpukit/rtems/src/semsetpriority.c b/cpukit/rtems/src/semsetpriority.c new file mode 100644 index 0000000000..b5dd1db101 --- /dev/null +++ b/cpukit/rtems/src/semsetpriority.c @@ -0,0 +1,116 @@ +/* + * 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. + */ + +#if HAVE_CONFIG_H + #include "config.h" +#endif + +#include <rtems/rtems/semimpl.h> +#include <rtems/rtems/attrimpl.h> +#include <rtems/rtems/tasksimpl.h> +#include <rtems/score/schedulerimpl.h> + +static rtems_status_code _Semaphore_Set_priority( + Semaphore_Control *the_semaphore, + rtems_id scheduler_id, + rtems_task_priority new_priority, + rtems_task_priority *old_priority_p +) +{ + rtems_status_code sc; + rtems_attribute attribute_set = the_semaphore->attribute_set; + rtems_task_priority old_priority; + + new_priority = _RTEMS_tasks_Priority_to_Core( new_priority ); + +#if defined(RTEMS_SMP) + if ( _Attributes_Is_multiprocessor_resource_sharing( attribute_set ) ) { + MRSP_Control *mrsp = &the_semaphore->Core_control.mrsp; + uint32_t scheduler_index = _Scheduler_Get_index_by_id( scheduler_id ); + + old_priority = _MRSP_Get_ceiling_priority( mrsp, scheduler_index ); + + if ( new_priority != RTEMS_CURRENT_PRIORITY ) { + _MRSP_Set_ceiling_priority( mrsp, scheduler_index, new_priority ); + } + + sc = RTEMS_SUCCESSFUL; + } else +#endif + if ( _Attributes_Is_priority_ceiling( attribute_set ) ) { + CORE_mutex_Control *mutex = &the_semaphore->Core_control.mutex; + + old_priority = mutex->Attributes.priority_ceiling; + + if ( new_priority != RTEMS_CURRENT_PRIORITY ) { + mutex->Attributes.priority_ceiling = new_priority; + } + + sc = RTEMS_SUCCESSFUL; + } else { + old_priority = 0; + + sc = RTEMS_NOT_DEFINED; + } + + *old_priority_p = _RTEMS_tasks_Priority_from_Core( old_priority ); + + _Objects_Put( &the_semaphore->Object ); + + return sc; +} + +rtems_status_code rtems_semaphore_set_priority( + rtems_id semaphore_id, + rtems_id scheduler_id, + rtems_task_priority new_priority, + rtems_task_priority *old_priority +) +{ + Semaphore_Control *the_semaphore; + Objects_Locations location; + + if ( new_priority != RTEMS_CURRENT_PRIORITY && + !_RTEMS_tasks_Priority_is_valid( new_priority ) ) { + return RTEMS_INVALID_PRIORITY; + } + + if ( old_priority == NULL ) { + return RTEMS_INVALID_ADDRESS; + } + + if ( !_Scheduler_Is_id_valid( scheduler_id ) ) { + return RTEMS_INVALID_ID; + } + + the_semaphore = _Semaphore_Get( semaphore_id, &location ); + switch ( location ) { + case OBJECTS_LOCAL: + return _Semaphore_Set_priority( + the_semaphore, + scheduler_id, + new_priority, + old_priority + ); +#if defined(RTEMS_MULTIPROCESSING) + case OBJECTS_REMOTE: + _Thread_Dispatch(); + return RTEMS_ILLEGAL_ON_REMOTE_OBJECT; +#endif + case OBJECTS_ERROR: + break; + } + + return RTEMS_INVALID_ID; +} diff --git a/cpukit/sapi/include/confdefs.h b/cpukit/sapi/include/confdefs.h index 1c97d153ba..6978277790 100644 --- a/cpukit/sapi/include/confdefs.h +++ b/cpukit/sapi/include/confdefs.h @@ -1792,6 +1792,17 @@ const rtems_libio_helper rtems_fs_init_helper = CONFIGURE_SEMAPHORES_FOR_FILE_SYSTEMS + \ CONFIGURE_NETWORKING_SEMAPHORES) + #if !defined(RTEMS_SMP) || \ + !defined(CONFIGURE_MAXIMUM_MRSP_SEMAPHORES) + #define CONFIGURE_MEMORY_FOR_MRSP_SEMAPHORES 0 + #else + #define CONFIGURE_MEMORY_FOR_MRSP_SEMAPHORES \ + CONFIGURE_MAXIMUM_MRSP_SEMAPHORES * \ + _Configure_From_workspace( \ + RTEMS_ARRAY_SIZE(_Scheduler_Table) * sizeof(Priority_Control) \ + ) + #endif + /* * If there are no user or support semaphores defined, then we can assume * that no memory need be allocated at all for semaphores. @@ -1800,7 +1811,8 @@ const rtems_libio_helper rtems_fs_init_helper = #define CONFIGURE_MEMORY_FOR_SEMAPHORES(_semaphores) 0 #else #define CONFIGURE_MEMORY_FOR_SEMAPHORES(_semaphores) \ - _Configure_Object_RAM(_semaphores, sizeof(Semaphore_Control) ) + _Configure_Object_RAM(_semaphores, sizeof(Semaphore_Control) ) + \ + CONFIGURE_MEMORY_FOR_MRSP_SEMAPHORES #endif #ifndef CONFIGURE_MAXIMUM_MESSAGE_QUEUES diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am index 7c426025ea..b9a9f28514 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -39,6 +39,8 @@ include_rtems_score_HEADERS += include/rtems/score/isr.h include_rtems_score_HEADERS += include/rtems/score/isrlevel.h include_rtems_score_HEADERS += include/rtems/score/isrlock.h include_rtems_score_HEADERS += include/rtems/score/freechain.h +include_rtems_score_HEADERS += include/rtems/score/mrsp.h +include_rtems_score_HEADERS += include/rtems/score/mrspimpl.h include_rtems_score_HEADERS += include/rtems/score/object.h include_rtems_score_HEADERS += include/rtems/score/objectimpl.h include_rtems_score_HEADERS += include/rtems/score/onceimpl.h diff --git a/cpukit/score/include/rtems/score/mrsp.h b/cpukit/score/include/rtems/score/mrsp.h new file mode 100644 index 0000000000..407d5efecd --- /dev/null +++ b/cpukit/score/include/rtems/score/mrsp.h @@ -0,0 +1,133 @@ +/* + * 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. + */ + +#ifndef _RTEMS_SCORE_MRSP_H +#define _RTEMS_SCORE_MRSP_H + +#include <rtems/score/cpuopts.h> + +#if defined(RTEMS_SMP) + +#include <rtems/score/atomic.h> +#include <rtems/score/chain.h> +#include <rtems/score/thread.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup ScoreMRSP Multiprocessor Resource Sharing Protocol Handler + * + * @ingroup Score + * + * @brief Multiprocessor Resource Sharing Protocol (MrsP). + * + * The Multiprocessor Resource Sharing Protocol (MrsP) is defined in A. Burns + * and A.J. Wellings, A Schedulability Compatible Multiprocessor Resource + * Sharing Protocol - MrsP, Proceedings of the 25th Euromicro Conference on + * Real-Time Systems (ECRTS 2013), July 2013. It is a generalization of the + * Priority Ceiling Protocol to SMP systems. Each MrsP semaphore uses a + * ceiling priority per scheduler instance. A task obtaining or owning a MrsP + * semaphore will execute with the ceiling priority for its scheduler instance + * as specified by the MrsP semaphore object. Tasks waiting to get ownership + * of a MrsP semaphore will not relinquish the processor voluntarily. In case + * the owner of a MrsP semaphore gets preempted it can ask all tasks waiting + * for this semaphore to help out and temporarily borrow the right to execute + * on one of their assigned processors. + * + * @{ + */ + +/** + * @brief MrsP status code. + * + * The values are chosen to directly map to RTEMS status codes. In case this + * implementation is used for other APIs, then for example the errno values can + * be added with a bit shift. + */ +typedef enum { + MRSP_SUCCESSFUL = 0, + MRSP_TIMEOUT = 6, + MRSP_INVALID_NUMBER = 10, + MRSP_RESOUCE_IN_USE = 12, + MRSP_UNSATISFIED = 13, + MRSP_INVALID_PRIORITY = 19, + MRSP_NOT_OWNER_OF_RESOURCE = 23, + MRSP_NO_MEMORY = 26 +} MRSP_Status; + +/** + * @brief MrsP rival. + * + * The rivals are used by threads waiting for resource ownership. They are + * registered in the MRSP control block. + */ +typedef struct { + /** + * @brief The node for registration in the MRSP rival chain. + * + * @see MRSP_Control::Rivals. + */ + Chain_Node Node; + + /** + * @brief Identification of the rival thread. + */ + Thread_Control *thread; + + /** + * @brief The rival state. + * + * Initially no state bits are set (MRSP_RIVAL_STATE_WAITING). The rival + * will busy wait until a state change happens. This can be + * MRSP_RIVAL_STATE_NEW_OWNER or MRSP_RIVAL_STATE_TIMEOUT. + */ + Atomic_Uint state; +} MRSP_Rival; + +/** + * @brief MrsP control block. + */ +typedef struct { + /** + * @brief The owner of the MRSP resource. + * + * In case this field is @c NULL, then this MRSP resource has currently no + * owner. + */ + Thread_Control *owner; + + /** + * @brief A chain of MrsP rivals waiting for resource ownership. + * + * @see MRSP_Rival::Node. + */ + Chain_Control Rivals; + + /** + * @brief One ceiling priority per scheduler instance. + */ + Priority_Control *ceiling_priorities; +} MRSP_Control; + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* RTEMS_SMP */ + +#endif /* _RTEMS_SCORE_MRSP_H */ diff --git a/cpukit/score/include/rtems/score/mrspimpl.h b/cpukit/score/include/rtems/score/mrspimpl.h new file mode 100644 index 0000000000..76d3bc898d --- /dev/null +++ b/cpukit/score/include/rtems/score/mrspimpl.h @@ -0,0 +1,283 @@ +/* + * 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. + */ + +#ifndef _RTEMS_SCORE_MRSPIMPL_H +#define _RTEMS_SCORE_MRSPIMPL_H + +#include <rtems/score/mrsp.h> + +#if defined(RTEMS_SMP) + +#include <rtems/score/assert.h> +#include <rtems/score/chainimpl.h> +#include <rtems/score/schedulerimpl.h> +#include <rtems/score/watchdogimpl.h> +#include <rtems/score/wkspace.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @addtogroup ScoreMRSP + * + * @{ + */ + +#define MRSP_RIVAL_STATE_WAITING 0x0U + +#define MRSP_RIVAL_STATE_NEW_OWNER 0x1U + +#define MRSP_RIVAL_STATE_TIMEOUT 0x2U + +RTEMS_INLINE_ROUTINE void _MRSP_Claim_ownership( + MRSP_Control *mrsp, + Thread_Control *new_owner, + Priority_Control ceiling_priority +) +{ + ++new_owner->resource_count; + mrsp->owner = new_owner; + _Thread_Change_priority( new_owner, ceiling_priority, false ); +} + +RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Initialize( + MRSP_Control *mrsp, + Priority_Control ceiling_priority, + Thread_Control *executing, + bool initially_locked +) +{ + uint32_t scheduler_count = _Scheduler_Count; + uint32_t i; + + if ( initially_locked ) { + return MRSP_INVALID_NUMBER; + } + + mrsp->ceiling_priorities = _Workspace_Allocate( + sizeof( *mrsp->ceiling_priorities ) * scheduler_count + ); + if ( mrsp->ceiling_priorities == NULL ) { + return MRSP_NO_MEMORY; + } + + for ( i = 0 ; i < scheduler_count ; ++i ) { + mrsp->ceiling_priorities[ i ] = ceiling_priority; + } + + mrsp->owner = NULL; + _Chain_Initialize_empty( &mrsp->Rivals ); + + return MRSP_SUCCESSFUL; +} + +RTEMS_INLINE_ROUTINE Priority_Control _MRSP_Get_ceiling_priority( + MRSP_Control *mrsp, + uint32_t scheduler_index +) +{ + return mrsp->ceiling_priorities[ scheduler_index ]; +} + +RTEMS_INLINE_ROUTINE void _MRSP_Set_ceiling_priority( + MRSP_Control *mrsp, + uint32_t scheduler_index, + Priority_Control ceiling_priority +) +{ + mrsp->ceiling_priorities[ scheduler_index ] = ceiling_priority; +} + +RTEMS_INLINE_ROUTINE void _MRSP_Restore_priority( Thread_Control *thread ) +{ + _Thread_Change_priority( thread, thread->real_priority, true ); +} + +RTEMS_INLINE_ROUTINE void _MRSP_Add_state( + MRSP_Rival *rival, + unsigned int state +) +{ + _Atomic_Fetch_or_uint( &rival->state, state, ATOMIC_ORDER_RELEASE ); +} + +RTEMS_INLINE_ROUTINE void _MRSP_Timeout( + Objects_Id id, + void *arg +) +{ + MRSP_Rival *rival = arg; + + (void) id; + + _MRSP_Add_state( rival, MRSP_RIVAL_STATE_TIMEOUT ); +} + +RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Wait_for_ownership( + MRSP_Control *mrsp, + Thread_Control *executing, + Priority_Control ceiling_priority, + Watchdog_Interval timeout +) +{ + MRSP_Status status; + MRSP_Rival rival; + bool previous_life_protection; + unsigned int state; + + _Thread_Change_priority( executing, ceiling_priority, false ); + + rival.thread = executing; + _Atomic_Init_uint( &rival.state, MRSP_RIVAL_STATE_WAITING ); + _Chain_Append_unprotected( &mrsp->Rivals, &rival.Node ); + + if ( timeout > 0 ) { + _Watchdog_Initialize( + &executing->Timer, + _MRSP_Timeout, + 0, + &rival + ); + _Watchdog_Insert_ticks( &executing->Timer, timeout ); + } + + previous_life_protection = _Thread_Set_life_protection( true ); + _Thread_Enable_dispatch(); + + _Assert( _Debug_Is_thread_dispatching_allowed() ); + + while ( + _Atomic_Load_uint( &rival.state, ATOMIC_ORDER_ACQUIRE ) + == MRSP_RIVAL_STATE_WAITING + ) { + /* Wait for state change */ + } + + _Thread_Disable_dispatch(); + _Thread_Set_life_protection( previous_life_protection ); + + if ( timeout > 0 ) { + _Watchdog_Remove( &executing->Timer ); + } + + _Chain_Extract_unprotected( &rival.Node ); + state = _Atomic_Load_uint( &rival.state, ATOMIC_ORDER_RELAXED ); + + if ( ( state & MRSP_RIVAL_STATE_NEW_OWNER ) != 0 ) { + ++executing->resource_count; + + status = MRSP_SUCCESSFUL; + } else { + if ( executing->resource_count == 0 ) { + _MRSP_Restore_priority( executing ); + } + + status = MRSP_TIMEOUT; + } + + return status; +} + +RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Obtain( + MRSP_Control *mrsp, + Thread_Control *executing, + bool wait, + Watchdog_Interval timeout +) +{ + MRSP_Status status; + const Scheduler_Control *scheduler = _Scheduler_Get( executing ); + uint32_t scheduler_index = _Scheduler_Get_index( scheduler ); + Priority_Control ceiling_priority = + _MRSP_Get_ceiling_priority( mrsp, scheduler_index ); + bool priority_ok = !_Scheduler_Is_priority_higher_than( + scheduler, + executing->current_priority, + ceiling_priority + ); + + if ( !priority_ok) { + return MRSP_INVALID_PRIORITY; + } + + if ( mrsp->owner == NULL ) { + _MRSP_Claim_ownership( mrsp, executing, ceiling_priority ); + status = MRSP_SUCCESSFUL; + } else if ( mrsp->owner == executing ) { + status = MRSP_UNSATISFIED; + } else if ( wait ) { + status = _MRSP_Wait_for_ownership( + mrsp, + executing, + ceiling_priority, + timeout + ); + } else { + status = MRSP_UNSATISFIED; + } + + return status; +} + +RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Release( + MRSP_Control *mrsp, + Thread_Control *executing +) +{ + uint32_t resource_count = executing->resource_count; + + if ( mrsp->owner != executing ) { + return MRSP_NOT_OWNER_OF_RESOURCE; + } + + if ( resource_count == 1 ) { + executing->resource_count = 0; + _MRSP_Restore_priority( executing ); + } else { + executing->resource_count = resource_count - 1; + } + + if ( _Chain_Is_empty( &mrsp->Rivals ) ) { + mrsp->owner = NULL; + } else { + MRSP_Rival *rival = (MRSP_Rival *) _Chain_First( &mrsp->Rivals ); + + mrsp->owner = rival->thread; + _MRSP_Add_state( rival, MRSP_RIVAL_STATE_NEW_OWNER ); + } + + return MRSP_SUCCESSFUL; +} + +RTEMS_INLINE_ROUTINE MRSP_Status _MRSP_Destroy( MRSP_Control *mrsp ) +{ + if ( mrsp->owner != NULL ) { + return MRSP_RESOUCE_IN_USE; + } + + _Workspace_Free( mrsp->ceiling_priorities ); + + return MRSP_SUCCESSFUL; +} + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* RTEMS_SMP */ + +#endif /* _RTEMS_SCORE_MRSPIMPL_H */ diff --git a/cpukit/score/include/rtems/score/schedulerimpl.h b/cpukit/score/include/rtems/score/schedulerimpl.h index 15a4207cfd..be841642ca 100644 --- a/cpukit/score/include/rtems/score/schedulerimpl.h +++ b/cpukit/score/include/rtems/score/schedulerimpl.h @@ -617,6 +617,16 @@ RTEMS_INLINE_ROUTINE bool _Scheduler_Get_by_id( && _Scheduler_Get_processor_count( scheduler ) > 0; } +RTEMS_INLINE_ROUTINE bool _Scheduler_Is_id_valid( Objects_Id id ) +{ + const Scheduler_Control *scheduler; + bool ok = _Scheduler_Get_by_id( id, &scheduler ); + + (void) scheduler; + + return ok; +} + RTEMS_INLINE_ROUTINE uint32_t _Scheduler_Get_index( const Scheduler_Control *scheduler ) diff --git a/cpukit/score/preinstall.am b/cpukit/score/preinstall.am index d00e1374c6..45a0ce730f 100644 --- a/cpukit/score/preinstall.am +++ b/cpukit/score/preinstall.am @@ -139,6 +139,14 @@ $(PROJECT_INCLUDE)/rtems/score/freechain.h: include/rtems/score/freechain.h $(PR $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/freechain.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/freechain.h +$(PROJECT_INCLUDE)/rtems/score/mrsp.h: include/rtems/score/mrsp.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/mrsp.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/mrsp.h + +$(PROJECT_INCLUDE)/rtems/score/mrspimpl.h: include/rtems/score/mrspimpl.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/mrspimpl.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/mrspimpl.h + $(PROJECT_INCLUDE)/rtems/score/object.h: include/rtems/score/object.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/object.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/object.h |