root/opal/class/opal_tree.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


DEFINITIONS

This source file includes following definitions.
  1. opal_tree_get_parent
  2. opal_tree_get_next_sibling
  3. opal_tree_get_prev_sibling
  4. opal_tree_get_first_child
  5. opal_tree_get_last_child
  6. opal_tree_is_empty
  7. opal_tree_get_root

   1 /*
   2  * Copyright (c) 2011      Oracle and/or its affiliates.  All rights reserved.
   3  * Copyright (c) 2011      Oak Ridge National Labs.  All rights reserved.
   4  *
   5  * $COPYRIGHT$
   6  *
   7  * Additional copyrights may follow
   8  *
   9  * $HEADER$
  10  */
  11 /**
  12  * @file
  13  *
  14  * The opal_tree_t interface is used to provide a generic
  15  * tree list container for Open MPI.  It was inspired by the opal_list_t
  16  * interface but instead of organizing items in a doubly-linked list
  17  * fashion, we order them in a finite tree structure.
  18  *
  19  * The general idea is a user creates an class instance that has two
  20  * components.  A tree structure component as defined by opal_tree_item_t
  21  * that links all the items together to form the tree.  Then there is
  22  * a user specific data component which the user defines what is stored at
  23  * each item.  When a user create a type to be used for a OBJ_CLASS_INSTANCE
  24  * it will contain the opal_tree_item_t followed by any user specific
  25  * data.  Then the opal_tree_item_t objects can be put in an
  26  * opal_tree_t.  Hence, you create a new type that derives from
  27  * opal_tree_item_t; this new type can then be used with opal_tree_t
  28  * containers.
  29  *
  30  * NOTE: opal_tree_item_t instances can only be on \em one tree at a
  31  * time.  Specifically, if you add an opal_tree_item_t to one tree,
  32  * and then add it to another tree (without first removing it from the
  33  * first tree), you will effectively be hosing the first tree.  You
  34  * have been warned.
  35  *
  36  * If OPAL_ENABLE_DEBUG is true, a bunch of checks occur, including
  37  * some spot checks for a debugging reference count in an attempt to
  38  * ensure that an opal_tree_item_t is only one *one* tree at a time.
  39  * Given the highly concurrent nature of this class, these spot checks
  40  * cannot guarantee that an item is only one tree at a time.
  41  * Specifically, since it is a desirable attribute of this class to
  42  * not use locks for normal operations, it is possible that two
  43  * threads may [erroneously] modify an opal_tree_item_t concurrently.
  44  *
  45  * The only way to guarantee that a debugging reference count is valid
  46  * for the duration of an operation is to lock the item_t during the
  47  * operation.  But this fundamentally changes the desirable attribute
  48  * of this class (i.e., no locks).  So all we can do is spot-check the
  49  * reference count in a bunch of places and check that it is still the
  50  * value that we think it should be.  But this doesn't mean that you
  51  * can run into "unlucky" cases where two threads are concurrently
  52  * modifying an item_t, but all the spot checks still return the
  53  * "right" values.  All we can do is hope that we have enough spot
  54  * checks to statistically drive down the possibility of the unlucky
  55  * cases happening.
  56  */
  57 
  58 #ifndef OPAL_TREE_H
  59 #define OPAL_TREE_H
  60 
  61 #include "opal_config.h"
  62 #include <stdio.h>
  63 #include <stdlib.h>
  64 #include "opal/class/opal_object.h"
  65 #include "opal/dss/dss.h"
  66 
  67 #if OPAL_ENABLE_DEBUG
  68 /* Need atomics for debugging (reference counting) */
  69 #include "opal/sys/atomic.h"
  70 #include "opal/threads/mutex.h"
  71 #endif
  72 
  73 BEGIN_C_DECLS
  74 
  75 /**
  76  * \internal
  77  *
  78  * The class for the tree container.
  79  */
  80 OPAL_DECLSPEC OBJ_CLASS_DECLARATION(opal_tree_t);
  81 /**
  82  * \internal
  83  *
  84  * Base class for items that are put in tree containers.
  85  */
  86 OPAL_DECLSPEC OBJ_CLASS_DECLARATION(opal_tree_item_t);
  87 
  88 /**
  89  * \internal
  90  *
  91  * Struct of an opal_tree_item_t
  92  */
  93 typedef struct opal_tree_item_t
  94 {
  95     /** Generic parent class for all Open MPI objects */
  96     opal_object_t super;
  97     /** Pointer to the tree this item belongs to */
  98     struct opal_tree_t *opal_tree_container;
  99     /* Parent info */
 100     /** Pointer to parent tree item */
 101     struct opal_tree_item_t *opal_tree_parent;
 102     /** Depth from the root item in tree */
 103     unsigned opal_tree_num_ancestors;
 104     /* Logical rank we are compared to other siblings */
 105     unsigned opal_tree_sibling_rank;
 106     /** Pointer to next item below same parent (or NULL if this is the
 107         leftmost sibling) */
 108     struct opal_tree_item_t *opal_tree_next_sibling;
 109     /** Pointer to previous item below same parent (or NULL if this is
 110         the rightmost sibling) */
 111     struct opal_tree_item_t *opal_tree_prev_sibling;
 112 
 113     /* Children info */
 114     /** Number of children */
 115     unsigned opal_tree_num_children;
 116     /** Pointer to first child item, or NULL if there are no children */
 117     struct opal_tree_item_t *opal_tree_first_child;
 118     /** Pointer to last child item, or NULL if there are no children */
 119     struct opal_tree_item_t *opal_tree_last_child;
 120 
 121 #if OPAL_ENABLE_DEBUG
 122     /** Atomic reference count for debugging */
 123     opal_atomic_int32_t opal_tree_item_refcount;
 124     /** The tree this item belong to */
 125     struct opal_tree_t* opal_tree_item_belong_to;
 126 #endif
 127 } opal_tree_item_t;
 128 
 129 /**
 130  * Check to see if item's user specific data matches key
 131  *
 132  * @param item - The item we want to check to see if it matches key
 133  * @param key - The opaque key that we want the match function to check
 134  *              in the item's user specific data.
 135  *
 136  * @returns 0 - If item's user specific data matches key
 137  * @returns non-zero - If item's user specific data does not match key
 138  *
 139  * This function is implemented by the code that constructs the tree
 140  * and initialized the pointer by the call to opal_tree_init.
 141  *
 142  */
 143 typedef int (*opal_tree_comp_fn_t)(opal_tree_item_t *item, void *key);
 144 
 145 /**
 146   * The serialize function typedef. This function is called by the
 147   * opal tree serialize code to serialize a tree item's user specific
 148   * data of a class type.
 149   *
 150   * @params item - item to serialize the user specific data from
 151   * @params buffer - the opal_buffer_t to store the serialized data in.
 152   *
 153   * @returns OPAL_SUCCESS - when successfully serialized item
 154   */
 155 typedef int (*opal_tree_item_serialize_fn_t)(opal_tree_item_t *item,
 156                                              opal_buffer_t *buffer);
 157 
 158 /**
 159   * The deserialize function typedef. This function is called by the
 160   * opal tree deserialize code to deserialize a tree item's user
 161   * specific data.
 162   *
 163   * @params buffer - the opal_buffer_t to deserialized data.
 164   * @params item - item to store the deserialized data into the user
 165   *                specific data
 166   *
 167   * @returns OPAL_SUCCESS - when successfully deserialized item
 168   */
 169 typedef int (*opal_tree_item_deserialize_fn_t)(opal_buffer_t *buffer,
 170                                                opal_tree_item_t **item);
 171 
 172 /**
 173   * Get the 'key' associated with this item
 174   */
 175 typedef void *(*opal_tree_get_key_fn_t)(opal_tree_item_t *item);
 176 
 177 /**
 178  * \internal
 179  *
 180  * Struct of an opal_tree_t
 181  *
 182  */
 183 typedef struct opal_tree_t
 184 {
 185     /** Generic parent class for all Open MPI objects */
 186     opal_object_t       super;
 187     /** Guard item of the tree that child points to root */
 188     opal_tree_item_t    opal_tree_sentinel;
 189     /** Quick reference to the number of items in the tree */
 190     volatile size_t     opal_tree_num_items;
 191     /** Function to compare two items in tree */
 192     opal_tree_comp_fn_t comp;
 193     /** Function to serialize tree item data */
 194     opal_tree_item_serialize_fn_t serialize;
 195     /** Function to deserialize tree item data */
 196     opal_tree_item_deserialize_fn_t deserialize;
 197     /**< Function to deserialize tree item data */
 198     opal_tree_get_key_fn_t get_key;
 199 } opal_tree_t;
 200 
 201 /** Macros to access items in the tree */
 202 
 203 /**
 204  * Get the parent of item in the tree.
 205  *
 206  * @param item A tree item.
 207  *
 208  * @returns The parent item in the tree
 209  *
 210  * This function is safe to be called with a null item pointer.
 211  */
 212 static inline opal_tree_item_t *opal_tree_get_parent(opal_tree_item_t *item)
 213 {
 214     return ((item) ? item->opal_tree_parent : NULL);
 215 }
 216 
 217 /**
 218  * Get the next sibling item in the tree.
 219  *
 220  * @param item A tree item.
 221  *
 222  * @returns The next sibling item in the tree
 223  *
 224  * This function is safe to be called with a null item pointer.
 225  */
 226 static inline opal_tree_item_t *opal_tree_get_next_sibling(opal_tree_item_t
 227                                                            *item)
 228 {
 229     return ((item) ? item->opal_tree_next_sibling : NULL);
 230 }
 231 
 232 
 233 /**
 234  * Get the previous sibling item in the tree.
 235  *
 236  * @param item A tree item.
 237  *
 238  * @returns The previous sibling item in the tree
 239  *
 240  * This function is safe to be called with a null item pointer.
 241  */
 242 static inline opal_tree_item_t *opal_tree_get_prev_sibling(opal_tree_item_t
 243                                                            *item)
 244 {
 245     return ((item) ? item->opal_tree_prev_sibling : NULL);
 246 }
 247 
 248 /**
 249  * Get the first child item in the tree.
 250  *
 251  * @param item A tree item.
 252  *
 253  * @returns The first child item in the tree
 254  *
 255  * This function is safe to be called with a null item pointer.
 256  *
 257  */
 258 static inline opal_tree_item_t *opal_tree_get_first_child(opal_tree_item_t
 259                                                           *item)
 260 {
 261     return ((item) ? item->opal_tree_first_child : NULL);
 262 }
 263 
 264 /**
 265  * Get the last child item in the tree.
 266  *
 267  * @param item A tree item.
 268  *
 269  * @returns The last child item in the tree
 270  *
 271  * This function is safe to be called with a null item pointer.
 272  *
 273  */
 274 static inline opal_tree_item_t *opal_tree_get_last_child(opal_tree_item_t
 275                                                          *item)
 276 {
 277     return ((item) ? item->opal_tree_last_child : NULL);
 278 }
 279 
 280 /**
 281  * Check for empty tree
 282  *
 283  * @param tree The tree container
 284  *
 285  * @returns true if tree's size is 0, false otherwise
 286  *
 287  * This is an O(1) operation.
 288  *
 289  * This is an inlined function in compilers that support inlining,
 290  * so it's usually a cheap operation.
 291  *
 292  */
 293 static inline bool opal_tree_is_empty(opal_tree_t* tree)
 294 {
 295 #if OPAL_ENABLE_DEBUG
 296     /* Spot check that the tree is a non-null pointer */
 297     assert(NULL != tree);
 298 #endif
 299     return (tree->opal_tree_sentinel.opal_tree_first_child ==
 300             &(tree->opal_tree_sentinel) ? true : false);
 301 }
 302 
 303 
 304 /**
 305  * Return the root item on the tree (does not remove it).
 306  *
 307  * @param tree The tree container
 308  *
 309  * @returns A pointer to the first item in the tree
 310  *
 311  * This is an O(1) operation to return the first item in the tree.
 312  *
 313  * This is an inlined function in compilers that support inlining, so
 314  * it's usually a cheap operation.
 315  *
 316  */
 317 static inline opal_tree_item_t* opal_tree_get_root(opal_tree_t* tree)
 318 {
 319     opal_tree_item_t* item;
 320 #if OPAL_ENABLE_DEBUG
 321     assert(NULL != tree);
 322 #endif
 323     item = tree->opal_tree_sentinel.opal_tree_first_child;
 324 #if OPAL_ENABLE_DEBUG
 325     /* Spot check: ensure that the first item is only on one list */
 326     assert(1 == item->opal_tree_item_refcount);
 327     assert(tree == item->opal_tree_item_belong_to );
 328 #endif
 329     return item;
 330 }
 331 
 332 /**
 333  * Return the number of items in a tree
 334  *
 335  * @param tree The tree container
 336  *
 337  * @returns The size of the tree (size_t)
 338  *
 339  * This is an O(1) (in non-debug mode) lookup to return the
 340  * size of the list.
 341  */
 342 OPAL_DECLSPEC size_t opal_tree_get_size(opal_tree_t* tree);
 343 
 344 
 345 /* Functions to manage the tree */
 346 /**
 347  * Initialize tree container; must be called before using
 348  * the tree.
 349  *
 350  * @param tree        The tree to initialize
 351  * @param comp        Comparison function to attach to tree.
 352  * @param serialize   Serialization function to attach to tree.
 353  * @param deserialize De-serialization function to attach to tree.
 354  *
 355  */
 356 OPAL_DECLSPEC void opal_tree_init(opal_tree_t *tree,
 357                                   opal_tree_comp_fn_t comp,
 358                                   opal_tree_item_serialize_fn_t serialize,
 359                                   opal_tree_item_deserialize_fn_t deserialize,
 360                                   opal_tree_get_key_fn_t get_key);
 361 
 362 /**
 363  * Add new item as child to its parent item
 364  *
 365  * @param parent_item pointer to what parent the new item belongs to
 366  * @param new_item the item to be added as a child to parent_item
 367  *
 368  * The new_item is added at the end of the child list of the parent_item.
 369  */
 370 OPAL_DECLSPEC void opal_tree_add_child(opal_tree_item_t *parent_item,
 371                                        opal_tree_item_t *new_item);
 372 
 373 /**
 374  * Remove an item and everything below from a tree.
 375  *
 376  * @param item The item at the top of subtree to remove
 377  *
 378  * @returns A pointer to the item on the list previous to the one
 379  * that was removed.
 380  *
 381  * This is an O(1) operation to remove an item from the tree.  The
 382  * item and all children below it will be removed from the tree.  This
 383  * means the item's siblings pointers and potentially the parents first
 384  * and last pointers will be updated to skip over the item.  The tree container
 385  * will also have its num_items adjusted to reflect the number of items
 386  * that were removed.  The tree item (and all children below it) that is
 387  * returned is now "owned" by the caller -- they are responsible for
 388  * OBJ_RELEASE()'ing it.
 389  *
 390  * With ENABLE_DEBUG on this routine will validate whether the item is actually
 391  * in the tree before doing pointer manipulation.
 392  */
 393 OPAL_DECLSPEC opal_tree_item_t *opal_tree_remove_subtree(opal_tree_item_t *item);
 394 
 395 /**
 396  * Remove an item, everything below inherited by parent.
 397  *
 398  * @param tree Tree from which to remove
 399  * @param item The item to remove
 400  *
 401  * @returns Success/Failure
 402  */
 403 OPAL_DECLSPEC int opal_tree_remove_item(opal_tree_t *tree,
 404                                         opal_tree_item_t *item);
 405 
 406 /**
 407  * Serialize tree data
 408  *
 409  * @param start_item The item of a tree to start serializing data
 410  * @param buffer The opal buffer that contains the serialized
 411  *  data stream of the tree
 412  *
 413  * @returns OPAL_SUCCESS if data has been successfully converted.
 414  *
 415  * This routine walks the tree starting at start_item until it has serialized
 416  * all children items of start_item and creates a bytestream of data,
 417  * using the opal_dss.pack routine, that can be sent over a network.
 418  * The format of the bytestream represents the tree parent/child relationship
 419  * of each item in the tree plus the data inside the tree.  This routine calls
 420  * the tree's serialization method to serialize the user specific data for
 421  * each item.
 422  *
 423  */
 424 OPAL_DECLSPEC int opal_tree_serialize(opal_tree_item_t *start_item,
 425                                       opal_buffer_t *buffer);
 426 
 427 /**
 428  * De-serialize tree data
 429  *
 430  * @param buffer The opal buffer that is to be deserialized
 431  * @param start_item The item in the tree the data should be
 432  * deserialized into
 433  *
 434  * @returns Status of call OPAL_SUCCESS if everything worked
 435  *
 436  * This routine takes a bytestream that was created by the
 437  * opal_tree_serialize() function and deserializes it into the
 438  * tree given.  If the tree already has data in it, this routine
 439  * will start adding the new data as a new child of the root
 440  * item.  This routine calls the tree's de-serialization
 441  * method to deserialize the user specific data for each item.
 442  *
 443  */
 444 OPAL_DECLSPEC int opal_tree_deserialize(opal_buffer_t *buffer,
 445                                         opal_tree_item_t *start_item);
 446 
 447 /**
 448  * Access the 'key' associated with the item
 449  *
 450  * @param tree Source Tree
 451  * @param item Item to access key of
 452  *
 453  * @returns Success/Failure
 454  */
 455 OPAL_DECLSPEC void * opal_tree_get_key(opal_tree_t *tree, opal_tree_item_t *item);
 456 
 457 /**
 458  * Copy/Duplicate a tree (requires serialize/deserialize)
 459  *
 460  * @param from Source tree to copy 'from'
 461  * @param to   Destination tree to copy 'to'
 462  *
 463  * @returns Success/Failure
 464  */
 465 OPAL_DECLSPEC int opal_tree_dup(opal_tree_t *from, opal_tree_t *to);
 466 
 467 /**
 468  * Copy/Duplicate a subtree (requires serialize/deserialize)
 469  *
 470  * @param base Base tree
 471  * @param from Source tree item to copy 'from'
 472  *
 473  * @returns Tree item copy
 474  */
 475 OPAL_DECLSPEC int opal_tree_copy_subtree(opal_tree_t *from_tree, opal_tree_item_t *from_item,
 476                                          opal_tree_t *to_tree,   opal_tree_item_t *to_parent);
 477 
 478 /**
 479  * Copy/Duplicate a tree item (requires serialize/deserialize)
 480  *
 481  * @param base Base tree
 482  * @param from Source tree item to copy 'from'
 483  *
 484  * @returns Tree item copy
 485  */
 486 OPAL_DECLSPEC opal_tree_item_t *opal_tree_dup_item(opal_tree_t *base, opal_tree_item_t *from);
 487 
 488 /**
 489  * Count the number of children of this parent
 490  *
 491  * @param parent A parent node in the tree
 492  *
 493  * @returns Number of children of this parent
 494  */
 495 OPAL_DECLSPEC int opal_tree_num_children(opal_tree_item_t *parent);
 496 
 497 /**
 498  * Compare two trees
 499  *
 500  * @param left Tree
 501  * @param right Tree
 502  *
 503  * @returns 0 if identical, ow returns non-zero
 504  */
 505 OPAL_DECLSPEC int opal_tree_compare(opal_tree_t *left, opal_tree_t *right);
 506 
 507 /* Functions to search for items on tree */
 508 /**
 509  * Return the next tree item that matches key provided
 510  *
 511  * @param item The item to start the find from
 512  * @param key the key we are wanting to match with
 513  *
 514  * @returns A pointer to the next item that in the tree (starting from item)
 515  * that matches the key based on a depth first search of the tree.  A null
 516  * pointer is returned if we've reached the end of the tree and have not
 517  * matched the key.
 518  *
 519  * This routine uses the tree container's comp function to determine the
 520  * whether there is a match between the key and each item we search in the
 521  * tree.  This means the actual tree type constructed determines how the
 522  * compare is done with the key.  In the case no compare routine is given
 523  * and NULL pointer is always returned for this function.
 524  *
 525  */
 526 OPAL_DECLSPEC opal_tree_item_t *opal_tree_find_with(opal_tree_item_t *item,
 527                                                     void *key);
 528 END_C_DECLS
 529 
 530 #endif /* OPAL_TREE_H */

/* [<][>][^][v][top][bottom][index][help] */