1
1
openmpi/opal/class/opal_list.c
Nathan Hjelm 7893248c5a opal/asm: add fetch-and-op atomics
This commit adds support for fetch-and-op atomics. This is needed
because and and or are irreversible operations so there needs to be a
way to get the old value atomically. These are also the only semantics
supported by C11 (there is not atomic_op_fetch, just
atomic_fetch_op). The old op-and-fetch atomics have been defined in
terms of fetch-and-op.

Signed-off-by: Nathan Hjelm <hjelmn@lanl.gov>
2017-11-30 10:41:23 -07:00

259 строки
6.7 KiB
C

/*
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
* University Research and Technology
* Corporation. All rights reserved.
* Copyright (c) 2004-2014 The University of Tennessee and The University
* of Tennessee Research Foundation. All rights
* reserved.
* Copyright (c) 2004-2007 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 (c) 2007 Voltaire All rights reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#include "opal_config.h"
#include "opal/class/opal_list.h"
#include "opal/constants.h"
/*
* List classes
*/
static void opal_list_item_construct(opal_list_item_t*);
static void opal_list_item_destruct(opal_list_item_t*);
OBJ_CLASS_INSTANCE(
opal_list_item_t,
opal_object_t,
opal_list_item_construct,
opal_list_item_destruct
);
static void opal_list_construct(opal_list_t*);
static void opal_list_destruct(opal_list_t*);
OBJ_CLASS_INSTANCE(
opal_list_t,
opal_object_t,
opal_list_construct,
opal_list_destruct
);
/*
*
* opal_list_link_item_t interface
*
*/
static void opal_list_item_construct(opal_list_item_t *item)
{
item->opal_list_next = item->opal_list_prev = NULL;
item->item_free = 1;
#if OPAL_ENABLE_DEBUG
item->opal_list_item_refcount = 0;
item->opal_list_item_belong_to = NULL;
#endif
}
static void opal_list_item_destruct(opal_list_item_t *item)
{
#if OPAL_ENABLE_DEBUG
assert( 0 == item->opal_list_item_refcount );
assert( NULL == item->opal_list_item_belong_to );
#endif /* OPAL_ENABLE_DEBUG */
}
/*
*
* opal_list_list_t interface
*
*/
static void opal_list_construct(opal_list_t *list)
{
#if OPAL_ENABLE_DEBUG
/* These refcounts should never be used in assertions because they
should never be removed from this list, added to another list,
etc. So set them to sentinel values. */
OBJ_CONSTRUCT( &(list->opal_list_sentinel), opal_list_item_t );
list->opal_list_sentinel.opal_list_item_refcount = 1;
list->opal_list_sentinel.opal_list_item_belong_to = list;
#endif
list->opal_list_sentinel.opal_list_next = &list->opal_list_sentinel;
list->opal_list_sentinel.opal_list_prev = &list->opal_list_sentinel;
list->opal_list_length = 0;
}
/*
* Reset all the pointers to be NULL -- do not actually destroy
* anything.
*/
static void opal_list_destruct(opal_list_t *list)
{
opal_list_construct(list);
}
/*
* Insert an item at a specific place in a list
*/
bool opal_list_insert(opal_list_t *list, opal_list_item_t *item, long long idx)
{
/* Adds item to list at index and retains item. */
int i;
volatile opal_list_item_t *ptr, *next;
if ( idx >= (long long)list->opal_list_length ) {
return false;
}
if ( 0 == idx )
{
opal_list_prepend(list, item);
} else {
#if OPAL_ENABLE_DEBUG
/* Spot check: ensure that this item is previously on no
lists */
assert(0 == item->opal_list_item_refcount);
#endif
/* pointer to element 0 */
ptr = list->opal_list_sentinel.opal_list_next;
for ( i = 0; i < idx-1; i++ )
ptr = ptr->opal_list_next;
next = ptr->opal_list_next;
item->opal_list_next = next;
item->opal_list_prev = ptr;
next->opal_list_prev = item;
ptr->opal_list_next = item;
#if OPAL_ENABLE_DEBUG
/* Spot check: ensure this item is only on the list that we
just insertted it into */
opal_atomic_add ( &(item->opal_list_item_refcount), 1 );
assert(1 == item->opal_list_item_refcount);
item->opal_list_item_belong_to = list;
#endif
}
list->opal_list_length++;
return true;
}
static
void
opal_list_transfer(opal_list_item_t *pos, opal_list_item_t *begin,
opal_list_item_t *end)
{
volatile opal_list_item_t *tmp;
if (pos != end) {
/* remove [begin, end) */
end->opal_list_prev->opal_list_next = pos;
begin->opal_list_prev->opal_list_next = end;
pos->opal_list_prev->opal_list_next = begin;
/* splice into new position before pos */
tmp = pos->opal_list_prev;
pos->opal_list_prev = end->opal_list_prev;
end->opal_list_prev = begin->opal_list_prev;
begin->opal_list_prev = tmp;
#if OPAL_ENABLE_DEBUG
{
volatile opal_list_item_t* item = begin;
while( pos != item ) {
item->opal_list_item_belong_to = pos->opal_list_item_belong_to;
item = item->opal_list_next;
assert(NULL != item);
}
}
#endif /* OPAL_ENABLE_DEBUG */
}
}
void
opal_list_join(opal_list_t *thislist, opal_list_item_t *pos,
opal_list_t *xlist)
{
if (0 != opal_list_get_size(xlist)) {
opal_list_transfer(pos, opal_list_get_first(xlist),
opal_list_get_end(xlist));
/* fix the sizes */
thislist->opal_list_length += xlist->opal_list_length;
xlist->opal_list_length = 0;
}
}
void
opal_list_splice(opal_list_t *thislist, opal_list_item_t *pos,
opal_list_t *xlist, opal_list_item_t *first,
opal_list_item_t *last)
{
size_t change = 0;
opal_list_item_t *tmp;
if (first != last) {
/* figure out how many things we are going to move (have to do
* first, since last might be end and then we wouldn't be able
* to run the loop)
*/
for (tmp = first ; tmp != last ; tmp = opal_list_get_next(tmp)) {
change++;
}
opal_list_transfer(pos, first, last);
/* fix the sizes */
thislist->opal_list_length += change;
xlist->opal_list_length -= change;
}
}
int opal_list_sort(opal_list_t* list, opal_list_item_compare_fn_t compare)
{
opal_list_item_t* item;
opal_list_item_t** items;
size_t i, index=0;
if (0 == list->opal_list_length) {
return OPAL_SUCCESS;
}
items = (opal_list_item_t**)malloc(sizeof(opal_list_item_t*) *
list->opal_list_length);
if (NULL == items) {
return OPAL_ERR_OUT_OF_RESOURCE;
}
while(NULL != (item = opal_list_remove_first(list))) {
items[index++] = item;
}
qsort(items, index, sizeof(opal_list_item_t*),
(int(*)(const void*,const void*))compare);
for (i=0; i<index; i++) {
opal_list_append(list,items[i]);
}
free(items);
return OPAL_SUCCESS;
}