Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-02-22 10:47:20

0001 /* -*- Mode: C; c-basic-offset:4 ; -*- */
0002 /*
0003  * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
0004  *                         University Research and Technology
0005  *                         Corporation.  All rights reserved.
0006  * Copyright (c) 2004-2006 The University of Tennessee and The University
0007  *                         of Tennessee Research Foundation.  All rights
0008  *                         reserved.
0009  * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
0010  *                         University of Stuttgart.  All rights reserved.
0011  * Copyright (c) 2004-2005 The Regents of the University of California.
0012  *                         All rights reserved.
0013  * Copyright (c) 2007      Voltaire All rights reserved.
0014  * Copyright (c) 2013      Los Alamos National Security, LLC. All rights
0015  *                         reserved.
0016  * Copyright (c) 2013-2020 Intel, Inc.  All rights reserved.
0017  * Copyright (c) 2021-2022 Nanook Consulting  All rights reserved.
0018  * $COPYRIGHT$
0019  *
0020  * Additional copyrights may follow
0021  *
0022  * $HEADER$
0023  */
0024 /**
0025  * @file
0026  *
0027  * The pmix_list_t interface is used to provide a generic
0028  * doubly-linked list container for PMIx.  It was inspired by (but
0029  * is slightly different than) the Standard Template Library (STL)
0030  * std::list class.  One notable difference from std::list is that
0031  * when an pmix_list_t is destroyed, all of the pmix_list_item_t
0032  * objects that it contains are orphaned -- they are \em not
0033  * destroyed.
0034  *
0035  * The general idea is that pmix_list_item_t objects can be put on an
0036  * pmix_list_t.  Hence, you create a new type that derives from
0037  * pmix_list_item_t; this new type can then be used with pmix_list_t
0038  * containers.
0039  *
0040  * NOTE: pmix_list_item_t instances can only be on \em one list at a
0041  * time.  Specifically, if you add an pmix_list_item_t to one list,
0042  * and then add it to another list (without first removing it from the
0043  * first list), you will effectively be hosing the first list.  You
0044  * have been warned.
0045  *
0046  * If PMIX_ENABLE_DEBUG is true, a bunch of checks occur, including
0047  * some spot checks for a debugging reference count in an attempt to
0048  * ensure that an pmix_list_item_t is only one *one* list at a time.
0049  * Given the highly concurrent nature of this class, these spot checks
0050  * cannot guarantee that an item is only one list at a time.
0051  * Specifically, since it is a desirable attribute of this class to
0052  * not use locks for normal operations, it is possible that two
0053  * threads may [erroneously] modify an pmix_list_item_t concurrently.
0054  *
0055  * The only way to guarantee that a debugging reference count is valid
0056  * for the duration of an operation is to lock the item_t during the
0057  * operation.  But this fundamentally changes the desirable attribute
0058  * of this class (i.e., no locks).  So all we can do is spot-check the
0059  * reference count in a bunch of places and check that it is still the
0060  * value that we think it should be.  But this doesn't mean that you
0061  * can run into "unlucky" cases where two threads are concurrently
0062  * modifying an item_t, but all the spot checks still return the
0063  * "right" values.  All we can do is hope that we have enough spot
0064  * checks to statistically drive down the possibility of the unlucky
0065  * cases happening.
0066  */
0067 
0068 #ifndef PMIX_LIST_H
0069 #define PMIX_LIST_H
0070 
0071 #include "src/include/pmix_config.h"
0072 #include <stdio.h>
0073 #include <stdlib.h>
0074 #if HAVE_STDBOOL_H
0075 #    include <stdbool.h>
0076 #endif
0077 
0078 #include "pmix_common.h"
0079 #include "src/class/pmix_object.h"
0080 
0081 BEGIN_C_DECLS
0082 
0083 /**
0084  * \internal
0085  *
0086  * The class for the list container.
0087  */
0088 PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_list_t);
0089 /**
0090  * \internal
0091  *
0092  * Base class for items that are put in list (pmix_list_t) containers.
0093  */
0094 PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_list_item_t);
0095 
0096 /**
0097  * \internal
0098  *
0099  * Struct of an pmix_list_item_t
0100  */
0101 struct pmix_list_item_t {
0102     pmix_object_t super;
0103     /**< Generic parent class for all PMIx objects */
0104     volatile struct pmix_list_item_t *pmix_list_next;
0105     /**< Pointer to next list item */
0106     volatile struct pmix_list_item_t *pmix_list_prev;
0107     /**< Pointer to previous list item */
0108     int32_t item_free;
0109 
0110 #if PMIX_ENABLE_DEBUG
0111     /** Atomic reference count for debugging */
0112     int32_t pmix_list_item_refcount;
0113     /** The list this item belong to */
0114     volatile struct pmix_list_t *pmix_list_item_belong_to;
0115 #endif
0116 };
0117 /**
0118  * Base type for items that are put in a list (pmix_list_t) containers.
0119  */
0120 typedef struct pmix_list_item_t pmix_list_item_t;
0121 
0122 /* static initializer for pmix_list_t */
0123 #define PMIX_LIST_ITEM_STATIC_INIT                      \
0124     {                                                   \
0125         .super = PMIX_OBJ_STATIC_INIT(pmix_object_t),   \
0126         .pmix_list_next = NULL,                         \
0127         .pmix_list_prev = NULL,                         \
0128         .item_free = 0                                  \
0129     }
0130 
0131 /**
0132  * Get the next item in a list.
0133  *
0134  * @param item A list item.
0135  *
0136  * @returns The next item in the list
0137  */
0138 #define pmix_list_get_next(item) \
0139     ((item) ? ((pmix_list_item_t *) ((pmix_list_item_t *) (item))->pmix_list_next) : NULL)
0140 
0141 /**
0142  * Get the next item in a list.
0143  *
0144  * @param item A list item.
0145  *
0146  * @returns The next item in the list
0147  */
0148 #define pmix_list_get_prev(item) \
0149     ((item) ? ((pmix_list_item_t *) ((pmix_list_item_t *) (item))->pmix_list_prev) : NULL)
0150 
0151 /**
0152  * \internal
0153  *
0154  * Struct of an pmix_list_t
0155  */
0156 struct pmix_list_t {
0157     pmix_object_t super;
0158     /**< Generic parent class for all PMIx objects */
0159     pmix_list_item_t pmix_list_sentinel;
0160     /**< Head and tail item of the list */
0161     volatile size_t pmix_list_length;
0162     /**< Quick reference to the number of items in the list */
0163 };
0164 /**
0165  * List container type.
0166  */
0167 typedef struct pmix_list_t pmix_list_t;
0168 
0169 /* static initializer for pmix_list_t */
0170 #define PMIX_LIST_STATIC_INIT                               \
0171     {                                                       \
0172         .super = PMIX_OBJ_STATIC_INIT(pmix_object_t),       \
0173         .pmix_list_sentinel = PMIX_LIST_ITEM_STATIC_INIT,   \
0174         .pmix_list_length = 0                               \
0175     }
0176 
0177 /** Cleanly destruct a list
0178  *
0179  * The pmix_list_t destructor doesn't release the items on the
0180  * list - so provide two convenience macros that do so and then
0181  * destruct/release the list object itself
0182  *
0183  * @param[in] list List to destruct or release
0184  */
0185 #define PMIX_LIST_DESTRUCT(list)                              \
0186     do {                                                      \
0187         pmix_list_item_t *it;                                 \
0188         while (NULL != (it = pmix_list_remove_first(list))) { \
0189             PMIX_RELEASE(it);                                 \
0190         }                                                     \
0191         PMIX_DESTRUCT(list);                                  \
0192     } while (0)
0193 
0194 #define PMIX_LIST_RELEASE(list)                               \
0195     do {                                                      \
0196         pmix_list_item_t *it;                                 \
0197         while (NULL != (it = pmix_list_remove_first(list))) { \
0198             PMIX_RELEASE(it);                                 \
0199         }                                                     \
0200         PMIX_RELEASE(list);                                   \
0201     } while (0)
0202 
0203 /**
0204  * Loop over a list.
0205  *
0206  * @param[in] item Storage for each item
0207  * @param[in] list List to iterate over
0208  * @param[in] type Type of each list item
0209  *
0210  * This macro provides a simple way to loop over the items in an pmix_list_t. It
0211  * is not safe to call pmix_list_remove_item from within the loop.
0212  *
0213  * Example Usage:
0214  *
0215  * class_foo_t *foo;
0216  * pmix_list_foreach(foo, list, class_foo_t) {
0217  *    do something;
0218  * }
0219  */
0220 #define PMIX_LIST_FOREACH(item, list, type)                         \
0221     for (item = (type *) (list)->pmix_list_sentinel.pmix_list_next; \
0222          item != (type *) &(list)->pmix_list_sentinel;              \
0223          item = (type *) ((pmix_list_item_t *) (item))->pmix_list_next)
0224 
0225 #define PMIX_LIST_FOREACH_DECL(item, list, type)                          \
0226     for (type *item = (type *) (list)->pmix_list_sentinel.pmix_list_next; \
0227          item != (type *) &(list)->pmix_list_sentinel;                    \
0228          item = (type *) ((pmix_list_item_t *) (item))->pmix_list_next)
0229     /**
0230  * Loop over a list in reverse.
0231  *
0232  * @param[in] item Storage for each item
0233  * @param[in] list List to iterate over
0234  * @param[in] type Type of each list item
0235  *
0236  * This macro provides a simple way to loop over the items in an pmix_list_t. It
0237  * is not safe to call pmix_list_remove_item from within the loop.
0238  *
0239  * Example Usage:
0240  *
0241  * class_foo_t *foo;
0242  * pmix_list_foreach(foo, list, class_foo_t) {
0243  *    do something;
0244  * }
0245  */
0246 #define PMIX_LIST_FOREACH_REV(item, list, type)                     \
0247     for (item = (type *) (list)->pmix_list_sentinel.pmix_list_prev; \
0248          item != (type *) &(list)->pmix_list_sentinel;              \
0249          item = (type *) ((pmix_list_item_t *) (item))->pmix_list_prev)
0250 
0251 /**
0252  * Loop over a list in a *safe* way
0253  *
0254  * @param[in] item Storage for each item
0255  * @param[in] next Storage for next item
0256  * @param[in] list List to iterate over
0257  * @param[in] type Type of each list item
0258  *
0259  * This macro provides a simple way to loop over the items in an pmix_list_t. It
0260  * is safe to call pmix_list_remove_item(list, item) from within the loop.
0261  *
0262  * Example Usage:
0263  *
0264  * class_foo_t *foo, *next;
0265  * pmix_list_foreach_safe(foo, next, list, class_foo_t) {
0266  *    do something;
0267  *    pmix_list_remove_item (list, (pmix_list_item_t *) foo);
0268  * }
0269  */
0270 #define PMIX_LIST_FOREACH_SAFE(item, next, list, type)                 \
0271     for (item = (type *) (list)->pmix_list_sentinel.pmix_list_next,    \
0272         next = (type *) ((pmix_list_item_t *) (item))->pmix_list_next; \
0273          item != (type *) &(list)->pmix_list_sentinel;                 \
0274          item = next, next = (type *) ((pmix_list_item_t *) (item))->pmix_list_next)
0275 
0276 /**
0277  * Loop over a list in a *safe* way
0278  *
0279  * @param[in] item Storage for each item
0280  * @param[in] next Storage for next item
0281  * @param[in] list List to iterate over
0282  * @param[in] type Type of each list item
0283  *
0284  * This macro provides a simple way to loop over the items in an pmix_list_t. If
0285  * is safe to call pmix_list_remove_item(list, item) from within the loop.
0286  *
0287  * Example Usage:
0288  *
0289  * class_foo_t *foo, *next;
0290  * pmix_list_foreach_safe(foo, next, list, class_foo_t) {
0291  *    do something;
0292  *    pmix_list_remove_item (list, (pmix_list_item_t *) foo);
0293  * }
0294  */
0295 #define PMIX_LIST_FOREACH_SAFE_REV(item, prev, list, type)             \
0296     for (item = (type *) (list)->pmix_list_sentinel.pmix_list_prev,    \
0297         prev = (type *) ((pmix_list_item_t *) (item))->pmix_list_prev; \
0298          item != (type *) &(list)->pmix_list_sentinel;                 \
0299          item = prev, prev = (type *) ((pmix_list_item_t *) (item))->pmix_list_prev)
0300 
0301 /**
0302  * Check for empty list
0303  *
0304  * @param list The list container
0305  *
0306  * @returns true if list's size is 0, false otherwise
0307  *
0308  * This is an O(1) operation.
0309  *
0310  * This is an inlined function in compilers that support inlining,
0311  * so it's usually a cheap operation.
0312  */
0313 static inline bool pmix_list_is_empty(pmix_list_t *list)
0314 {
0315     return (list->pmix_list_sentinel.pmix_list_next == &(list->pmix_list_sentinel) ? true : false);
0316 }
0317 
0318 /**
0319  * Return the first item on the list (does not remove it).
0320  *
0321  * @param list The list container
0322  *
0323  * @returns A pointer to the first item on the list
0324  *
0325  * This is an O(1) operation to return the first item on the list.  It
0326  * should be compared against the returned value from
0327  * pmix_list_get_end() to ensure that the list is not empty.
0328  *
0329  * This is an inlined function in compilers that support inlining, so
0330  * it's usually a cheap operation.
0331  */
0332 static inline pmix_list_item_t *pmix_list_get_first(pmix_list_t *list)
0333 {
0334     pmix_list_item_t *item = (pmix_list_item_t *) list->pmix_list_sentinel.pmix_list_next;
0335 #if PMIX_ENABLE_DEBUG
0336     /* Spot check: ensure that the first item is only on one list */
0337 
0338     assert(1 == item->pmix_list_item_refcount);
0339     assert(list == item->pmix_list_item_belong_to);
0340 #endif
0341 
0342     return item;
0343 }
0344 
0345 /**
0346  * Return the last item on the list (does not remove it).
0347  *
0348  * @param list The list container
0349  *
0350  * @returns A pointer to the last item on the list
0351  *
0352  * This is an O(1) operation to return the last item on the list.  It
0353  * should be compared against the returned value from
0354  * pmix_list_get_begin() to ensure that the list is not empty.
0355  *
0356  * This is an inlined function in compilers that support inlining, so
0357  * it's usually a cheap operation.
0358  */
0359 static inline pmix_list_item_t *pmix_list_get_last(pmix_list_t *list)
0360 {
0361     pmix_list_item_t *item = (pmix_list_item_t *) list->pmix_list_sentinel.pmix_list_prev;
0362 #if PMIX_ENABLE_DEBUG
0363     /* Spot check: ensure that the last item is only on one list */
0364 
0365     assert(1 == item->pmix_list_item_refcount);
0366     assert(list == item->pmix_list_item_belong_to);
0367 #endif
0368 
0369     return item;
0370 }
0371 
0372 /**
0373  * Return the beginning of the list; an invalid list entry suitable
0374  * for comparison only.
0375  *
0376  * @param list The list container
0377  *
0378  * @returns A pointer to the beginning of the list.
0379  *
0380  * This is an O(1) operation to return the beginning of the list.
0381  * Similar to the STL, this is a special invalid list item -- it
0382  * should \em not be used for storage.  It is only suitable for
0383  * comparison to other items in the list to see if they are valid or
0384  * not; it's usually used when iterating through the items in a list.
0385  *
0386  * This is an inlined function in compilers that support inlining, so
0387  * it's usually a cheap operation.
0388  */
0389 static inline pmix_list_item_t *pmix_list_get_begin(pmix_list_t *list)
0390 {
0391     return &(list->pmix_list_sentinel);
0392 }
0393 
0394 /**
0395  * Return the end of the list; an invalid list entry suitable for
0396  * comparison only.
0397  *
0398  * @param list The list container
0399  *
0400  * @returns A pointer to the end of the list.
0401  *
0402  * This is an O(1) operation to return the end of the list.
0403  * Similar to the STL, this is a special invalid list item -- it
0404  * should \em not be used for storage.  It is only suitable for
0405  * comparison to other items in the list to see if they are valid or
0406  * not; it's usually used when iterating through the items in a list.
0407  *
0408  * This is an inlined function in compilers that support inlining, so
0409  * it's usually a cheap operation.
0410  */
0411 static inline pmix_list_item_t *pmix_list_get_end(pmix_list_t *list)
0412 {
0413     return &(list->pmix_list_sentinel);
0414 }
0415 
0416 /**
0417  * Return the number of items in a list
0418  *
0419  * @param list The list container
0420  *
0421  * @returns The size of the list (size_t)
0422  *
0423  * This is an O(1) lookup to return the size of the list.
0424  *
0425  * This is an inlined function in compilers that support inlining, so
0426  * it's usually a cheap operation.
0427  *
0428  * \warning The size of the list is cached as part of the list.  In
0429  * the future, calling \c pmix_list_splice or \c pmix_list_join may
0430  * result in this function recomputing the list size, which would be
0431  * an O(N) operation.  If \c pmix_list_splice or \c pmix_list_join is
0432  * never called on the specified list, this function will always be
0433  * O(1).
0434  */
0435 static inline size_t pmix_list_get_size(pmix_list_t *list)
0436 {
0437 #if PMIX_ENABLE_DEBUG && 0
0438     /* not sure if we really want this running in devel, as it does
0439      * slow things down.  Wanted for development of splice / join to
0440      * make sure length was reset properly
0441      */
0442     size_t check_len = 0;
0443     pmix_list_item_t *item;
0444 
0445     for (item = pmix_list_get_first(list); item != pmix_list_get_end(list);
0446          item = pmix_list_get_next(item)) {
0447         check_len++;
0448     }
0449 
0450     if (check_len != list->pmix_list_length) {
0451         fprintf(
0452             stderr,
0453             " Error :: pmix_list_get_size - pmix_list_length does not match actual list length\n");
0454         fflush(stderr);
0455         abort();
0456     }
0457 #endif
0458 
0459     return list->pmix_list_length;
0460 }
0461 
0462 /**
0463  * Remove an item from a list.
0464  *
0465  * @param list The list container
0466  * @param item The item to remove
0467  *
0468  * @returns A pointer to the item on the list previous to the one
0469  * that was removed.
0470  *
0471  * This is an O(1) operation to remove an item from the list.  The
0472  * forward / reverse pointers in the list are updated and the item is
0473  * removed.  The list item that is returned is now "owned" by the
0474  * caller -- they are responsible for PMIX_RELEASE()'ing it.
0475  *
0476  * If debugging is enabled (specifically, if --enable-debug was used
0477  * to configure PMIx), this is an O(N) operation because it checks
0478  * to see if the item is actually in the list first.
0479  *
0480  * This is an inlined function in compilers that support inlining, so
0481  * it's usually a cheap operation.
0482  */
0483 static inline pmix_list_item_t *pmix_list_remove_item(pmix_list_t *list, pmix_list_item_t *item)
0484 {
0485 #if PMIX_ENABLE_DEBUG
0486     pmix_list_item_t *item_ptr;
0487     bool found = false;
0488 
0489     /* check to see that the item is in the list */
0490     for (item_ptr = pmix_list_get_first(list); item_ptr != pmix_list_get_end(list);
0491          item_ptr = (pmix_list_item_t *) (item_ptr->pmix_list_next)) {
0492         if (item_ptr == (pmix_list_item_t *) item) {
0493             found = true;
0494             break;
0495         }
0496     }
0497     if (!found) {
0498         fprintf(stderr, " Warning :: pmix_list_remove_item - the item %p is not on the list %p \n",
0499                 (void *) item, (void *) list);
0500         fflush(stderr);
0501         return (pmix_list_item_t *) NULL;
0502     }
0503 
0504     assert(list == item->pmix_list_item_belong_to);
0505 #endif
0506 
0507     /* reset next pointer of previous element */
0508     item->pmix_list_prev->pmix_list_next = item->pmix_list_next;
0509 
0510     /* reset previous pointer of next element */
0511     item->pmix_list_next->pmix_list_prev = item->pmix_list_prev;
0512 
0513     list->pmix_list_length--;
0514 
0515 #if PMIX_ENABLE_DEBUG
0516     /* Spot check: ensure that this item is still only on one list */
0517 
0518     item->pmix_list_item_refcount -= 1;
0519     assert(0 == item->pmix_list_item_refcount);
0520     item->pmix_list_item_belong_to = NULL;
0521 #endif
0522 
0523     return (pmix_list_item_t *) item->pmix_list_prev;
0524 }
0525 
0526 /**
0527  * Append an item to the end of the list.
0528  *
0529  * @param list The list container
0530  * @param item The item to append
0531  *
0532  * This is an O(1) operation to append an item to the end of a list.
0533  * The pmix_list_item_t is not PMIX_RETAIN()'ed; it is assumed that
0534  * "ownership" of the item is passed from the caller to the list.
0535  *
0536  * This is an inlined function in compilers that support inlining, so
0537  * it's usually a cheap operation.
0538  */
0539 
0540 #if PMIX_ENABLE_DEBUG
0541 #    define pmix_list_append(l, i) _pmix_list_append(l, i, __FILE__, __LINE__)
0542 #else
0543 #    define pmix_list_append(l, i) _pmix_list_append(l, i)
0544 #endif /* PMIX_ENABLE_DEBUG */
0545 
0546 static inline void _pmix_list_append(pmix_list_t *list, pmix_list_item_t *item
0547 #if PMIX_ENABLE_DEBUG
0548                                      ,
0549                                      const char *FILE_NAME, int LINENO
0550 #endif /* PMIX_ENABLE_DEBUG */
0551 )
0552 {
0553     pmix_list_item_t *sentinel = &(list->pmix_list_sentinel);
0554 #if PMIX_ENABLE_DEBUG
0555     /* Spot check: ensure that this item is previously on no lists */
0556 
0557     assert(0 == item->pmix_list_item_refcount);
0558     assert(NULL == item->pmix_list_item_belong_to);
0559     item->super.cls_init_file_name = FILE_NAME;
0560     item->super.cls_init_lineno = LINENO;
0561 #endif
0562 
0563     /* set new element's previous pointer */
0564     item->pmix_list_prev = sentinel->pmix_list_prev;
0565 
0566     /* reset previous pointer on current last element */
0567     sentinel->pmix_list_prev->pmix_list_next = item;
0568 
0569     /* reset new element's next pointer */
0570     item->pmix_list_next = sentinel;
0571 
0572     /* reset the list's tail element previous pointer */
0573     sentinel->pmix_list_prev = item;
0574 
0575     /* increment list element counter */
0576     list->pmix_list_length++;
0577 
0578 #if PMIX_ENABLE_DEBUG
0579     /* Spot check: ensure this item is only on the list that we just
0580        appended it to */
0581 
0582     item->pmix_list_item_refcount += 1;
0583     assert(1 == item->pmix_list_item_refcount);
0584     item->pmix_list_item_belong_to = list;
0585 #endif
0586 }
0587 
0588 /**
0589  * Prepend an item to the beginning of the list.
0590  *
0591  * @param list The list container
0592  * @param item The item to prepend
0593  *
0594  * This is an O(1) operation to prepend an item to the beginning of a
0595  * list.  The pmix_list_item_t is not PMIX_RETAIN()'ed; it is assumed
0596  * that "ownership" of the item is passed from the caller to the list.
0597  *
0598  * This is an inlined function in compilers that support inlining, so
0599  * it's usually a cheap operation.
0600  */
0601 static inline void pmix_list_prepend(pmix_list_t *list, pmix_list_item_t *item)
0602 {
0603     pmix_list_item_t *sentinel = &(list->pmix_list_sentinel);
0604 #if PMIX_ENABLE_DEBUG
0605     /* Spot check: ensure that this item is previously on no lists */
0606 
0607     assert(0 == item->pmix_list_item_refcount);
0608     assert(NULL == item->pmix_list_item_belong_to);
0609 #endif
0610 
0611     /* reset item's next pointer */
0612     item->pmix_list_next = sentinel->pmix_list_next;
0613 
0614     /* reset item's previous pointer */
0615     item->pmix_list_prev = sentinel;
0616 
0617     /* reset previous first element's previous pointer */
0618     sentinel->pmix_list_next->pmix_list_prev = item;
0619 
0620     /* reset head's next pointer */
0621     sentinel->pmix_list_next = item;
0622 
0623     /* increment list element counter */
0624     list->pmix_list_length++;
0625 
0626 #if PMIX_ENABLE_DEBUG
0627     /* Spot check: ensure this item is only on the list that we just
0628        prepended it to */
0629 
0630     item->pmix_list_item_refcount += 1;
0631     assert(1 == item->pmix_list_item_refcount);
0632     item->pmix_list_item_belong_to = list;
0633 #endif
0634 }
0635 
0636 /**
0637  * Remove the first item from the list and return it.
0638  *
0639  * @param list The list container
0640  *
0641  * @returns The first item on the list.  If the list is empty,
0642  * NULL will be returned
0643  *
0644  * This is an O(1) operation to return the first item on the list.  If
0645  * the list is not empty, a pointer to the first item in the list will
0646  * be returned.  Ownership of the item is transferred from the list to
0647  * the caller; no calls to PMIX_RETAIN() or PMIX_RELEASE() are invoked.
0648  *
0649  * This is an inlined function in compilers that support inlining, so
0650  * it's usually a cheap operation.
0651  */
0652 static inline pmix_list_item_t *pmix_list_remove_first(pmix_list_t *list)
0653 {
0654     /*  Removes and returns first item on list.
0655         Caller now owns the item and should release the item
0656         when caller is done with it.
0657     */
0658     volatile pmix_list_item_t *item;
0659     if (0 == list->pmix_list_length) {
0660         return (pmix_list_item_t *) NULL;
0661     }
0662 
0663 #if PMIX_ENABLE_DEBUG
0664     /* Spot check: ensure that the first item is only on this list */
0665 
0666     assert(1 == list->pmix_list_sentinel.pmix_list_next->pmix_list_item_refcount);
0667 #endif
0668 
0669     /* reset list length counter */
0670     list->pmix_list_length--;
0671 
0672     /* get pointer to first element on the list */
0673     item = (pmix_list_item_t*)list->pmix_list_sentinel.pmix_list_next;
0674 
0675     /* reset previous pointer of next item on the list */
0676     item->pmix_list_next->pmix_list_prev = item->pmix_list_prev;
0677 
0678     /* reset the head next pointer */
0679     list->pmix_list_sentinel.pmix_list_next = item->pmix_list_next;
0680 
0681 #if PMIX_ENABLE_DEBUG
0682     assert(list == item->pmix_list_item_belong_to);
0683     item->pmix_list_item_belong_to = NULL;
0684     item->pmix_list_prev = (pmix_list_item_t *) NULL;
0685     item->pmix_list_next = (pmix_list_item_t *) NULL;
0686 
0687     /* Spot check: ensure that the item we're returning is now on no
0688        lists */
0689 
0690     item->pmix_list_item_refcount -= 1;
0691     assert(0 == item->pmix_list_item_refcount);
0692 #endif
0693 
0694     return (pmix_list_item_t *) item;
0695 }
0696 
0697 /**
0698  * Remove the last item from the list and return it.
0699  *
0700  * @param list The list container
0701  *
0702  * @returns The last item on the list.  If the list is empty,
0703  * NULL will be returned
0704  *
0705  * This is an O(1) operation to return the last item on the list.  If
0706  * the list is not empty, a pointer to the last item in the list will
0707  * be returned.  Ownership of the item is transferred from the list to
0708  * the caller; no calls to PMIX_RETAIN() or PMIX_RELEASE() are invoked.
0709  *
0710  * This is an inlined function in compilers that support inlining, so
0711  * it's usually a cheap operation.
0712  */
0713 static inline pmix_list_item_t *pmix_list_remove_last(pmix_list_t *list)
0714 {
0715     /*  Removes, releases and returns last item on list.
0716         Caller now owns the item and should release the item
0717         when caller is done with it.
0718     */
0719     volatile pmix_list_item_t *item;
0720     if (0 == list->pmix_list_length) {
0721         return (pmix_list_item_t *) NULL;
0722     }
0723 
0724 #if PMIX_ENABLE_DEBUG
0725     /* Spot check: ensure that the first item is only on this list */
0726 
0727     assert(1 == list->pmix_list_sentinel.pmix_list_prev->pmix_list_item_refcount);
0728 #endif
0729 
0730     /* reset list length counter */
0731     list->pmix_list_length--;
0732 
0733     /* get item */
0734     item = (pmix_list_item_t*)list->pmix_list_sentinel.pmix_list_prev;
0735 
0736     /* reset previous pointer on next to last pointer */
0737     item->pmix_list_prev->pmix_list_next = item->pmix_list_next;
0738 
0739     /* reset tail's previous pointer */
0740     list->pmix_list_sentinel.pmix_list_prev = item->pmix_list_prev;
0741 
0742 #if PMIX_ENABLE_DEBUG
0743     assert(list == item->pmix_list_item_belong_to);
0744     item->pmix_list_next = item->pmix_list_prev = (pmix_list_item_t *) NULL;
0745 
0746     /* Spot check: ensure that the item we're returning is now on no
0747        lists */
0748 
0749     item->pmix_list_item_refcount -= 1;
0750     assert(0 == item->pmix_list_item_refcount);
0751     item->pmix_list_item_belong_to = NULL;
0752 #endif
0753 
0754     return (pmix_list_item_t *) item;
0755 }
0756 
0757 /**
0758  * Add an item to the list before a given element
0759  *
0760  * @param list The list container
0761  * @param pos List element to insert \c item before
0762  * @param item The item to insert
0763  *
0764  * Inserts \c item before \c pos.  This is an O(1) operation.
0765  */
0766 static inline void pmix_list_insert_pos(pmix_list_t *list, pmix_list_item_t *pos,
0767                                         pmix_list_item_t *item)
0768 {
0769 #if PMIX_ENABLE_DEBUG
0770     /* Spot check: ensure that the item we're insertting is currently
0771        not on any list */
0772 
0773     assert(0 == item->pmix_list_item_refcount);
0774     assert(NULL == item->pmix_list_item_belong_to);
0775 #endif
0776 
0777     /* point item at the existing elements */
0778     item->pmix_list_next = pos;
0779     item->pmix_list_prev = pos->pmix_list_prev;
0780 
0781     /* splice into the list */
0782     pos->pmix_list_prev->pmix_list_next = item;
0783     pos->pmix_list_prev = item;
0784 
0785     /* reset list length counter */
0786     list->pmix_list_length++;
0787 
0788 #if PMIX_ENABLE_DEBUG
0789     /* Spot check: double check that this item is only on the list
0790        that we just added it to */
0791 
0792     item->pmix_list_item_refcount += 1;
0793     assert(1 == item->pmix_list_item_refcount);
0794     item->pmix_list_item_belong_to = list;
0795 #endif
0796 }
0797 
0798 /**
0799  * Add an item to the list at a specific index location in the list.
0800  *
0801  * @param list The list container
0802  * @param item The item to insert
0803  * @param index Location to add the item
0804  *
0805  * @returns true if insertion succeeded; otherwise false
0806  *
0807  * This is potentially an O(N) operation to traverse down to the
0808  * correct location in the list and add an item.
0809  *
0810  * Example: if idx = 2 and list = item1->item2->item3->item4, then
0811  * after insert, list = item1->item2->item->item3->item4.
0812  *
0813  * If index is greater than the length of the list, no action is
0814  * performed and false is returned.
0815  */
0816 PMIX_EXPORT bool pmix_list_insert(pmix_list_t *list,
0817                                   pmix_list_item_t *item,
0818                                   long long idx);
0819 
0820 /**
0821  * Join a list into another list
0822  *
0823  * @param thislist List container for list being operated on
0824  * @param pos List item in \c thislist marking the position before
0825  *              which items are inserted
0826  * @param xlist List container for list being spliced from
0827  *
0828  * Join a list into another list.  All of the elements of \c xlist
0829  * are inserted before \c pos and removed from \c xlist.
0830  *
0831  * This operation is an O(1) operation.  Both \c thislist and \c
0832  * xlist must be valid list containsers.  \c xlist will be empty
0833  * but valid after the call.  All pointers to \c pmix_list_item_t
0834  * containers remain valid, including those that point to elements
0835  * in \c xlist.
0836  */
0837 PMIX_EXPORT void pmix_list_join(pmix_list_t *thislist,
0838                                 pmix_list_item_t *pos,
0839                                 pmix_list_t *xlist);
0840 
0841 /**
0842  * Splice a list into another list
0843  *
0844  * @param thislist List container for list being operated on
0845  * @param pos List item in \c thislist marking the position before
0846  *             which items are inserted
0847  * @param xlist List container for list being spliced from
0848  * @param first List item in \c xlist marking the start of elements
0849  *             to be copied into \c thislist
0850  * @param last List item in \c xlist marking the end of elements
0851  * to be copied into \c thislist
0852  *
0853  * Splice a subset of a list into another list.  The \c [first,
0854  * last) elements of \c xlist are moved into \c thislist,
0855  * inserting them before \c pos.  \c pos must be a valid iterator
0856  * in \c thislist and \c [first, last) must be a valid range in \c
0857  * xlist.  \c position must not be in the range \c [first, last).
0858  * It is, however, valid for \c xlist and \c thislist to be the
0859  * same list.
0860  *
0861  * This is an O(N) operation because the length of both lists must
0862  * be recomputed.
0863  */
0864 PMIX_EXPORT void pmix_list_splice(pmix_list_t *thislist,
0865                                   pmix_list_item_t *pos,
0866                                   pmix_list_t *xlist,
0867                                   pmix_list_item_t *first,
0868                                   pmix_list_item_t *last);
0869 
0870 /**
0871  * Comparison function for pmix_list_sort(), below.
0872  *
0873  * @param a Pointer to a pointer to an pmix_list_item_t.
0874  * Explanation below.
0875  * @param b Pointer to a pointer to an pmix_list_item_t.
0876  * Explanation below.
0877  * @retval 1 if \em a is greater than \em b
0878  * @retval 0 if \em a is equal to \em b
0879  * @retval 11 if \em a is less than \em b
0880  *
0881  * This function is invoked by qsort(3) from within
0882  * pmix_list_sort().  It is important to understand what
0883  * pmix_list_sort() does before invoking qsort, so go read that
0884  * documentation first.
0885  *
0886  * The important thing to realize here is that a and b will be \em
0887  * double pointers to the items that you need to compare.  Here's
0888  * a sample compare function to illustrate this point:
0889  */
0890 typedef int (*pmix_list_item_compare_fn_t)(pmix_list_item_t **a,
0891                                            pmix_list_item_t **b);
0892 
0893 /**
0894  * Sort a list with a provided compare function.
0895  *
0896  * @param list The list to sort
0897  * @param compare Compare function
0898  *
0899  * Put crassly, this function's complexity is O(N) + O(log(N)).
0900  * Its algorithm is:
0901  *
0902  * - remove every item from the list and put the corresponding
0903  *    (pmix_list_item_t*)'s in an array
0904  * - call qsort(3) with that array and your compare function
0905  * - re-add every element of the now-sorted array to the list
0906  *
0907  * The resulting list is now ordered.  Note, however, that since
0908  * an array of pointers is sorted, the comparison function must do
0909  * a double de-reference to get to the actual pmix_list_item_t (or
0910  * whatever the underlying type is).  See the documentation of
0911  * pmix_list_item_compare_fn_t for an example).
0912  */
0913 PMIX_EXPORT int pmix_list_sort(pmix_list_t *list,
0914                                pmix_list_item_compare_fn_t compare);
0915 
0916 END_C_DECLS
0917 
0918 #endif /* PMIX_LIST_H */