diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2014-03-27 14:16:12 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2014-03-31 08:29:44 +0200 |
commit | 23fec9f0e18dc4913fab818118f836af150b98f3 (patch) | |
tree | 66228f23bbf654117a33e28db7a017eea21fb785 /cpukit/score | |
parent | score: Use thread life protection for API mutexes (diff) | |
download | rtems-23fec9f0e18dc4913fab818118f836af150b98f3.tar.bz2 |
score: PR2152: Use allocator mutex for objects
Use allocator mutex for objects allocate/free. This prevents that the
thread dispatch latency depends on the workspace/heap fragmentation.
Diffstat (limited to 'cpukit/score')
-rw-r--r-- | cpukit/score/include/rtems/score/objectimpl.h | 147 | ||||
-rw-r--r-- | cpukit/score/include/rtems/score/threadimpl.h | 7 | ||||
-rw-r--r-- | cpukit/score/src/apimutex.c | 3 | ||||
-rw-r--r-- | cpukit/score/src/objectactivecount.c | 10 | ||||
-rw-r--r-- | cpukit/score/src/objectallocate.c | 27 | ||||
-rw-r--r-- | cpukit/score/src/objectextendinformation.c | 49 | ||||
-rw-r--r-- | cpukit/score/src/objectfree.c | 5 | ||||
-rw-r--r-- | cpukit/score/src/objectshrinkinformation.c | 5 |
8 files changed, 204 insertions, 49 deletions
diff --git a/cpukit/score/include/rtems/score/objectimpl.h b/cpukit/score/include/rtems/score/objectimpl.h index 119f11d829..383f0a738b 100644 --- a/cpukit/score/include/rtems/score/objectimpl.h +++ b/cpukit/score/include/rtems/score/objectimpl.h @@ -20,6 +20,7 @@ #define _RTEMS_SCORE_OBJECTIMPL_H #include <rtems/score/object.h> +#include <rtems/score/apimutex.h> #include <rtems/score/isrlevel.h> #include <rtems/score/threaddispatch.h> @@ -264,25 +265,120 @@ unsigned int _Objects_API_maximum_class( ); /** - * @brief Allocate an object. + * @brief Allocates an object without locking the allocator mutex. * - * This function allocates an object control block from - * the inactive chain of free object control blocks. + * This function can be called in two contexts + * - the executing thread is the owner of the object allocator mutex, or + * - in case the system state is not up, e.g. during sequential system + * initialization. * - * @param[in] information points to an object class information block. + * @param[in] information The object information block. + * + * @retval NULL No object available. + * @retval object The allocated object. + * + * @see _Objects_Allocate() and _Objects_Free(). */ -Objects_Control *_Objects_Allocate( +Objects_Control *_Objects_Allocate_unprotected( Objects_Information *information ); /** - * @brief Free an object. + * @brief Allocates an object. * - * This function frees an object control block to the - * inactive chain of free object control blocks. + * This function locks the object allocator mutex via + * _Objects_Allocator_lock(). The caller must later unlock the object + * allocator mutex via _Objects_Allocator_unlock(). The caller must unlock the + * mutex in any case, even if the allocation failed due to resource shortage. * - * @param[in] information points to an object class information block. - * @param[in] the_object points to the object to deallocate. + * A typical object allocation code looks like this: + * @code + * rtems_status_code some_create( rtems_id *id ) + * { + * rtems_status_code sc; + * Some_Control *some; + * + * // The object allocator mutex protects the executing thread from + * // asynchronous thread restart and deletion. + * some = (Some_Control *) _Objects_Allocate( &_Some_Information ); + * + * if ( some != NULL ) { + * _Some_Initialize( some ); + * sc = RTEMS_SUCCESSFUL; + * } else { + * sc = RTEMS_TOO_MANY; + * } + * + * _Objects_Allocator_unlock(); + * + * return sc; + * } + * @endcode + * + * @param[in] information The object information block. + * + * @retval NULL No object available. + * @retval object The allocated object. + * + * @see _Objects_Free(). + */ +Objects_Control *_Objects_Allocate( Objects_Information *information ); + +/** + * @brief Frees an object. + * + * Appends the object to the chain of inactive objects. + * + * @param[in] information The object information block. + * @param[in] the_object The object to free. + * + * @see _Objects_Allocate(). + * + * A typical object deletion code looks like this: + * @code + * rtems_status_code some_delete( rtems_id id ) + * { + * rtems_status_code sc; + * Some_Control *some; + * Objects_Locations location; + * + * // The object allocator mutex protects the executing thread from + * // asynchronous thread restart and deletion. + * _Objects_Allocator_lock(); + * + * // This will disable thread dispatching, so this starts a thread dispatch + * // critical section. + * some = (Semaphore_Control *) + * _Objects_Get( &_Some_Information, id, &location ); + * + * switch ( location ) { + * case OBJECTS_LOCAL: + * // After the object close an object get with this identifier will + * // fail. + * _Objects_Close( &_Some_Information, &some->Object ); + * + * _Some_Delete( some ); + * + * // This enables thread dispatching, so the thread dispatch critical + * // section ends here. + * _Objects_Put( &some->Object ); + * + * // Thread dispatching is enabled. The object free is only protected + * // by the object allocator mutex. + * _Objects_Free( &_Some_Information, &some->Object ); + * + * sc = RTEMS_SUCCESSFUL; + * break; + * default: + * sc = RTEMS_INVALID_ID; + * break; + * } + * + * _Objects_Allocator_unlock(); + * + * return sc; + * } + * @endcode */ void _Objects_Free( Objects_Information *information, @@ -892,6 +988,37 @@ RTEMS_INLINE_ROUTINE void _Objects_Put_for_get_isr_disable( #endif } +/** + * @brief Locks the object allocator mutex. + * + * While holding the allocator mutex the executing thread is protected from + * asynchronous thread restart and deletion. + * + * The usage of the object allocator mutex with the thread life protection + * makes it possible to allocate and free objects without thread dispatching + * disabled. The usage of a unified workspace and unlimited objects may lead + * to heap fragmentation. Thus the execution time of the _Objects_Allocate() + * function may increase during system run-time. + * + * @see _Objects_Allocator_unlock() and _Objects_Allocate(). + */ +RTEMS_INLINE_ROUTINE void _Objects_Allocator_lock( void ) +{ + _RTEMS_Lock_allocator(); +} + +/** + * @brief Unlocks the object allocator mutex. + * + * In case the mutex is fully unlocked, then this function restores the + * previous thread life protection state and thus may not return if the + * executing thread was restarted or deleted in the mean-time. + */ +RTEMS_INLINE_ROUTINE void _Objects_Allocator_unlock( void ) +{ + _RTEMS_Unlock_allocator(); +} + /** @} */ #ifdef __cplusplus diff --git a/cpukit/score/include/rtems/score/threadimpl.h b/cpukit/score/include/rtems/score/threadimpl.h index d0c7933aa3..2ac8344577 100644 --- a/cpukit/score/include/rtems/score/threadimpl.h +++ b/cpukit/score/include/rtems/score/threadimpl.h @@ -590,13 +590,10 @@ RTEMS_INLINE_ROUTINE uint32_t _Thread_Get_maximum_internal_threads(void) return maximum_internal_threads; } -/** - * This routine allocates an internal thread. - */ - RTEMS_INLINE_ROUTINE Thread_Control *_Thread_Internal_allocate( void ) { - return (Thread_Control *) _Objects_Allocate( &_Thread_Internal_information ); + return (Thread_Control *) + _Objects_Allocate_unprotected( &_Thread_Internal_information ); } RTEMS_INLINE_ROUTINE void _Thread_Request_dispatch_if_executing( diff --git a/cpukit/score/src/apimutex.c b/cpukit/score/src/apimutex.c index 18ac2db864..7899934183 100644 --- a/cpukit/score/src/apimutex.c +++ b/cpukit/score/src/apimutex.c @@ -58,7 +58,8 @@ void _API_Mutex_Allocate( 0 }; - mutex = (API_Mutex_Control *) _Objects_Allocate( &_API_Mutex_Information ); + mutex = (API_Mutex_Control *) + _Objects_Allocate_unprotected( &_API_Mutex_Information ); _CORE_mutex_Initialize( &mutex->Mutex, NULL, &attr, CORE_MUTEX_UNLOCKED ); diff --git a/cpukit/score/src/objectactivecount.c b/cpukit/score/src/objectactivecount.c index de34212f29..de3243afcb 100644 --- a/cpukit/score/src/objectactivecount.c +++ b/cpukit/score/src/objectactivecount.c @@ -17,14 +17,20 @@ #endif #include <rtems/score/objectimpl.h> +#include <rtems/score/assert.h> #include <rtems/score/chainimpl.h> Objects_Maximum _Objects_Active_count( const Objects_Information *information ) { - size_t inactive = _Chain_Node_count_unprotected( &information->Inactive ); - size_t maximum = information->maximum; + size_t inactive; + size_t maximum; + + _Assert( _Debug_Is_owner_of_allocator() ); + + inactive = _Chain_Node_count_unprotected( &information->Inactive ); + maximum = information->maximum; return (Objects_Maximum) ( maximum - inactive ); } diff --git a/cpukit/score/src/objectallocate.c b/cpukit/score/src/objectallocate.c index 842c49d77a..40a7cae82c 100644 --- a/cpukit/score/src/objectallocate.c +++ b/cpukit/score/src/objectallocate.c @@ -19,7 +19,9 @@ #endif #include <rtems/score/objectimpl.h> +#include <rtems/score/assert.h> #include <rtems/score/chainimpl.h> +#include <rtems/score/sysstate.h> /* #define RTEMS_DEBUG_OBJECT_ALLOCATION */ @@ -27,12 +29,24 @@ #include <rtems/bspIo.h> #endif -Objects_Control *_Objects_Allocate( +static Objects_Control *_Objects_Get_inactive( + Objects_Information *information +) +{ + return (Objects_Control *) _Chain_Get_unprotected( &information->Inactive ); +} + +Objects_Control *_Objects_Allocate_unprotected( Objects_Information *information ) { Objects_Control *the_object; + _Assert( + _Debug_Is_owner_of_allocator() + || !_System_state_Is_up( _System_state_Get() ) + ); + /* * If the application is using the optional manager stubs and * still attempts to create the object, the information block @@ -46,7 +60,7 @@ Objects_Control *_Objects_Allocate( * OK. The manager should be initialized and configured to have objects. * With any luck, it is safe to attempt to allocate an object. */ - the_object = (Objects_Control *) _Chain_Get( &information->Inactive ); + the_object = _Objects_Get_inactive( information ); if ( information->auto_extend ) { /* @@ -56,7 +70,7 @@ Objects_Control *_Objects_Allocate( if ( !the_object ) { _Objects_Extend_information( information ); - the_object = (Objects_Control *) _Chain_Get( &information->Inactive ); + the_object = _Objects_Get_inactive( information ); } if ( the_object ) { @@ -83,3 +97,10 @@ Objects_Control *_Objects_Allocate( return the_object; } + +Objects_Control *_Objects_Allocate( Objects_Information *information ) +{ + _RTEMS_Lock_allocator(); + + return _Objects_Allocate_unprotected( information ); +} diff --git a/cpukit/score/src/objectextendinformation.c b/cpukit/score/src/objectextendinformation.c index d11f927588..b1fcec7617 100644 --- a/cpukit/score/src/objectextendinformation.c +++ b/cpukit/score/src/objectextendinformation.c @@ -20,8 +20,10 @@ #include <rtems/score/objectimpl.h> #include <rtems/score/address.h> +#include <rtems/score/assert.h> #include <rtems/score/chainimpl.h> #include <rtems/score/isrlevel.h> +#include <rtems/score/sysstate.h> #include <rtems/score/wkspace.h> #include <string.h> /* for memcpy() */ @@ -42,10 +44,10 @@ void _Objects_Extend_information( ) { Objects_Control *the_object; - Chain_Control Inactive; uint32_t block_count; uint32_t block; uint32_t index_base; + uint32_t index_end; uint32_t minimum_index; uint32_t index; uint32_t maximum; @@ -53,6 +55,11 @@ void _Objects_Extend_information( void *new_object_block; bool do_extend; + _Assert( + _Debug_Is_owner_of_allocator() + || !_System_state_Is_up( _System_state_Get() ) + ); + /* * Search for a free block of indexes. If we do NOT need to allocate or * extend the block table, then we will change do_extend. @@ -76,6 +83,7 @@ void _Objects_Extend_information( index_base += information->allocation_size; } } + index_end = index_base + information->allocation_size; maximum = (uint32_t) information->maximum + information->allocation_size; @@ -213,12 +221,11 @@ void _Objects_Extend_information( object_blocks[block_count] = NULL; inactive_per_block[block_count] = 0; - for ( index=index_base ; - index < ( information->allocation_size + index_base ); - index++ ) { + for ( index = index_base ; index < index_end ; ++index ) { local_table[ index ] = NULL; } + _Thread_Disable_dispatch(); _ISR_Disable( level ); old_tables = information->object_blocks; @@ -235,6 +242,7 @@ void _Objects_Extend_information( ); _ISR_Enable( level ); + _Thread_Enable_dispatch(); _Workspace_Free( old_tables ); @@ -247,32 +255,21 @@ void _Objects_Extend_information( information->object_blocks[ block ] = new_object_block; /* - * Initialize objects .. add to a local chain first. + * Append to inactive chain. */ - _Chain_Initialize( - &Inactive, - information->object_blocks[ block ], - information->allocation_size, - information->size - ); - - /* - * Move from the local chain, initialise, then append to the inactive chain - */ - index = index_base; - - while ((the_object = (Objects_Control *) _Chain_Get( &Inactive )) != NULL ) { - + the_object = information->object_blocks[ block ]; + for ( index = index_base ; index < index_end ; ++index ) { the_object->id = _Objects_Build_id( - information->the_api, - information->the_class, - _Objects_Local_node, - index - ); + information->the_api, + information->the_class, + _Objects_Local_node, + index + ); - _Chain_Append( &information->Inactive, &the_object->Node ); + _Chain_Append_unprotected( &information->Inactive, &the_object->Node ); - index++; + the_object = (Objects_Control *) + ( (char *) the_object + information->size ); } information->inactive_per_block[ block ] = information->allocation_size; diff --git a/cpukit/score/src/objectfree.c b/cpukit/score/src/objectfree.c index cc2fbac5a5..f1c0ee49b2 100644 --- a/cpukit/score/src/objectfree.c +++ b/cpukit/score/src/objectfree.c @@ -19,6 +19,7 @@ #endif #include <rtems/score/objectimpl.h> +#include <rtems/score/assert.h> #include <rtems/score/chainimpl.h> void _Objects_Free( @@ -28,7 +29,9 @@ void _Objects_Free( { uint32_t allocation_size = information->allocation_size; - _Chain_Append( &information->Inactive, &the_object->Node ); + _Assert( _Debug_Is_owner_of_allocator() ); + + _Chain_Append_unprotected( &information->Inactive, &the_object->Node ); if ( information->auto_extend ) { uint32_t block; diff --git a/cpukit/score/src/objectshrinkinformation.c b/cpukit/score/src/objectshrinkinformation.c index 9731c2179d..2f64cd2502 100644 --- a/cpukit/score/src/objectshrinkinformation.c +++ b/cpukit/score/src/objectshrinkinformation.c @@ -19,6 +19,7 @@ #endif #include <rtems/score/objectimpl.h> +#include <rtems/score/assert.h> #include <rtems/score/chainimpl.h> #include <rtems/score/wkspace.h> @@ -30,6 +31,8 @@ void _Objects_Shrink_information( uint32_t block; uint32_t index_base; + _Assert( _Debug_Is_owner_of_allocator() ); + /* * Search the list to find block or chunk with all objects inactive. */ @@ -55,7 +58,7 @@ void _Objects_Shrink_information( node = _Chain_Next( node ); if ( index >= index_base && index < index_end ) { - _Chain_Extract( &object->Node ); + _Chain_Extract_unprotected( &object->Node ); } } |