From 218844422978cf19cde8dc9e91d7b2c03b4cf2bf Mon Sep 17 00:00:00 2001 From: George Bosilca Date: Mon, 23 Jan 2006 18:20:53 +0000 Subject: [PATCH] Add support for lock-free "Last In First Out" lists and add them to the build. This commit was SVN r8788. --- opal/class/Makefile.am | 2 + opal/class/opal_atomic_lifo.c | 36 ++++++++++++ opal/class/opal_atomic_lifo.h | 102 ++++++++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+) create mode 100644 opal/class/opal_atomic_lifo.c create mode 100644 opal/class/opal_atomic_lifo.h diff --git a/opal/class/Makefile.am b/opal/class/Makefile.am index 54510ac1ae..afe668eac5 100644 --- a/opal/class/Makefile.am +++ b/opal/class/Makefile.am @@ -25,6 +25,7 @@ headers += \ class/opal_hash_table.h \ class/opal_list.h \ class/opal_object.h \ + class/opal_atomic_lifo.h \ class/opal_value_array.h libopal_la_SOURCES += \ @@ -32,4 +33,5 @@ libopal_la_SOURCES += \ class/opal_hash_table.c \ class/opal_list.c \ class/opal_object.c \ + class/opal_atomic_lifo.c \ class/opal_value_array.c diff --git a/opal/class/opal_atomic_lifo.c b/opal/class/opal_atomic_lifo.c new file mode 100644 index 0000000000..d53467f9d7 --- /dev/null +++ b/opal/class/opal_atomic_lifo.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana + * University Research and Technology + * Corporation. All rights reserved. + * Copyright (c) 2004-2005 The University of Tennessee and The University + * 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. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#include "ompi_config.h" +#include "opal/class/opal_atomic_lifo.h" + +static void opal_atomic_lifo_construct( opal_atomic_lifo_t* lifo ) +{ + lifo->opal_lifo_head = &(lifo->opal_lifo_ghost); + OBJ_CONSTRUCT( &(lifo->opal_lifo_ghost), opal_list_item_t ); + lifo->opal_lifo_ghost.opal_list_next = &(lifo->opal_lifo_ghost); +} + +static void opal_atomic_lifo_destruct( opal_atomic_lifo_t* lifo ) +{ +} + +OBJ_CLASS_INSTANCE( opal_atomic_lifo_t, + opal_object_t, + opal_atomic_lifo_construct, + opal_atomic_lifo_destruct ); diff --git a/opal/class/opal_atomic_lifo.h b/opal/class/opal_atomic_lifo.h new file mode 100644 index 0000000000..6158672b22 --- /dev/null +++ b/opal/class/opal_atomic_lifo.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana + * University Research and Technology + * Corporation. All rights reserved. + * Copyright (c) 2004-2005 The University of Tennessee and The University + * 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. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#ifndef OPAL_ATOMIC_LIFO_H_HAS_BEEN_INCLUDED +#define OPAL_ATOMIC_LIFO_H_HAS_BEEN_INCLUDED + +#include "ompi_config.h" +#include "opal/class/opal_list.h" +#include "opal/include/sys/atomic.h" + +/* Atomic Last In First Out lists. If we are in a multi-threaded environment then the + * 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; + +OMPI_DECLSPEC OBJ_CLASS_DECLARATION(opal_atomic_lifo_t); + +/* 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); +} + +/* 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 ) +{ +#if OMPI_HAVE_THREAD_SUPPORT + do { + item->opal_list_next = lifo->opal_lifo_head; + if( opal_atomic_cmpset_ptr( &(lifo->opal_lifo_head), + (void*)item->opal_list_next, + item ) ) + return (opal_list_item_t*)item->opal_list_next; + /* 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; +#endif /* OMPI_HAVE_THREAD_SUPPORT */ +} + +/* 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; +#if OMPI_HAVE_THREAD_SUPPORT + do { + item = lifo->opal_lifo_head; + if( opal_atomic_cmpset_ptr( &(lifo->opal_lifo_head), + item, + (void*)item->opal_list_next ) ) + break; + /* Do some kind of pause to release the bus */ + } while( 1 ); +#else + item = lifo->opal_lifo_head; +#endif /* OMPI_HAVE_THREAD_SUPPORT */ + if( item == &(lifo->opal_lifo_ghost) ) return NULL; + item->opal_list_next = NULL; + return item; +} + +#endif /* OPAL_ATOMIC_LIFO_H_HAS_BEEN_INCLUDED */ +