summaryrefslogtreecommitdiffstats
path: root/cpukit/score
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2014-03-27 14:16:12 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2014-03-31 08:29:44 +0200
commit23fec9f0e18dc4913fab818118f836af150b98f3 (patch)
tree66228f23bbf654117a33e28db7a017eea21fb785 /cpukit/score
parentscore: Use thread life protection for API mutexes (diff)
downloadrtems-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.h147
-rw-r--r--cpukit/score/include/rtems/score/threadimpl.h7
-rw-r--r--cpukit/score/src/apimutex.c3
-rw-r--r--cpukit/score/src/objectactivecount.c10
-rw-r--r--cpukit/score/src/objectallocate.c27
-rw-r--r--cpukit/score/src/objectextendinformation.c49
-rw-r--r--cpukit/score/src/objectfree.c5
-rw-r--r--cpukit/score/src/objectshrinkinformation.c5
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 );
}
}