sapi: SMP support for chains

Add ISR lock to chain control for proper SMP protection.  Replace
rtems_chain_extract() with rtems_chain_explicit_extract() and
rtems_chain_insert() with rtems_chain_explicit_insert() on SMP
configurations.  Use rtems_chain_explicit_extract() and
rtems_chain_explicit_insert() to provide SMP support.
This commit is contained in:
Sebastian Huber
2013-08-26 15:14:33 +02:00
parent e127c4c9ea
commit 1215fd4d94
9 changed files with 326 additions and 64 deletions

View File

@@ -275,7 +275,7 @@ void mpc55xx_edma_release_channel(edma_channel_context *ctx)
unsigned channel_index = edma_channel_index_of_tcd(ctx->edma_tcd); unsigned channel_index = edma_channel_index_of_tcd(ctx->edma_tcd);
mpc55xx_edma_release_channel_by_tcd(ctx->edma_tcd); mpc55xx_edma_release_channel_by_tcd(ctx->edma_tcd);
rtems_chain_extract(&ctx->node); rtems_chain_explicit_extract(&edma_channel_chain, &ctx->node);
sc = rtems_interrupt_handler_remove( sc = rtems_interrupt_handler_remove(
MPC55XX_IRQ_EDMA(channel_index), MPC55XX_IRQ_EDMA(channel_index),

View File

@@ -491,7 +491,7 @@ ata_request_done(ata_req_t *areq, rtems_device_minor_number ctrl_minor,
#endif #endif
ATA_EXEC_CALLBACK(areq, status); ATA_EXEC_CALLBACK(areq, status);
rtems_chain_extract(&areq->link); rtems_chain_explicit_extract(&ata_ide_ctrls[ctrl_minor].reqs, &areq->link);
if (!rtems_chain_is_empty(&ata_ide_ctrls[ctrl_minor].reqs)) if (!rtems_chain_is_empty(&ata_ide_ctrls[ctrl_minor].reqs))
{ {

View File

@@ -26,6 +26,8 @@
int aio_cancel(int fildes, struct aiocb *aiocbp) int aio_cancel(int fildes, struct aiocb *aiocbp)
{ {
rtems_chain_control *idle_req_chain = &aio_request_queue.idle_req;
rtems_chain_control *work_req_chain = &aio_request_queue.work_req;
rtems_aio_request_chain *r_chain; rtems_aio_request_chain *r_chain;
int result; int result;
@@ -40,12 +42,12 @@ int aio_cancel(int fildes, struct aiocb *aiocbp)
if (aiocbp == NULL) { if (aiocbp == NULL) {
AIO_printf ("Cancel all requests\n"); AIO_printf ("Cancel all requests\n");
r_chain = rtems_aio_search_fd (&aio_request_queue.work_req, fildes, 0); r_chain = rtems_aio_search_fd (work_req_chain, fildes, 0);
if (r_chain == NULL) { if (r_chain == NULL) {
AIO_printf ("Request chain not on [WQ]\n"); AIO_printf ("Request chain not on [WQ]\n");
if (!rtems_chain_is_empty (&aio_request_queue.idle_req)) { if (!rtems_chain_is_empty (idle_req_chain)) {
r_chain = rtems_aio_search_fd (&aio_request_queue.idle_req, fildes, 0); r_chain = rtems_aio_search_fd (idle_req_chain, fildes, 0);
if (r_chain == NULL) { if (r_chain == NULL) {
pthread_mutex_unlock(&aio_request_queue.mutex); pthread_mutex_unlock(&aio_request_queue.mutex);
return AIO_ALLDONE; return AIO_ALLDONE;
@@ -53,7 +55,7 @@ int aio_cancel(int fildes, struct aiocb *aiocbp)
AIO_printf ("Request chain on [IQ]\n"); AIO_printf ("Request chain on [IQ]\n");
rtems_chain_extract (&r_chain->next_fd); rtems_chain_explicit_extract (idle_req_chain, &r_chain->next_fd);
rtems_aio_remove_fd (r_chain); rtems_aio_remove_fd (r_chain);
pthread_mutex_destroy (&r_chain->mutex); pthread_mutex_destroy (&r_chain->mutex);
pthread_cond_destroy (&r_chain->mutex); pthread_cond_destroy (&r_chain->mutex);
@@ -70,7 +72,7 @@ int aio_cancel(int fildes, struct aiocb *aiocbp)
AIO_printf ("Request chain on [WQ]\n"); AIO_printf ("Request chain on [WQ]\n");
pthread_mutex_lock (&r_chain->mutex); pthread_mutex_lock (&r_chain->mutex);
rtems_chain_extract (&r_chain->next_fd); rtems_chain_explicit_extract (work_req_chain, &r_chain->next_fd);
rtems_aio_remove_fd (r_chain); rtems_aio_remove_fd (r_chain);
pthread_mutex_unlock (&r_chain->mutex); pthread_mutex_unlock (&r_chain->mutex);
pthread_mutex_unlock (&aio_request_queue.mutex); pthread_mutex_unlock (&aio_request_queue.mutex);
@@ -83,10 +85,10 @@ int aio_cancel(int fildes, struct aiocb *aiocbp)
rtems_set_errno_and_return_minus_one (EINVAL); rtems_set_errno_and_return_minus_one (EINVAL);
} }
r_chain = rtems_aio_search_fd (&aio_request_queue.work_req, fildes, 0); r_chain = rtems_aio_search_fd (work_req_chain, fildes, 0);
if (r_chain == NULL) { if (r_chain == NULL) {
if (!rtems_chain_is_empty (&aio_request_queue.idle_req)) { if (!rtems_chain_is_empty (idle_req_chain)) {
r_chain = rtems_aio_search_fd (&aio_request_queue.idle_req, fildes, 0); r_chain = rtems_aio_search_fd (idle_req_chain, fildes, 0);
if (r_chain == NULL) { if (r_chain == NULL) {
pthread_mutex_unlock (&aio_request_queue.mutex); pthread_mutex_unlock (&aio_request_queue.mutex);
rtems_set_errno_and_return_minus_one (EINVAL); rtems_set_errno_and_return_minus_one (EINVAL);

View File

@@ -120,7 +120,9 @@ rtems_aio_search_fd (rtems_chain_control *chain, int fildes, int create)
if (rtems_chain_is_empty (chain)) if (rtems_chain_is_empty (chain))
rtems_chain_prepend (chain, &r_chain->next_fd); rtems_chain_prepend (chain, &r_chain->next_fd);
else else
rtems_chain_insert (rtems_chain_previous (node), &r_chain->next_fd); rtems_chain_explicit_insert (chain,
rtems_chain_previous (node),
&r_chain->next_fd);
r_chain->new_fd = 1; r_chain->new_fd = 1;
r_chain->fildes = fildes; r_chain->fildes = fildes;
@@ -144,19 +146,22 @@ rtems_aio_search_fd (rtems_chain_control *chain, int fildes, int create)
static void static void
rtems_aio_move_to_work (rtems_aio_request_chain *r_chain) rtems_aio_move_to_work (rtems_aio_request_chain *r_chain)
{ {
rtems_chain_control *work_req_chain = &aio_request_queue.work_req;
rtems_aio_request_chain *temp; rtems_aio_request_chain *temp;
rtems_chain_node *node; rtems_chain_node *node;
node = rtems_chain_first (&aio_request_queue.work_req); node = rtems_chain_first (work_req_chain);
temp = (rtems_aio_request_chain *) node; temp = (rtems_aio_request_chain *) node;
while (temp->fildes < r_chain->fildes && while (temp->fildes < r_chain->fildes &&
!rtems_chain_is_tail (&aio_request_queue.work_req, node)) { !rtems_chain_is_tail (work_req_chain, node)) {
node = rtems_chain_next (node); node = rtems_chain_next (node);
temp = (rtems_aio_request_chain *) node; temp = (rtems_aio_request_chain *) node;
} }
rtems_chain_insert (rtems_chain_previous (node), &r_chain->next_fd); rtems_chain_explicit_insert (work_req_chain,
rtems_chain_previous (node),
&r_chain->next_fd);
} }
@@ -195,7 +200,7 @@ rtems_aio_insert_prio (rtems_chain_control *chain, rtems_aio_request *req)
prio = ((rtems_aio_request *) node)->aiocbp->aio_reqprio; prio = ((rtems_aio_request *) node)->aiocbp->aio_reqprio;
} }
rtems_chain_insert (node->previous, &req->next_prio); rtems_chain_explicit_insert (chain, node->previous, &req->next_prio);
} }
} }
@@ -221,7 +226,7 @@ void rtems_aio_remove_fd (rtems_aio_request_chain *r_chain)
while (!rtems_chain_is_tail (chain, node)) while (!rtems_chain_is_tail (chain, node))
{ {
rtems_chain_extract (node); rtems_chain_explicit_extract (chain, node);
rtems_aio_request *req = (rtems_aio_request *) node; rtems_aio_request *req = (rtems_aio_request *) node;
node = rtems_chain_next (node); node = rtems_chain_next (node);
req->aiocbp->error_code = ECANCELED; req->aiocbp->error_code = ECANCELED;
@@ -265,7 +270,7 @@ int rtems_aio_remove_req (rtems_chain_control *chain, struct aiocb *aiocbp)
return AIO_NOTCANCELED; return AIO_NOTCANCELED;
else else
{ {
rtems_chain_extract (node); rtems_chain_explicit_extract (chain, node);
current->aiocbp->error_code = ECANCELED; current->aiocbp->error_code = ECANCELED;
current->aiocbp->return_value = -1; current->aiocbp->return_value = -1;
free (current); free (current);
@@ -440,7 +445,7 @@ rtems_aio_handle (void *arg)
param.sched_priority = req->priority; param.sched_priority = req->priority;
pthread_setschedparam (pthread_self(), req->policy, &param); pthread_setschedparam (pthread_self(), req->policy, &param);
rtems_chain_extract (node); rtems_chain_explicit_extract (chain, node);
pthread_mutex_unlock (&r_chain->mutex); pthread_mutex_unlock (&r_chain->mutex);
@@ -506,7 +511,8 @@ rtems_aio_handle (void *arg)
/* If no requests were added to the chain we delete the fd chain from /* If no requests were added to the chain we delete the fd chain from
the queue and start working with idle fd chains */ the queue and start working with idle fd chains */
if (result == ETIMEDOUT) { if (result == ETIMEDOUT) {
rtems_chain_extract (&r_chain->next_fd); rtems_chain_explicit_extract (&aio_request_queue.work_req,
&r_chain->next_fd);
pthread_mutex_destroy (&r_chain->mutex); pthread_mutex_destroy (&r_chain->mutex);
pthread_cond_destroy (&r_chain->cond); pthread_cond_destroy (&r_chain->cond);
free (r_chain); free (r_chain);
@@ -542,7 +548,7 @@ rtems_aio_handle (void *arg)
++aio_request_queue.active_threads; ++aio_request_queue.active_threads;
node = rtems_chain_first (&aio_request_queue.idle_req); node = rtems_chain_first (&aio_request_queue.idle_req);
rtems_chain_extract (node); rtems_chain_explicit_extract (&aio_request_queue.idle_req, node);
r_chain = (rtems_aio_request_chain *) node; r_chain = (rtems_aio_request_chain *) node;
rtems_aio_move_to_work (r_chain); rtems_aio_move_to_work (r_chain);

View File

@@ -31,6 +31,7 @@ libsapi_a_SOURCES = src/debug.c src/extension.c src/extensioncreate.c \
src/chainappendnotify.c src/chaingetnotify.c src/chaingetwait.c \ src/chainappendnotify.c src/chaingetnotify.c src/chaingetwait.c \
src/chainprependnotify.c src/rbheap.c src/interrdesc.c \ src/chainprependnotify.c src/rbheap.c src/interrdesc.c \
src/fatal2.c src/fatalsrcdesc.c src/fatal2.c src/fatalsrcdesc.c
libsapi_a_SOURCES += src/chainsmp.c
libsapi_a_CPPFLAGS = $(AM_CPPFLAGS) libsapi_a_CPPFLAGS = $(AM_CPPFLAGS)
include $(srcdir)/preinstall.am include $(srcdir)/preinstall.am

View File

@@ -19,6 +19,7 @@
#define _RTEMS_CHAIN_H #define _RTEMS_CHAIN_H
#include <rtems/score/chainimpl.h> #include <rtems/score/chainimpl.h>
#include <rtems/score/isrlock.h>
#include <rtems/rtems/event.h> #include <rtems/rtems/event.h>
#ifdef __cplusplus #ifdef __cplusplus
@@ -36,13 +37,16 @@ extern "C" {
typedef Chain_Node rtems_chain_node; typedef Chain_Node rtems_chain_node;
typedef Chain_Control rtems_chain_control; typedef struct {
Chain_Control Chain;
ISR_lock_Control Lock;
} rtems_chain_control;
/** /**
* @brief Chain initializer for an empty chain with designator @a name. * @brief Chain initializer for an empty chain with designator @a name.
*/ */
#define RTEMS_CHAIN_INITIALIZER_EMPTY(name) \ #define RTEMS_CHAIN_INITIALIZER_EMPTY( name ) \
CHAIN_INITIALIZER_EMPTY(name) { CHAIN_INITIALIZER_EMPTY( name.Chain ), ISR_LOCK_INITIALIZER }
/** /**
* @brief Chain initializer for a chain with one @a node. * @brief Chain initializer for a chain with one @a node.
@@ -50,7 +54,7 @@ typedef Chain_Control rtems_chain_control;
* @see RTEMS_CHAIN_NODE_INITIALIZER_ONE_NODE_CHAIN(). * @see RTEMS_CHAIN_NODE_INITIALIZER_ONE_NODE_CHAIN().
*/ */
#define RTEMS_CHAIN_INITIALIZER_ONE_NODE( node ) \ #define RTEMS_CHAIN_INITIALIZER_ONE_NODE( node ) \
CHAIN_INITIALIZER_ONE_NODE( node ) { CHAIN_INITIALIZER_ONE_NODE( node ), ISR_LOCK_INITIALIZER }
/** /**
* @brief Chain node initializer for a @a chain containing exactly this node. * @brief Chain node initializer for a @a chain containing exactly this node.
@@ -58,13 +62,13 @@ typedef Chain_Control rtems_chain_control;
* @see RTEMS_CHAIN_INITIALIZER_ONE_NODE(). * @see RTEMS_CHAIN_INITIALIZER_ONE_NODE().
*/ */
#define RTEMS_CHAIN_NODE_INITIALIZER_ONE_NODE_CHAIN( chain ) \ #define RTEMS_CHAIN_NODE_INITIALIZER_ONE_NODE_CHAIN( chain ) \
CHAIN_NODE_INITIALIZER_ONE_NODE_CHAIN( chain ) CHAIN_NODE_INITIALIZER_ONE_NODE_CHAIN( &( chain )->Chain )
/** /**
* @brief Chain definition for an empty chain with designator @a name. * @brief Chain definition for an empty chain with designator @a name.
*/ */
#define RTEMS_CHAIN_DEFINE_EMPTY(name) \ #define RTEMS_CHAIN_DEFINE_EMPTY( name ) \
CHAIN_DEFINE_EMPTY(name) rtems_chain_control name = RTEMS_CHAIN_INITIALIZER_EMPTY( name )
/** /**
* @brief Appends the @a node to the @a chain and sends the @a events to the * @brief Appends the @a node to the @a chain and sends the @a events to the
@@ -150,7 +154,13 @@ RTEMS_INLINE_ROUTINE void rtems_chain_initialize(
size_t node_size size_t node_size
) )
{ {
_Chain_Initialize( the_chain, starting_address, number_nodes, node_size ); _ISR_lock_Initialize( &the_chain->Lock );
_Chain_Initialize(
&the_chain->Chain,
starting_address,
number_nodes,
node_size
);
} }
/** /**
@@ -164,7 +174,8 @@ RTEMS_INLINE_ROUTINE void rtems_chain_initialize_empty(
rtems_chain_control *the_chain rtems_chain_control *the_chain
) )
{ {
_Chain_Initialize_empty( the_chain ); _ISR_lock_Initialize( &the_chain->Lock );
_Chain_Initialize_empty( &the_chain->Chain );
} }
/** /**
@@ -230,7 +241,7 @@ RTEMS_INLINE_ROUTINE rtems_chain_node *rtems_chain_head(
rtems_chain_control *the_chain rtems_chain_control *the_chain
) )
{ {
return _Chain_Head( the_chain ); return _Chain_Head( &the_chain->Chain );
} }
/** /**
@@ -246,7 +257,7 @@ RTEMS_INLINE_ROUTINE const rtems_chain_node *rtems_chain_immutable_head(
const rtems_chain_control *the_chain const rtems_chain_control *the_chain
) )
{ {
return _Chain_Immutable_head( the_chain ); return _Chain_Immutable_head( &the_chain->Chain );
} }
/** /**
@@ -262,7 +273,7 @@ RTEMS_INLINE_ROUTINE rtems_chain_node *rtems_chain_tail(
rtems_chain_control *the_chain rtems_chain_control *the_chain
) )
{ {
return _Chain_Tail( the_chain ); return _Chain_Tail( &the_chain->Chain );
} }
/** /**
@@ -278,7 +289,7 @@ RTEMS_INLINE_ROUTINE const rtems_chain_node *rtems_chain_immutable_tail(
const rtems_chain_control *the_chain const rtems_chain_control *the_chain
) )
{ {
return _Chain_Immutable_tail( the_chain ); return _Chain_Immutable_tail( &the_chain->Chain );
} }
/** /**
@@ -295,7 +306,7 @@ RTEMS_INLINE_ROUTINE rtems_chain_node *rtems_chain_first(
rtems_chain_control *the_chain rtems_chain_control *the_chain
) )
{ {
return _Chain_First( the_chain ); return _Chain_First( &the_chain->Chain );
} }
/** /**
@@ -312,7 +323,7 @@ RTEMS_INLINE_ROUTINE const rtems_chain_node *rtems_chain_immutable_first(
const rtems_chain_control *the_chain const rtems_chain_control *the_chain
) )
{ {
return _Chain_Immutable_first( the_chain ); return _Chain_Immutable_first( &the_chain->Chain );
} }
/** /**
@@ -329,7 +340,7 @@ RTEMS_INLINE_ROUTINE rtems_chain_node *rtems_chain_last(
rtems_chain_control *the_chain rtems_chain_control *the_chain
) )
{ {
return _Chain_Last( the_chain ); return _Chain_Last( &the_chain->Chain );
} }
/** /**
@@ -346,7 +357,7 @@ RTEMS_INLINE_ROUTINE const rtems_chain_node *rtems_chain_immutable_last(
const rtems_chain_control *the_chain const rtems_chain_control *the_chain
) )
{ {
return _Chain_Immutable_last( the_chain ); return _Chain_Immutable_last( &the_chain->Chain );
} }
/** /**
@@ -448,7 +459,7 @@ RTEMS_INLINE_ROUTINE bool rtems_chain_is_empty(
const rtems_chain_control *the_chain const rtems_chain_control *the_chain
) )
{ {
return _Chain_Is_empty( the_chain ); return _Chain_Is_empty( &the_chain->Chain );
} }
/** /**
@@ -503,7 +514,7 @@ RTEMS_INLINE_ROUTINE bool rtems_chain_has_only_one_node(
const rtems_chain_control *the_chain const rtems_chain_control *the_chain
) )
{ {
return _Chain_Has_only_one_node( the_chain ); return _Chain_Has_only_one_node( &the_chain->Chain );
} }
/** /**
@@ -523,7 +534,7 @@ RTEMS_INLINE_ROUTINE bool rtems_chain_is_head(
const rtems_chain_node *the_node const rtems_chain_node *the_node
) )
{ {
return _Chain_Is_head( the_chain, the_node ); return _Chain_Is_head( &the_chain->Chain, the_node );
} }
/** /**
@@ -543,9 +554,10 @@ RTEMS_INLINE_ROUTINE bool rtems_chain_is_tail(
const rtems_chain_node *the_node const rtems_chain_node *the_node
) )
{ {
return _Chain_Is_tail( the_chain, the_node ); return _Chain_Is_tail( &the_chain->Chain, the_node );
} }
#if !defined( RTEMS_SMP )
/** /**
* @brief Extract the specified node from a chain. * @brief Extract the specified node from a chain.
* *
@@ -561,6 +573,29 @@ RTEMS_INLINE_ROUTINE void rtems_chain_extract(
{ {
_Chain_Extract( the_node ); _Chain_Extract( the_node );
} }
#endif
#if defined( RTEMS_SMP )
/**
* @brief Extract the specified node from a chain.
*
* @param[in,out] chain The chain containing the node.
* @param[in,out] node The node to extract.
*/
void rtems_chain_explicit_extract(
rtems_chain_control *chain,
rtems_chain_node *node
);
#else
RTEMS_INLINE_ROUTINE void rtems_chain_explicit_extract(
rtems_chain_control *chain,
rtems_chain_node *node
)
{
( void ) chain;
rtems_chain_extract( node );
}
#endif
/** /**
* @brief Extract the specified node from a chain (unprotected). * @brief Extract the specified node from a chain (unprotected).
@@ -589,12 +624,18 @@ RTEMS_INLINE_ROUTINE void rtems_chain_extract_unprotected(
* *
* NOTE: It disables interrupts to ensure the atomicity of the get operation. * NOTE: It disables interrupts to ensure the atomicity of the get operation.
*/ */
#if defined( RTEMS_SMP )
rtems_chain_node *rtems_chain_get(
rtems_chain_control *the_chain
);
#else
RTEMS_INLINE_ROUTINE rtems_chain_node *rtems_chain_get( RTEMS_INLINE_ROUTINE rtems_chain_node *rtems_chain_get(
rtems_chain_control *the_chain rtems_chain_control *the_chain
) )
{ {
return _Chain_Get( the_chain ); return _Chain_Get( &the_chain->Chain );
} }
#endif
/** /**
* @brief See _Chain_Get_unprotected(). * @brief See _Chain_Get_unprotected().
@@ -603,9 +644,10 @@ RTEMS_INLINE_ROUTINE rtems_chain_node *rtems_chain_get_unprotected(
rtems_chain_control *the_chain rtems_chain_control *the_chain
) )
{ {
return _Chain_Get_unprotected( the_chain ); return _Chain_Get_unprotected( &the_chain->Chain );
} }
#if !defined( RTEMS_SMP )
/** /**
* @brief Insert a node on a chain * @brief Insert a node on a chain
* *
@@ -622,6 +664,32 @@ RTEMS_INLINE_ROUTINE void rtems_chain_insert(
{ {
_Chain_Insert( after_node, the_node ); _Chain_Insert( after_node, the_node );
} }
#endif
/**
* @brief Insert a node on a chain
*
* @param[in,out] chain The chain containing the after node.
* @param[in,out] after_node Insert the node after this node.
* @param[in,out] node The node to insert.
*/
#if defined( RTEMS_SMP )
void rtems_chain_explicit_insert(
rtems_chain_control *chain,
rtems_chain_node *after_node,
rtems_chain_node *node
);
#else
RTEMS_INLINE_ROUTINE void rtems_chain_explicit_insert(
rtems_chain_control *chain,
rtems_chain_node *after_node,
rtems_chain_node *node
)
{
( void ) chain;
rtems_chain_insert( after_node, node );
}
#endif
/** /**
* @brief See _Chain_Insert_unprotected(). * @brief See _Chain_Insert_unprotected().
@@ -642,13 +710,20 @@ RTEMS_INLINE_ROUTINE void rtems_chain_insert_unprotected(
* NOTE: It disables interrupts to ensure the atomicity of the * NOTE: It disables interrupts to ensure the atomicity of the
* append operation. * append operation.
*/ */
#if defined( RTEMS_SMP )
void rtems_chain_append(
rtems_chain_control *the_chain,
rtems_chain_node *the_node
);
#else
RTEMS_INLINE_ROUTINE void rtems_chain_append( RTEMS_INLINE_ROUTINE void rtems_chain_append(
rtems_chain_control *the_chain, rtems_chain_control *the_chain,
rtems_chain_node *the_node rtems_chain_node *the_node
) )
{ {
_Chain_Append( the_chain, the_node ); _Chain_Append( &the_chain->Chain, the_node );
} }
#endif
/** /**
* @brief Append a node on the end of a chain (unprotected). * @brief Append a node on the end of a chain (unprotected).
@@ -663,7 +738,7 @@ RTEMS_INLINE_ROUTINE void rtems_chain_append_unprotected(
rtems_chain_node *the_node rtems_chain_node *the_node
) )
{ {
_Chain_Append_unprotected( the_chain, the_node ); _Chain_Append_unprotected( &the_chain->Chain, the_node );
} }
/** /**
@@ -677,13 +752,20 @@ RTEMS_INLINE_ROUTINE void rtems_chain_append_unprotected(
* NOTE: It disables interrupts to ensure the atomicity of the * NOTE: It disables interrupts to ensure the atomicity of the
* prepend operation. * prepend operation.
*/ */
#if defined( RTEMS_SMP )
void rtems_chain_prepend(
rtems_chain_control *the_chain,
rtems_chain_node *the_node
);
#else
RTEMS_INLINE_ROUTINE void rtems_chain_prepend( RTEMS_INLINE_ROUTINE void rtems_chain_prepend(
rtems_chain_control *the_chain, rtems_chain_control *the_chain,
rtems_chain_node *the_node rtems_chain_node *the_node
) )
{ {
_Chain_Prepend( the_chain, the_node ); _Chain_Prepend( &the_chain->Chain, the_node );
} }
#endif
/** /**
* @brief Prepend a node (unprotected). * @brief Prepend a node (unprotected).
@@ -701,7 +783,7 @@ RTEMS_INLINE_ROUTINE void rtems_chain_prepend_unprotected(
rtems_chain_node *the_node rtems_chain_node *the_node
) )
{ {
_Chain_Prepend_unprotected( the_chain, the_node ); _Chain_Prepend_unprotected( &the_chain->Chain, the_node );
} }
/** /**
@@ -712,13 +794,20 @@ RTEMS_INLINE_ROUTINE void rtems_chain_prepend_unprotected(
* @retval true The chain was empty before the append. * @retval true The chain was empty before the append.
* @retval false The chain contained at least one node before the append. * @retval false The chain contained at least one node before the append.
*/ */
#if defined( RTEMS_SMP )
bool rtems_chain_append_with_empty_check(
rtems_chain_control *chain,
rtems_chain_node *node
);
#else
RTEMS_INLINE_ROUTINE bool rtems_chain_append_with_empty_check( RTEMS_INLINE_ROUTINE bool rtems_chain_append_with_empty_check(
rtems_chain_control *chain, rtems_chain_control *chain,
rtems_chain_node *node rtems_chain_node *node
) )
{ {
return _Chain_Append_with_empty_check( chain, node ); return _Chain_Append_with_empty_check( &chain->Chain, node );
} }
#endif
/** /**
* @brief Checks if the @a chain is empty and prepends the @a node. * @brief Checks if the @a chain is empty and prepends the @a node.
@@ -728,13 +817,20 @@ RTEMS_INLINE_ROUTINE bool rtems_chain_append_with_empty_check(
* @retval true The chain was empty before the prepend. * @retval true The chain was empty before the prepend.
* @retval false The chain contained at least one node before the prepend. * @retval false The chain contained at least one node before the prepend.
*/ */
#if defined( RTEMS_SMP )
bool rtems_chain_prepend_with_empty_check(
rtems_chain_control *chain,
rtems_chain_node *node
);
#else
RTEMS_INLINE_ROUTINE bool rtems_chain_prepend_with_empty_check( RTEMS_INLINE_ROUTINE bool rtems_chain_prepend_with_empty_check(
rtems_chain_control *chain, rtems_chain_control *chain,
rtems_chain_node *node rtems_chain_node *node
) )
{ {
return _Chain_Prepend_with_empty_check( chain, node ); return _Chain_Prepend_with_empty_check( &chain->Chain, node );
} }
#endif
/** /**
* @brief Tries to get the first @a node and check if the @a chain is empty * @brief Tries to get the first @a node and check if the @a chain is empty
@@ -748,13 +844,20 @@ RTEMS_INLINE_ROUTINE bool rtems_chain_prepend_with_empty_check(
* @retval true The chain is empty after the node removal. * @retval true The chain is empty after the node removal.
* @retval false The chain contained at least one node after the node removal. * @retval false The chain contained at least one node after the node removal.
*/ */
#if defined( RTEMS_SMP )
bool rtems_chain_get_with_empty_check(
rtems_chain_control *chain,
rtems_chain_node **node
);
#else
RTEMS_INLINE_ROUTINE bool rtems_chain_get_with_empty_check( RTEMS_INLINE_ROUTINE bool rtems_chain_get_with_empty_check(
rtems_chain_control *chain, rtems_chain_control *chain,
rtems_chain_node **node rtems_chain_node **node
) )
{ {
return _Chain_Get_with_empty_check( chain, node ); return _Chain_Get_with_empty_check( &chain->Chain, node );
} }
#endif
/** /**
* @brief Returns the node count of the chain. * @brief Returns the node count of the chain.
@@ -770,7 +873,7 @@ RTEMS_INLINE_ROUTINE size_t rtems_chain_node_count_unprotected(
const rtems_chain_control *chain const rtems_chain_control *chain
) )
{ {
return _Chain_Node_count_unprotected( chain ); return _Chain_Node_count_unprotected( &chain->Chain );
} }
/** @} */ /** @} */

138
cpukit/sapi/src/chainsmp.c Normal file
View File

@@ -0,0 +1,138 @@
/*
* Copyright (c) 2013 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.com/license/LICENSE.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <rtems/chain.h>
#if defined( RTEMS_SMP )
void rtems_chain_explicit_extract(
rtems_chain_control *chain,
rtems_chain_node *node
)
{
ISR_Level level;
_ISR_lock_ISR_disable_and_acquire( &chain->Lock, level );
_Chain_Extract_unprotected( node );
_ISR_lock_Release_and_ISR_enable( &chain->Lock, level );
}
rtems_chain_node *rtems_chain_get( rtems_chain_control *chain )
{
rtems_chain_node *node;
ISR_Level level;
_ISR_lock_ISR_disable_and_acquire( &chain->Lock, level );
node = _Chain_Get_unprotected( &chain->Chain );
_ISR_lock_Release_and_ISR_enable( &chain->Lock, level );
return node;
}
void rtems_chain_explicit_insert(
rtems_chain_control *chain,
rtems_chain_node *after_node,
rtems_chain_node *node
)
{
ISR_Level level;
_ISR_lock_ISR_disable_and_acquire( &chain->Lock, level );
_Chain_Insert_unprotected( after_node, node );
_ISR_lock_Release_and_ISR_enable( &chain->Lock, level );
}
void rtems_chain_append(
rtems_chain_control *chain,
rtems_chain_node *node
)
{
ISR_Level level;
_ISR_lock_ISR_disable_and_acquire( &chain->Lock, level );
_Chain_Append_unprotected( &chain->Chain, node );
_ISR_lock_Release_and_ISR_enable( &chain->Lock, level );
}
void rtems_chain_prepend(
rtems_chain_control *chain,
rtems_chain_node *node
)
{
ISR_Level level;
_ISR_lock_ISR_disable_and_acquire( &chain->Lock, level );
_Chain_Prepend_unprotected( &chain->Chain, node );
_ISR_lock_Release_and_ISR_enable( &chain->Lock, level );
}
bool rtems_chain_append_with_empty_check(
rtems_chain_control *chain,
rtems_chain_node *node
)
{
bool was_empty;
ISR_Level level;
_ISR_lock_ISR_disable_and_acquire( &chain->Lock, level );
was_empty = _Chain_Append_with_empty_check_unprotected(
&chain->Chain,
node
);
_ISR_lock_Release_and_ISR_enable( &chain->Lock, level );
return was_empty;
}
bool rtems_chain_prepend_with_empty_check(
rtems_chain_control *chain,
rtems_chain_node *node
)
{
bool was_empty;
ISR_Level level;
_ISR_lock_ISR_disable_and_acquire( &chain->Lock, level );
was_empty = _Chain_Prepend_with_empty_check_unprotected(
&chain->Chain,
node
);
_ISR_lock_Release_and_ISR_enable( &chain->Lock, level );
return was_empty;
}
bool rtems_chain_get_with_empty_check(
rtems_chain_control *chain,
rtems_chain_node **node
)
{
bool is_empty_now;
ISR_Level level;
_ISR_lock_ISR_disable_and_acquire( &chain->Lock, level );
is_empty_now = _Chain_Get_with_empty_check_unprotected(
&chain->Chain,
node
);
_ISR_lock_Release_and_ISR_enable( &chain->Lock, level );
return is_empty_now;
}
#endif /* defined( RTEMS_SMP ) */

View File

@@ -1130,14 +1130,14 @@ bdbuf_tests_task_0_test_8 (bdbuf_task_control* tc)
bd = (rtems_bdbuf_buffer*) node; bd = (rtems_bdbuf_buffer*) node;
pnode = node->previous; pnode = node->previous;
rtems_chain_extract (node); rtems_chain_explicit_extract (&buffers, node);
node = pnode; node = pnode;
bdbuf_test_printf ("%s: rtems_bdbuf_release_modified[4]: ", tc->name); bdbuf_test_printf ("%s: rtems_bdbuf_release_modified[4]: ", tc->name);
passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd), true); passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd), true);
bd = (rtems_bdbuf_buffer*) node; bd = (rtems_bdbuf_buffer*) node;
pnode = node->previous; pnode = node->previous;
rtems_chain_extract (node); rtems_chain_explicit_extract (&buffers, node);
node = pnode; node = pnode;
bdbuf_test_printf ("%s: rtems_bdbuf_release_modified[3]: ", tc->name); bdbuf_test_printf ("%s: rtems_bdbuf_release_modified[3]: ", tc->name);
passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd), true); passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd), true);

View File

@@ -60,17 +60,29 @@ static void test_chain_control_initializer(void)
static void test_chain_control_layout(void) static void test_chain_control_layout(void)
{ {
rtems_chain_control chain; Chain_Control chain;
puts( "INIT - Verify rtems_chain_control layout" ); puts( "INIT - Verify rtems_chain_control layout" );
rtems_test_assert( rtems_test_assert(
sizeof(rtems_chain_control) sizeof(Chain_Control)
== sizeof(rtems_chain_node) + sizeof(rtems_chain_node *) == sizeof(Chain_Node) + sizeof(Chain_Node *)
); );
rtems_test_assert( rtems_test_assert(
sizeof(rtems_chain_control) sizeof(Chain_Control)
== 3 * sizeof(rtems_chain_node *) == 3 * sizeof(Chain_Node *)
); );
rtems_test_assert( &chain.Head.Node.previous == &chain.Tail.Node.next ); rtems_test_assert(
_Chain_Previous( _Chain_Head( &chain ) )
== _Chain_Next( _Chain_Tail( &chain ) )
);
#if !defined( RTEMS_SMP )
rtems_test_assert(
sizeof(Chain_Control)
== sizeof(rtems_chain_control)
);
#endif
} }
static void test_chain_get_with_wait(void) static void test_chain_get_with_wait(void)
@@ -94,7 +106,7 @@ static void test_chain_first_and_last(void)
rtems_chain_initialize_empty( &chain ); rtems_chain_initialize_empty( &chain );
rtems_chain_append( &chain, &node1 ); rtems_chain_append( &chain, &node1 );
rtems_chain_insert( &node1, &node2 ); rtems_chain_explicit_insert( &chain, &node1, &node2 );
puts( "INIT - Verify rtems_chain_is_first" ); puts( "INIT - Verify rtems_chain_is_first" );
cnode = rtems_chain_first(&chain); cnode = rtems_chain_first(&chain);
@@ -296,7 +308,7 @@ rtems_task Init(
node1.id = 1; node1.id = 1;
node2.id = 2; node2.id = 2;
rtems_chain_append( &chain1, &node1.Node ); rtems_chain_append( &chain1, &node1.Node );
rtems_chain_insert( &node1.Node, &node2.Node ); rtems_chain_explicit_insert( &chain1, &node1.Node, &node2.Node );
for ( p = rtems_chain_first(&chain1), id = 1 ; for ( p = rtems_chain_first(&chain1), id = 1 ;
!rtems_chain_is_tail(&chain1, p) ; !rtems_chain_is_tail(&chain1, p) ;