[PATCH] sapi: SMP support for chains

Sebastian Huber sebastian.huber at embedded-brains.de
Mon Aug 26 15:50:09 UTC 2013


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.
---
 c/src/lib/libcpu/powerpc/mpc55xx/edma/edma.c |    2 +-
 c/src/libchip/ide/ata.c                      |    2 +-
 cpukit/posix/src/aio_cancel.c                |   18 ++--
 cpukit/posix/src/aio_misc.c                  |   32 +++--
 cpukit/sapi/Makefile.am                      |    1 +
 cpukit/sapi/include/rtems/chain.h            |  164 +++++++++++++++++++++-----
 cpukit/sapi/src/chainsmp.c                   |  138 ++++++++++++++++++++++
 testsuites/libtests/block06/init.c           |    4 +-
 testsuites/sptests/spchain/init.c            |   28 +++--
 9 files changed, 325 insertions(+), 64 deletions(-)
 create mode 100644 cpukit/sapi/src/chainsmp.c

diff --git a/c/src/lib/libcpu/powerpc/mpc55xx/edma/edma.c b/c/src/lib/libcpu/powerpc/mpc55xx/edma/edma.c
index 7b9eab4..0856ad7 100644
--- a/c/src/lib/libcpu/powerpc/mpc55xx/edma/edma.c
+++ b/c/src/lib/libcpu/powerpc/mpc55xx/edma/edma.c
@@ -275,7 +275,7 @@ void mpc55xx_edma_release_channel(edma_channel_context *ctx)
   unsigned channel_index = edma_channel_index_of_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(
     MPC55XX_IRQ_EDMA(channel_index),
diff --git a/c/src/libchip/ide/ata.c b/c/src/libchip/ide/ata.c
index 8229714..64238b7 100644
--- a/c/src/libchip/ide/ata.c
+++ b/c/src/libchip/ide/ata.c
@@ -491,7 +491,7 @@ ata_request_done(ata_req_t *areq, rtems_device_minor_number ctrl_minor,
 #endif
 
     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))
     {
diff --git a/cpukit/posix/src/aio_cancel.c b/cpukit/posix/src/aio_cancel.c
index 561e2f8..aec554e 100644
--- a/cpukit/posix/src/aio_cancel.c
+++ b/cpukit/posix/src/aio_cancel.c
@@ -26,6 +26,8 @@
 
 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;
   int result;
   
@@ -40,12 +42,12 @@ int aio_cancel(int fildes, struct aiocb  *aiocbp)
   if (aiocbp == NULL) {
     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) {
       AIO_printf ("Request chain not on [WQ]\n");
 
-      if (!rtems_chain_is_empty (&aio_request_queue.idle_req)) {
-        r_chain = rtems_aio_search_fd (&aio_request_queue.idle_req, fildes, 0);
+      if (!rtems_chain_is_empty (idle_req_chain)) {
+        r_chain = rtems_aio_search_fd (idle_req_chain, fildes, 0);
         if (r_chain == NULL) {
           pthread_mutex_unlock(&aio_request_queue.mutex);
           return AIO_ALLDONE;
@@ -53,7 +55,7 @@ int aio_cancel(int fildes, struct aiocb  *aiocbp)
 
         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);
         pthread_mutex_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");
 
     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);
     pthread_mutex_unlock (&r_chain->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);
     }
       
-    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 (!rtems_chain_is_empty (&aio_request_queue.idle_req)) {
-        r_chain = rtems_aio_search_fd (&aio_request_queue.idle_req, fildes, 0);
+      if (!rtems_chain_is_empty (idle_req_chain)) {
+        r_chain = rtems_aio_search_fd (idle_req_chain, fildes, 0);
         if (r_chain == NULL) { 
           pthread_mutex_unlock (&aio_request_queue.mutex);
           rtems_set_errno_and_return_minus_one (EINVAL);
diff --git a/cpukit/posix/src/aio_misc.c b/cpukit/posix/src/aio_misc.c
index e4c40df..656ba41 100644
--- a/cpukit/posix/src/aio_misc.c
+++ b/cpukit/posix/src/aio_misc.c
@@ -120,7 +120,9 @@ rtems_aio_search_fd (rtems_chain_control *chain, int fildes, int create)
       if (rtems_chain_is_empty (chain))
         rtems_chain_prepend (chain, &r_chain->next_fd);
       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->fildes = fildes;
@@ -144,19 +146,22 @@ rtems_aio_search_fd (rtems_chain_control *chain, int fildes, int create)
 static void
 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_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;
 
-  while (temp->fildes < r_chain->fildes && 
-	 !rtems_chain_is_tail (&aio_request_queue.work_req, node)) {
+  while (temp->fildes < r_chain->fildes &&
+	 !rtems_chain_is_tail (work_req_chain, node)) {
     node = rtems_chain_next (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;
     }
 
-    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))
     {
-      rtems_chain_extract (node);
+      rtems_chain_explicit_extract (chain, node);
       rtems_aio_request *req = (rtems_aio_request *) node;
       node = rtems_chain_next (node);
       req->aiocbp->error_code = ECANCELED;
@@ -265,7 +270,7 @@ int rtems_aio_remove_req (rtems_chain_control *chain, struct aiocb *aiocbp)
     return AIO_NOTCANCELED;
   else
     {
-      rtems_chain_extract (node);
+      rtems_chain_explicit_extract (chain, node);
       current->aiocbp->error_code = ECANCELED;
       current->aiocbp->return_value = -1;
       free (current); 
@@ -440,7 +445,7 @@ rtems_aio_handle (void *arg)
       param.sched_priority = req->priority;
       pthread_setschedparam (pthread_self(), req->policy, &param);
 
-      rtems_chain_extract (node);
+      rtems_chain_explicit_extract (chain, node);
 
       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 
 	     the queue and start working with idle fd chains */
 	  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_cond_destroy (&r_chain->cond);
 	    free (r_chain);
@@ -542,7 +548,7 @@ rtems_aio_handle (void *arg)
 	    ++aio_request_queue.active_threads;
 
 	    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;
 	    rtems_aio_move_to_work (r_chain);
diff --git a/cpukit/sapi/Makefile.am b/cpukit/sapi/Makefile.am
index eaea591..2a88aa3 100644
--- a/cpukit/sapi/Makefile.am
+++ b/cpukit/sapi/Makefile.am
@@ -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/chainprependnotify.c src/rbheap.c src/interrdesc.c \
     src/fatal2.c src/fatalsrcdesc.c
+libsapi_a_SOURCES += src/chainsmp.c
 libsapi_a_CPPFLAGS = $(AM_CPPFLAGS)
 
 include $(srcdir)/preinstall.am
diff --git a/cpukit/sapi/include/rtems/chain.h b/cpukit/sapi/include/rtems/chain.h
index 7e48dc7..eae3a6d 100644
--- a/cpukit/sapi/include/rtems/chain.h
+++ b/cpukit/sapi/include/rtems/chain.h
@@ -36,13 +36,16 @@ extern "C" {
 
 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.
  */
-#define RTEMS_CHAIN_INITIALIZER_EMPTY(name) \
-  CHAIN_INITIALIZER_EMPTY(name)
+#define RTEMS_CHAIN_INITIALIZER_EMPTY( name ) \
+  { CHAIN_INITIALIZER_EMPTY( name.Chain ), ISR_LOCK_INITIALIZER }
 
 /**
  *  @brief Chain initializer for a chain with one @a node.
@@ -50,7 +53,7 @@ typedef Chain_Control rtems_chain_control;
  *  @see RTEMS_CHAIN_NODE_INITIALIZER_ONE_NODE_CHAIN().
  */
 #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.
@@ -58,13 +61,13 @@ typedef Chain_Control rtems_chain_control;
  *  @see RTEMS_CHAIN_INITIALIZER_ONE_NODE().
  */
 #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.
  */
-#define RTEMS_CHAIN_DEFINE_EMPTY(name) \
-  CHAIN_DEFINE_EMPTY(name)
+#define RTEMS_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
@@ -150,7 +153,13 @@ RTEMS_INLINE_ROUTINE void rtems_chain_initialize(
   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 +173,8 @@ RTEMS_INLINE_ROUTINE void rtems_chain_initialize_empty(
   rtems_chain_control *the_chain
 )
 {
-  _Chain_Initialize_empty( the_chain );
+  _ISR_lock_Initialize( &the_chain->Lock );
+  _Chain_Initialize_empty( &the_chain->Chain );
 }
 
 /**
@@ -230,7 +240,7 @@ RTEMS_INLINE_ROUTINE rtems_chain_node *rtems_chain_head(
   rtems_chain_control *the_chain
 )
 {
-  return _Chain_Head( the_chain );
+  return _Chain_Head( &the_chain->Chain );
 }
 
 /**
@@ -246,7 +256,7 @@ RTEMS_INLINE_ROUTINE const rtems_chain_node *rtems_chain_immutable_head(
   const rtems_chain_control *the_chain
 )
 {
-  return _Chain_Immutable_head( the_chain );
+  return _Chain_Immutable_head( &the_chain->Chain );
 }
 
 /**
@@ -262,7 +272,7 @@ RTEMS_INLINE_ROUTINE rtems_chain_node *rtems_chain_tail(
   rtems_chain_control *the_chain
 )
 {
-  return _Chain_Tail( the_chain );
+  return _Chain_Tail( &the_chain->Chain );
 }
 
 /** 
@@ -278,7 +288,7 @@ RTEMS_INLINE_ROUTINE const rtems_chain_node *rtems_chain_immutable_tail(
   const rtems_chain_control *the_chain
 )
 {
-  return _Chain_Immutable_tail( the_chain );
+  return _Chain_Immutable_tail( &the_chain->Chain );
 }
 
 /**
@@ -295,7 +305,7 @@ RTEMS_INLINE_ROUTINE rtems_chain_node *rtems_chain_first(
   rtems_chain_control *the_chain
 )
 {
-  return _Chain_First( the_chain );
+  return _Chain_First( &the_chain->Chain );
 }
 
 /** 
@@ -312,7 +322,7 @@ RTEMS_INLINE_ROUTINE const rtems_chain_node *rtems_chain_immutable_first(
   const rtems_chain_control *the_chain
 )
 {
-  return _Chain_Immutable_first( the_chain );
+  return _Chain_Immutable_first( &the_chain->Chain );
 }
 
 /**
@@ -329,7 +339,7 @@ RTEMS_INLINE_ROUTINE rtems_chain_node *rtems_chain_last(
   rtems_chain_control *the_chain
 )
 {
-  return _Chain_Last( the_chain );
+  return _Chain_Last( &the_chain->Chain );
 }
 
 /**
@@ -346,7 +356,7 @@ RTEMS_INLINE_ROUTINE const rtems_chain_node *rtems_chain_immutable_last(
   const rtems_chain_control *the_chain
 )
 {
-  return _Chain_Immutable_last( the_chain );
+  return _Chain_Immutable_last( &the_chain->Chain );
 }
 
 /**
@@ -448,7 +458,7 @@ RTEMS_INLINE_ROUTINE bool rtems_chain_is_empty(
   const rtems_chain_control *the_chain
 )
 {
-  return _Chain_Is_empty( the_chain );
+  return _Chain_Is_empty( &the_chain->Chain );
 }
 
 /**
@@ -503,7 +513,7 @@ RTEMS_INLINE_ROUTINE bool rtems_chain_has_only_one_node(
   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 +533,7 @@ RTEMS_INLINE_ROUTINE bool rtems_chain_is_head(
   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 +553,10 @@ RTEMS_INLINE_ROUTINE bool rtems_chain_is_tail(
   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.
  *
@@ -561,6 +572,29 @@ RTEMS_INLINE_ROUTINE void rtems_chain_extract(
 {
   _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).
@@ -589,12 +623,18 @@ RTEMS_INLINE_ROUTINE void rtems_chain_extract_unprotected(
  *
  *  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_chain_control *the_chain
 )
 {
-  return _Chain_Get( the_chain );
+  return _Chain_Get( &the_chain->Chain );
 }
+#endif
 
 /**
  * @brief See _Chain_Get_unprotected().
@@ -603,9 +643,10 @@ RTEMS_INLINE_ROUTINE rtems_chain_node *rtems_chain_get_unprotected(
   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
  *
@@ -622,6 +663,32 @@ RTEMS_INLINE_ROUTINE void rtems_chain_insert(
 {
   _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().
@@ -642,13 +709,20 @@ RTEMS_INLINE_ROUTINE void rtems_chain_insert_unprotected(
  * NOTE: It disables interrupts to ensure the atomicity of the
  * 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_chain_control *the_chain,
   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).
@@ -663,7 +737,7 @@ RTEMS_INLINE_ROUTINE void rtems_chain_append_unprotected(
   rtems_chain_node    *the_node
 )
 {
-  _Chain_Append_unprotected( the_chain, the_node );
+  _Chain_Append_unprotected( &the_chain->Chain, the_node );
 }
 
 /** 
@@ -677,13 +751,20 @@ RTEMS_INLINE_ROUTINE void rtems_chain_append_unprotected(
  * NOTE: It disables interrupts to ensure the atomicity of the
  *       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_chain_control *the_chain,
   rtems_chain_node    *the_node
 )
 {
-  _Chain_Prepend( the_chain, the_node );
+  _Chain_Prepend( &the_chain->Chain, the_node );
 }
+#endif
 
 /** 
  * @brief Prepend a node (unprotected).
@@ -701,7 +782,7 @@ RTEMS_INLINE_ROUTINE void rtems_chain_prepend_unprotected(
   rtems_chain_node    *the_node
 )
 {
-  _Chain_Prepend_unprotected( the_chain, the_node );
+  _Chain_Prepend_unprotected( &the_chain->Chain, the_node );
 }
 
 /**
@@ -712,13 +793,20 @@ RTEMS_INLINE_ROUTINE void rtems_chain_prepend_unprotected(
  * @retval true The chain was empty 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_chain_control *chain,
   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.
@@ -728,13 +816,20 @@ RTEMS_INLINE_ROUTINE bool rtems_chain_append_with_empty_check(
  * @retval true The chain was empty 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_chain_control *chain,
   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
@@ -748,13 +843,20 @@ RTEMS_INLINE_ROUTINE bool rtems_chain_prepend_with_empty_check(
  * @retval true The chain is empty 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_chain_control *chain,
   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.
@@ -770,7 +872,7 @@ RTEMS_INLINE_ROUTINE size_t rtems_chain_node_count_unprotected(
   const rtems_chain_control *chain
 )
 {
-  return _Chain_Node_count_unprotected( chain );
+  return _Chain_Node_count_unprotected( &chain->Chain );
 }
 
 /** @} */
diff --git a/cpukit/sapi/src/chainsmp.c b/cpukit/sapi/src/chainsmp.c
new file mode 100644
index 0000000..ea8de83
--- /dev/null
+++ b/cpukit/sapi/src/chainsmp.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2013 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems at 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 ) */
diff --git a/testsuites/libtests/block06/init.c b/testsuites/libtests/block06/init.c
index 6352aba..e51bf27 100644
--- a/testsuites/libtests/block06/init.c
+++ b/testsuites/libtests/block06/init.c
@@ -1130,14 +1130,14 @@ bdbuf_tests_task_0_test_8 (bdbuf_task_control* tc)
 
   bd = (rtems_bdbuf_buffer*) node;
   pnode = node->previous;
-  rtems_chain_extract (node);
+  rtems_chain_explicit_extract (&buffers, node);
   node = pnode;
   bdbuf_test_printf ("%s: rtems_bdbuf_release_modified[4]: ", tc->name);
   passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd), true);
 
   bd = (rtems_bdbuf_buffer*) node;
   pnode = node->previous;
-  rtems_chain_extract (node);
+  rtems_chain_explicit_extract (&buffers, node);
   node = pnode;
   bdbuf_test_printf ("%s: rtems_bdbuf_release_modified[3]: ", tc->name);
   passed = bdbuf_test_print_sc (rtems_bdbuf_release_modified (bd), true);
diff --git a/testsuites/sptests/spchain/init.c b/testsuites/sptests/spchain/init.c
index 219d0f3..747f404 100644
--- a/testsuites/sptests/spchain/init.c
+++ b/testsuites/sptests/spchain/init.c
@@ -60,17 +60,29 @@ static void test_chain_control_initializer(void)
 
 static void test_chain_control_layout(void)
 {
-  rtems_chain_control chain;
+  Chain_Control chain;
+
   puts( "INIT - Verify rtems_chain_control layout" );
+
+  rtems_test_assert(
+    sizeof(Chain_Control)
+      == sizeof(Chain_Node) + sizeof(Chain_Node *)
+  );
   rtems_test_assert(
-    sizeof(rtems_chain_control)
-      == sizeof(rtems_chain_node) + sizeof(rtems_chain_node *)
+    sizeof(Chain_Control)
+      == 3 * sizeof(Chain_Node *)
   );
   rtems_test_assert(
-    sizeof(rtems_chain_control)
-      == 3 * sizeof(rtems_chain_node *)
+    _Chain_Previous( _Chain_Head( &chain ) )
+      == _Chain_Next( _Chain_Tail( &chain ) )
   );
-  rtems_test_assert( &chain.Head.Node.previous == &chain.Tail.Node.next );
+
+#if !defined( RTEMS_SMP )
+  rtems_test_assert(
+    sizeof(Chain_Control)
+      == sizeof(rtems_chain_control)
+  );
+#endif
 }
 
 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_append( &chain, &node1 );
-  rtems_chain_insert( &node1, &node2 );
+  rtems_chain_explicit_insert( &chain, &node1, &node2 );
 
   puts( "INIT - Verify rtems_chain_is_first" );
   cnode = rtems_chain_first(&chain);  
@@ -296,7 +308,7 @@ rtems_task Init(
   node1.id = 1;
   node2.id = 2;
   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 ;
         !rtems_chain_is_tail(&chain1, p) ;
-- 
1.7.7




More information about the devel mailing list