1
1
openmpi/opal/class/opal_tree.c
Nathan Hjelm 1282e98a01 opal/asm: rename existing arithmetic atomic functions
This commit renames the arithmetic atomic operations in opal to
indicate that they return the new value not the old value. This naming
differentiates these routines from new functions that return the old
value.

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

708 строки
22 KiB
C

/*
* Copyright (c) 2011 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011 Oak Ridge National Labs. All rights reserved.
* Copyright (c) 2012 The University of Tennessee and The University
* of Tennessee Research Foundation. All rights
* reserved.
* Copyright (c) 2013 Cisco Systems, Inc. All rights reserved.
* Copyright (c) 2014 Research Organization for Information Science
* and Technology (RIST). All rights reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#include "opal_config.h"
#include "opal/class/opal_tree.h"
#include "opal/constants.h"
/*
* List classes
*/
static void opal_tree_item_construct(opal_tree_item_t*);
static void opal_tree_item_destruct(opal_tree_item_t*);
OBJ_CLASS_INSTANCE(
opal_tree_item_t,
opal_object_t,
opal_tree_item_construct,
opal_tree_item_destruct
);
static void opal_tree_construct(opal_tree_t*);
static void opal_tree_destruct(opal_tree_t*);
OBJ_CLASS_INSTANCE(
opal_tree_t,
opal_object_t,
opal_tree_construct,
opal_tree_destruct
);
/*
*
* opal_tree_item_t interface
*
*/
static void opal_tree_item_construct(opal_tree_item_t *item)
{
item->opal_tree_parent = NULL;
item->opal_tree_num_ancestors = 0;
item->opal_tree_sibling_rank = 0xdeadbeef;
item->opal_tree_next_sibling = item->opal_tree_prev_sibling = NULL;
item->opal_tree_num_children = 0;
item->opal_tree_first_child = item->opal_tree_last_child = NULL;
#if OPAL_ENABLE_DEBUG
item->opal_tree_item_refcount = 0;
item->opal_tree_item_belong_to = NULL;
#endif
}
static void opal_tree_item_destruct(opal_tree_item_t *item)
{
#if OPAL_ENABLE_DEBUG
assert( 0 == item->opal_tree_item_refcount );
assert( NULL == item->opal_tree_item_belong_to );
#endif /* OPAL_ENABLE_DEBUG */
}
/*
*
* opal_tree_t interface
*
*/
static void opal_tree_construct(opal_tree_t *tree)
{
OBJ_CONSTRUCT( &(tree->opal_tree_sentinel), opal_tree_item_t );
#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. */
tree->opal_tree_sentinel.opal_tree_item_refcount = 1;
tree->opal_tree_sentinel.opal_tree_item_belong_to = tree;
#endif
tree->opal_tree_sentinel.opal_tree_container = tree;
tree->opal_tree_sentinel.opal_tree_parent = &tree->opal_tree_sentinel;
tree->opal_tree_sentinel.opal_tree_num_ancestors = -1;
tree->opal_tree_sentinel.opal_tree_next_sibling =
&tree->opal_tree_sentinel;
tree->opal_tree_sentinel.opal_tree_prev_sibling =
&tree->opal_tree_sentinel;
tree->opal_tree_sentinel.opal_tree_first_child = &tree->opal_tree_sentinel;
tree->opal_tree_sentinel.opal_tree_last_child = &tree->opal_tree_sentinel;
tree->opal_tree_num_items = 0;
tree->comp = NULL;
tree->serialize = NULL;
tree->deserialize = NULL;
tree->get_key = NULL;
}
/*
* Reset all the pointers to be NULL -- do not actually destroy
* anything.
*/
static void opal_tree_destruct(opal_tree_t *tree)
{
opal_tree_construct(tree);
}
/*
* initialize tree container
*/
void opal_tree_init(opal_tree_t *tree, opal_tree_comp_fn_t comp,
opal_tree_item_serialize_fn_t serialize,
opal_tree_item_deserialize_fn_t deserialize,
opal_tree_get_key_fn_t get_key)
{
tree->comp = comp;
tree->serialize = serialize;
tree->deserialize = deserialize;
tree->get_key = get_key;
}
/*
* count all the descendants from our level and below
*/
static int count_descendants(opal_tree_item_t* item)
{
int current_count = 0;
/* loop over all siblings for descendants to count */
while (item) {
current_count += count_descendants(opal_tree_get_first_child(item));
current_count++; /* count ourselves */
item = opal_tree_get_next_sibling(item);
}
return(current_count);
}
/*
* get size of tree
*/
size_t opal_tree_get_size(opal_tree_t* tree)
{
#if OPAL_ENABLE_DEBUG
/* not sure if we really want this running in devel, as it does
* slow things down. Wanted for development of splice / join to
* make sure length was reset properly
*/
size_t check_len = 0;
opal_tree_item_t *root;
if (!opal_tree_is_empty(tree)) {
/* tree has entries so count up items */
root = opal_tree_get_root(tree);
check_len = count_descendants(root);
}
if (check_len != tree->opal_tree_num_items) {
fprintf(stderr," Error :: opal_tree_get_size - opal_tree_num_items does not match actual tree length\n");
fflush(stderr);
abort();
}
#endif
return tree->opal_tree_num_items;
}
/*
* add item to parent's child list
*/
void opal_tree_add_child(opal_tree_item_t *parent_item,
opal_tree_item_t *new_item)
{
#if OPAL_ENABLE_DEBUG
/* Spot check: ensure that this item is previously on no lists */
assert(0 == new_item->opal_tree_item_refcount);
assert( NULL == new_item->opal_tree_item_belong_to );
#endif
new_item->opal_tree_parent = parent_item;
new_item->opal_tree_num_ancestors = parent_item->opal_tree_num_ancestors+1;
if (parent_item->opal_tree_num_children) {
/* append item to end of children and sibling lists */
new_item->opal_tree_prev_sibling = parent_item->opal_tree_last_child;
parent_item->opal_tree_last_child->opal_tree_next_sibling = new_item;
} else {
/* no children existing on parent */
parent_item->opal_tree_first_child = new_item;
}
parent_item->opal_tree_last_child = new_item;
parent_item->opal_tree_num_children++;
new_item->opal_tree_container = parent_item->opal_tree_container;
new_item->opal_tree_container->opal_tree_num_items++;
#if OPAL_ENABLE_DEBUG
/* Spot check: ensure this item is only on the list that we just
appended it to */
OPAL_THREAD_ADD_FETCH32( &(new_item->opal_tree_item_refcount), 1 );
assert(1 == new_item->opal_tree_item_refcount);
new_item->opal_tree_item_belong_to = new_item->opal_tree_container;
#endif
}
/*
* check to see if item is in tree
*/
#if OPAL_ENABLE_DEBUG
static bool item_in_tree(opal_tree_item_t *item, opal_tree_item_t *search_item)
{
bool result = false;
opal_tree_item_t *first_child;
while (!result && item) {
/* check for item match */
result = (item == search_item) ? true : false;
if (!result && (first_child = opal_tree_get_first_child(item))) {
/* search descendants for match */
result = item_in_tree(first_child, search_item);
}
if (!result) {
/* didn't find match at our node or descending so check sibling */
item = opal_tree_get_next_sibling(item);
}
}
return(result);
}
#endif /* OPAL_ENABLE_DEBUG */
/*
* remove item and all items below it from tree and return it to the caller
*/
opal_tree_item_t *opal_tree_remove_subtree(opal_tree_item_t *item)
{
opal_tree_item_t *parent_item = NULL;
#if OPAL_ENABLE_DEBUG
/* validate that item does exist on tree */
if (NULL != item->opal_tree_container) {
/* we point to a container, check if we can find item in tree */
if (!item_in_tree(opal_tree_get_root(item->opal_tree_container), item)) {
return(NULL);
}
} else {
return (NULL);
}
#endif
parent_item = item->opal_tree_parent;
/* remove from parent */
/* If item is the only child, set _first_child and _last_child to
be item's _first_child and _last_child */
if (parent_item->opal_tree_first_child == item &&
parent_item->opal_tree_last_child == item) {
parent_item->opal_tree_first_child = item->opal_tree_first_child;
parent_item->opal_tree_last_child = item->opal_tree_last_child;
} else {
/* Otherwise, there are multiple children of this parent. If
this item is the first or last child of this parent, then
ensure that the parent gets a valid first / last child:
- If I have children, then my first/last child
- If I have no children, then my immediate sibling */
if (item->opal_tree_parent->opal_tree_first_child == item) {
if (item->opal_tree_num_children > 0) {
parent_item->opal_tree_first_child =
item->opal_tree_next_sibling;
} else {
parent_item->opal_tree_first_child =
opal_tree_get_next_sibling(item);
}
} else if (parent_item->opal_tree_last_child == item) {
if (item->opal_tree_num_children > 0) {
parent_item->opal_tree_last_child =
item->opal_tree_last_child;
} else {
parent_item->opal_tree_last_child =
opal_tree_get_prev_sibling(item);
}
}
}
item->opal_tree_parent->opal_tree_num_children--;
/* remove from sibling pointers */
if (NULL != item->opal_tree_prev_sibling) {
item->opal_tree_prev_sibling->opal_tree_next_sibling=
item->opal_tree_next_sibling;
}
if (NULL != item->opal_tree_next_sibling) {
item->opal_tree_next_sibling->opal_tree_prev_sibling=
item->opal_tree_prev_sibling;
}
item->opal_tree_prev_sibling = NULL;
item->opal_tree_next_sibling = NULL;
/* adjust items relating to container */
item->opal_tree_container->opal_tree_num_items -= count_descendants(item);
item->opal_tree_container = NULL;
return(item);
}
int opal_tree_remove_item(opal_tree_t *tree,
opal_tree_item_t *item)
{
opal_tree_item_t *parent_item = NULL, *child = NULL;
parent_item = (opal_tree_item_t*)item->opal_tree_parent;
/*
* Point each of my children to my parent
*/
for(child = opal_tree_get_first_child(item);
child != NULL;
child = opal_tree_get_next_sibling(child)) {
child->opal_tree_parent = parent_item;
child->opal_tree_num_ancestors--;
parent_item->opal_tree_num_children++;
}
/*
* My first child points to my 'prev' sibling
*/
child = opal_tree_get_first_child(item);
if( NULL != child ) {
child->opal_tree_prev_sibling = item->opal_tree_prev_sibling;
}
if( NULL != item->opal_tree_prev_sibling ) {
(item->opal_tree_prev_sibling)->opal_tree_next_sibling = child;
}
child = opal_tree_get_last_child(item);
if( NULL != child ) {
child->opal_tree_next_sibling = item->opal_tree_next_sibling;
}
if( NULL != item->opal_tree_next_sibling ) {
(item->opal_tree_next_sibling)->opal_tree_prev_sibling = child;
}
/*
* Remove me from my parent. If I was the only child, then make
* the first child be my first child, and make the last child be
* my last child.
*/
if( parent_item->opal_tree_first_child == item &&
parent_item->opal_tree_last_child == item ) {
parent_item->opal_tree_first_child = opal_tree_get_first_child(item);
parent_item->opal_tree_last_child = opal_tree_get_last_child(item);
} else {
/* There were multiple children. If I was the first or last,
then ensure the parent gets a valid first or last child:
- If I have children, then my first/last
- If I have no childen, then my immediate sibling */
if (parent_item->opal_tree_first_child == item) {
if (item->opal_tree_num_children > 0) {
parent_item->opal_tree_first_child =
item->opal_tree_first_child;
} else {
parent_item->opal_tree_first_child =
opal_tree_get_next_sibling(item);
}
} else if (parent_item->opal_tree_last_child == item) {
if (item->opal_tree_num_children > 0) {
parent_item->opal_tree_last_child =
item->opal_tree_last_child;
} else {
parent_item->opal_tree_last_child =
opal_tree_get_prev_sibling(item);
}
}
}
parent_item->opal_tree_num_children--;
return OPAL_SUCCESS;
}
/* delimeter characters that mark items in a serialized stream */
static char *start_lvl = "[";
static char *end_lvl = "]";
static char *end_stream = "E";
/*
* add item to opal buffer that represents all items of a sub-tree from the
* item passed in on down. We exit out of converting tree items once we've
* done the last child of the tree_item and we are at depth 1.
*/
static int add_tree_item2buf(opal_tree_item_t *tree_item,
opal_buffer_t *buf,
opal_tree_item_serialize_fn_t fn,
int depth
)
{
opal_tree_item_t *first_child;
int rc;
do {
/* add start delim to buffer */
if (OPAL_SUCCESS !=
(rc = opal_dss.pack(buf, &start_lvl, 1, OPAL_STRING))){
return(rc);
}
/* add item to opal buffer from class creator */
fn(tree_item, buf);
if ((first_child = opal_tree_get_first_child(tree_item))) {
/* add items for our children */
if (OPAL_SUCCESS !=
(rc = add_tree_item2buf(first_child, buf, fn, depth+1))){
return(rc);
}
if (OPAL_SUCCESS !=
(rc = opal_dss.pack(buf, &end_lvl, 1, OPAL_STRING))){
return(rc);
}
} else {
/* end item entry */
if (OPAL_SUCCESS !=
(rc = opal_dss.pack(buf, &end_lvl, 1, OPAL_STRING))){
return(rc);
}
}
/* advance to next sibling, if none we'll drop out of
* loop and return to our parent
*/
tree_item = opal_tree_get_next_sibling(tree_item);
} while (tree_item && 1 < depth);
return(OPAL_SUCCESS);
}
/*
* serialize tree data
*/
int opal_tree_serialize(opal_tree_item_t *start_item, opal_buffer_t *buffer)
{
int rc;
if (OPAL_SUCCESS !=
(rc = add_tree_item2buf(start_item, buffer,
start_item->opal_tree_container->serialize,
1))){
return(rc);
}
if (OPAL_SUCCESS !=
(rc = opal_dss.pack(buffer, &end_stream, 1, OPAL_STRING))){
return(rc);
}
return(OPAL_SUCCESS);
}
static int deserialize_add_tree_item(opal_buffer_t *data,
opal_tree_item_t *parent_item,
opal_tree_item_deserialize_fn_t deserialize,
char **curr_delim,
int depth)
{
int idx = 1, rc;
opal_tree_item_t *new_item = NULL;
int level = 0; /* 0 - one up 1 - curr, 2 - one down */
if (!*curr_delim) {
if (OPAL_SUCCESS !=
(rc = opal_dss.unpack(data, curr_delim, &idx, OPAL_STRING))) {
return(rc);
}
}
while(*curr_delim[0] != end_stream[0]) {
if (*curr_delim[0] == start_lvl[0]) {
level++;
} else {
level--;
}
switch (level) {
case 0:
if (1 < depth) {
/* done with this level go up one level */
return(OPAL_SUCCESS);
}
break;
case 1:
/* add found child at this level */
deserialize(data, &new_item);
opal_tree_add_child(parent_item, new_item);
break;
case 2:
/* need to add child one level down */
deserialize_add_tree_item(data, new_item, deserialize, curr_delim,
depth+1);
level--;
break;
}
if (OPAL_SUCCESS !=
(rc = opal_dss.unpack(data, curr_delim, &idx, OPAL_STRING))) {
return(rc);
}
}
return(OPAL_SUCCESS);
}
/*
* deserialize tree data
*/
int opal_tree_deserialize(opal_buffer_t *serialized_data,
opal_tree_item_t *start_item)
{
char * null = NULL;
deserialize_add_tree_item(serialized_data,
start_item,
start_item->opal_tree_container->deserialize,
&null,
1);
return OPAL_SUCCESS;
}
void * opal_tree_get_key(opal_tree_t *tree, opal_tree_item_t *item)
{
return tree->get_key(item);
}
int opal_tree_dup(opal_tree_t *from, opal_tree_t *to)
{
int ret;
opal_buffer_t *buffer = NULL;
opal_tree_init(to,
from->comp,
from->serialize,
from->deserialize,
from->get_key);
buffer = OBJ_NEW(opal_buffer_t);
opal_tree_serialize(opal_tree_get_root(from), buffer);
ret = opal_tree_deserialize(buffer, opal_tree_get_root(to));
OBJ_RELEASE(buffer);
return ret;
}
int opal_tree_copy_subtree(opal_tree_t *from_tree, opal_tree_item_t *from_item,
opal_tree_t *to_tree, opal_tree_item_t *to_parent)
{
int ret;
opal_buffer_t *buffer = NULL;
buffer = OBJ_NEW(opal_buffer_t);
opal_tree_serialize(from_item, buffer);
ret = opal_tree_deserialize(buffer, to_parent);
OBJ_RELEASE(buffer);
return ret;
}
opal_tree_item_t *opal_tree_dup_item(opal_tree_t *base, opal_tree_item_t *from)
{
opal_buffer_t *buffer = NULL;
opal_tree_item_t *new_item = NULL;
buffer = OBJ_NEW(opal_buffer_t);
opal_tree_serialize(from, buffer);
new_item = OBJ_NEW(opal_tree_item_t);
opal_tree_deserialize(buffer, new_item);
OBJ_RELEASE(buffer);
return new_item;
}
int opal_tree_num_children(opal_tree_item_t *parent)
{
opal_tree_item_t *child = NULL;
int i = 0;
for(child = opal_tree_get_first_child(parent);
child != NULL;
child = opal_tree_get_next_sibling(child) ) {
++i;
}
return i;
}
static int opal_tree_compare_subtrees(opal_tree_t *tree_left, opal_tree_t *tree_right,
opal_tree_item_t *left, opal_tree_item_t *right)
{
int ret;
opal_tree_item_t *left_child = NULL, *right_child = NULL;
/* Basecase */
if( NULL == left && NULL == right ) {
return 0; /* Match */
}
/* Compare: Depth */
if( NULL == left && NULL != right ) {
return -1;
}
else if( NULL != left && NULL == right ) {
return 1;
}
/* Compare: Keys */
if( 0 != tree_left->comp(right, opal_tree_get_key(tree_left, left)) ) {
return -2;
}
/* Compare: Number of children */
if( opal_tree_num_children(left) != opal_tree_num_children(right) ) {
return 2;
}
/* Recursively compare all children */
for(left_child = opal_tree_get_first_child(left), right_child = opal_tree_get_first_child(right);
left_child != NULL && right_child != NULL;
left_child = opal_tree_get_next_sibling(left_child), right_child = opal_tree_get_next_sibling(right_child) ) {
/* On first difference, return the result */
if( 0 != (ret = opal_tree_compare_subtrees(tree_left, tree_right, left_child, right_child)) ) {
return ret;
}
}
return 0;
}
int opal_tree_compare(opal_tree_t *left, opal_tree_t *right)
{
return opal_tree_compare_subtrees(left, right, opal_tree_get_root(left), opal_tree_get_root(right));
}
/*
* search myself, descendants and siblings for item matching key
*/
static opal_tree_item_t *find_in_descendants(opal_tree_item_t* item, void *key)
{
opal_tree_item_t *result = NULL, *first_child;
while (!result && item) {
/* check for item match */
result = (item->opal_tree_container->comp(item, key) == 0) ?
item : NULL;
if (!result && (first_child = opal_tree_get_first_child(item))) {
/* search descendants for match */
result = find_in_descendants(first_child, key);
}
if (!result) {
/* didn't find match at our node or descending so check sibling */
item = opal_tree_get_next_sibling(item);
}
}
return(result);
}
/*
* return next tree item that matches key
*/
opal_tree_item_t *opal_tree_find_with(opal_tree_item_t *item, void *key)
{
opal_tree_item_t *curr_item = item, *result = NULL;
if (!opal_tree_is_empty(item->opal_tree_container)) {
/* check my descendant for a match */
result = find_in_descendants(opal_tree_get_first_child(item), key);
if (!result) {
/* check my siblings for match */
if (NULL != (curr_item = opal_tree_get_next_sibling(curr_item))) {
result = find_in_descendants(curr_item, key);
}
}
/* check my ancestors (uncles) for match */
curr_item = item;
while (!result && curr_item && curr_item->opal_tree_num_ancestors > 0){
curr_item = opal_tree_get_next_sibling(item->opal_tree_parent);
while (NULL == curr_item &&
item->opal_tree_parent->opal_tree_num_ancestors > 0) {
item = item->opal_tree_parent;
curr_item = opal_tree_get_next_sibling(item->opal_tree_parent);
}
if (curr_item) {
/* search ancestors descendants for match */
result = find_in_descendants(curr_item, key);
}
}
}
return(result);
}