2006-01-23 21:20:53 +03:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
|
|
|
|
* University Research and Technology
|
|
|
|
* Corporation. All rights reserved.
|
2007-08-04 04:43:15 +04:00
|
|
|
* Copyright (c) 2004-2007 The University of Tennessee and The University
|
2006-01-23 21:20:53 +03:00
|
|
|
* of Tennessee Research Foundation. All rights
|
|
|
|
* reserved.
|
|
|
|
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
|
|
|
* University of Stuttgart. All rights reserved.
|
|
|
|
* Copyright (c) 2004-2005 The Regents of the University of California.
|
|
|
|
* All rights reserved.
|
2007-09-11 19:40:30 +04:00
|
|
|
* Copyright (c) 2007 Voltaire All rights reserved.
|
2010-03-25 06:44:38 +03:00
|
|
|
* Copyright (c) 2010 IBM Corporation. All rights reserved.
|
2006-01-23 21:20:53 +03:00
|
|
|
* $COPYRIGHT$
|
|
|
|
*
|
|
|
|
* Additional copyrights may follow
|
|
|
|
*
|
|
|
|
* $HEADER$
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef OPAL_ATOMIC_LIFO_H_HAS_BEEN_INCLUDED
|
|
|
|
#define OPAL_ATOMIC_LIFO_H_HAS_BEEN_INCLUDED
|
|
|
|
|
2006-02-12 04:33:29 +03:00
|
|
|
#include "opal_config.h"
|
2006-01-23 21:20:53 +03:00
|
|
|
#include "opal/class/opal_list.h"
|
2007-08-04 04:43:15 +04:00
|
|
|
|
2011-03-19 00:36:35 +03:00
|
|
|
#if OPAL_ENABLE_MULTI_THREADS
|
2006-02-12 04:33:29 +03:00
|
|
|
#include "opal/sys/atomic.h"
|
2011-03-19 00:36:35 +03:00
|
|
|
#endif /* OPAL_ENABLE_MULTI_THREADS */
|
2006-01-23 21:20:53 +03:00
|
|
|
|
2009-03-17 18:11:48 +03:00
|
|
|
BEGIN_C_DECLS
|
2006-08-23 04:29:35 +04:00
|
|
|
|
2009-03-17 18:11:48 +03:00
|
|
|
/* Atomic Last In First Out lists. If we are in a multi-threaded environment then the
|
2006-01-23 21:20:53 +03:00
|
|
|
* atomicity is insured via the compare-and-swap operation, if not we simply do a read
|
|
|
|
* and/or a write.
|
|
|
|
*
|
|
|
|
* There is a trick. The ghost element at the end of the list. This ghost element has
|
|
|
|
* the next pointer pointing to itself, therefore we cannot go past the end of the list.
|
|
|
|
* With this approach we will never have a NULL element in the list, so we never have
|
|
|
|
* to test for the NULL.
|
|
|
|
*/
|
|
|
|
struct opal_atomic_lifo_t
|
|
|
|
{
|
|
|
|
opal_object_t super;
|
|
|
|
opal_list_item_t* opal_lifo_head;
|
|
|
|
opal_list_item_t opal_lifo_ghost;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct opal_atomic_lifo_t opal_atomic_lifo_t;
|
|
|
|
|
2006-08-20 19:54:04 +04:00
|
|
|
OPAL_DECLSPEC OBJ_CLASS_DECLARATION(opal_atomic_lifo_t);
|
2006-01-23 21:20:53 +03:00
|
|
|
|
2009-03-17 18:11:48 +03:00
|
|
|
|
2006-01-23 21:20:53 +03:00
|
|
|
/* The ghost pointer will never change. The head will change via an atomic
|
|
|
|
* compare-and-swap. On most architectures the reading of a pointer is an
|
|
|
|
* atomic operation so we don't have to protect it.
|
|
|
|
*/
|
|
|
|
static inline bool opal_atomic_lifo_is_empty( opal_atomic_lifo_t* lifo )
|
|
|
|
{
|
|
|
|
return (lifo->opal_lifo_head == &(lifo->opal_lifo_ghost) ? true : false);
|
|
|
|
}
|
|
|
|
|
2009-03-17 18:11:48 +03:00
|
|
|
|
2006-01-23 21:20:53 +03:00
|
|
|
/* Add one element to the LIFO. We will return the last head of the list
|
|
|
|
* to allow the upper level to detect if this element is the first one in the
|
|
|
|
* list (if the list was empty before this operation).
|
|
|
|
*/
|
|
|
|
static inline opal_list_item_t* opal_atomic_lifo_push( opal_atomic_lifo_t* lifo,
|
|
|
|
opal_list_item_t* item )
|
|
|
|
{
|
2011-03-19 00:36:35 +03:00
|
|
|
#if OPAL_ENABLE_MULTI_THREADS
|
2006-01-23 21:20:53 +03:00
|
|
|
do {
|
|
|
|
item->opal_list_next = lifo->opal_lifo_head;
|
2010-12-03 22:13:57 +03:00
|
|
|
opal_atomic_wmb();
|
2006-01-23 21:20:53 +03:00
|
|
|
if( opal_atomic_cmpset_ptr( &(lifo->opal_lifo_head),
|
|
|
|
(void*)item->opal_list_next,
|
2007-09-11 19:40:30 +04:00
|
|
|
item ) ) {
|
|
|
|
opal_atomic_cmpset_32((volatile int32_t*)&item->item_free, 1, 0);
|
2006-01-23 21:20:53 +03:00
|
|
|
return (opal_list_item_t*)item->opal_list_next;
|
2007-09-11 19:40:30 +04:00
|
|
|
}
|
2006-01-23 21:20:53 +03:00
|
|
|
/* DO some kind of pause to release the bus */
|
|
|
|
} while( 1 );
|
|
|
|
#else
|
|
|
|
item->opal_list_next = lifo->opal_lifo_head;
|
|
|
|
lifo->opal_lifo_head = item;
|
|
|
|
return (opal_list_item_t*)item->opal_list_next;
|
2011-03-19 00:36:35 +03:00
|
|
|
#endif /* OPAL_ENABLE_MULTI_THREADS */
|
2006-01-23 21:20:53 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Retrieve one element from the LIFO. If we reach the ghost element then the LIFO
|
|
|
|
* is empty so we return NULL.
|
|
|
|
*/
|
|
|
|
static inline opal_list_item_t* opal_atomic_lifo_pop( opal_atomic_lifo_t* lifo )
|
|
|
|
{
|
|
|
|
opal_list_item_t* item;
|
2011-03-19 00:36:35 +03:00
|
|
|
#if OPAL_ENABLE_MULTI_THREADS
|
2007-09-11 19:40:30 +04:00
|
|
|
while((item = lifo->opal_lifo_head) != &(lifo->opal_lifo_ghost))
|
|
|
|
{
|
2010-12-03 22:13:57 +03:00
|
|
|
opal_atomic_rmb();
|
2007-09-11 19:40:30 +04:00
|
|
|
if(!opal_atomic_cmpset_32((volatile int32_t*)&item->item_free, 0, 1))
|
|
|
|
continue;
|
2006-01-23 21:20:53 +03:00
|
|
|
if( opal_atomic_cmpset_ptr( &(lifo->opal_lifo_head),
|
|
|
|
item,
|
|
|
|
(void*)item->opal_list_next ) )
|
|
|
|
break;
|
2007-09-11 19:40:30 +04:00
|
|
|
opal_atomic_cmpset_32((volatile int32_t*)&item->item_free, 1, 0);
|
2006-01-23 21:20:53 +03:00
|
|
|
/* Do some kind of pause to release the bus */
|
2007-09-11 19:40:30 +04:00
|
|
|
}
|
2006-01-23 21:20:53 +03:00
|
|
|
#else
|
|
|
|
item = lifo->opal_lifo_head;
|
2006-01-23 22:41:39 +03:00
|
|
|
lifo->opal_lifo_head = (opal_list_item_t*)item->opal_list_next;
|
2011-03-19 00:36:35 +03:00
|
|
|
#endif /* OPAL_ENABLE_MULTI_THREADS */
|
2006-01-23 21:20:53 +03:00
|
|
|
if( item == &(lifo->opal_lifo_ghost) ) return NULL;
|
|
|
|
item->opal_list_next = NULL;
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
2009-03-17 18:11:48 +03:00
|
|
|
END_C_DECLS
|
2006-08-23 04:29:35 +04:00
|
|
|
|
2006-01-23 21:20:53 +03:00
|
|
|
#endif /* OPAL_ATOMIC_LIFO_H_HAS_BEEN_INCLUDED */
|
|
|
|
|