wait_free_array_value_pool.h 8.51 KB
Newer Older
1
/*
Marcus Winter committed
2
 * Copyright (c) 2014-2016, Siemens AG. All rights reserved.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef EMBB_CONTAINERS_WAIT_FREE_ARRAY_VALUE_POOL_H_
#define EMBB_CONTAINERS_WAIT_FREE_ARRAY_VALUE_POOL_H_

#include <embb/base/atomic.h>
#include <embb/base/memory_allocation.h>

namespace embb {
namespace containers {
/**
 * \defgroup CPP_CONCEPTS_VALUE_POOL Value Pool Concept
 * Concept for thread-safe value pools
 *
 * \ingroup CPP_CONCEPT
 * \{
 * \par Description
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
 * A value pool is a multi-set of elements, where each element has a unique,
 * continuous (starting with 0) index. The elements cannot be modified and are
 * given at construction time by providing first/last iterators.
 *
 * \par
 * A value pool provides two primary operations: \c Allocate and \c Free. \c
 * Allocate allocates an element/index "pair" (index via return, element via
 * reference parameter) from the pool, and \c Free returns an element/index pair
 * to the pool. To guarantee linearizability, \c element is not allowed to be
 * modified between \c Allocate and \c Free. It is only allowed to free elements
 * that have previously been allocated. The \c Allocate function does not
 * guarantee an order on which indices are allocated. The count of elements that
 * can be allocated with \c Allocate might be smaller than the count of
 * elements, the pool is initialized with. This might be because of
 * implementation details and respective concurrency effects: for example, if
 * indices are managed within a queue, one has to protect queue elements from
 * concurrency effects (reuse and access). As long as a thread potentially
 * accesses a node (and with that an index), the respective index cannot not be
 * given out to the user, even if being logically not part of the pool anymore.
 * However, the user might want to guarantee a certain amount of indices to the
 * user. Therefore, the static \c GetMinimumElementCountForGuaranteedCapacity
 * method is used. The user passes the count of indices to this method, that
 * shall be guaranteed by the pool. The method returns the count on indices, the
 * pool has to be initialized with in order to guarantee this count on indices.
66 67 68
 *
 * \par Requirements
 * - Let \c Pool be the pool class
69 70 71
 * - Let \c Type be the element type of the pool. Atomic operations must be
 *   possible on \c Type.
 * - Let \c b, d be objects of type \c Type
72
 * - Let \c i, j be forward iterators supporting \c std::distance.
73
 * - Let \c c be an object of type \c Type&
74
 * - Let \c e be a value of type \c int
75
 * - Let \c f be a value of type \c int
76 77 78 79 80 81 82 83 84 85
 *
 * \par Valid Expressions
 *
 * <table>
 *   <tr>
 *     <th>Expression</th>
 *     <th>Return type</th>
 *     <th>Description</th>
 *   </tr>
 *   <tr>
86
 *     <td>\code{.cpp} Pool<Type, b>(i, j) \endcode
87 88 89
 *     </td>
 *     <td>Nothing</td>
 *     <td>
90 91 92
 *     Constructs a value pool holding elements of type \c Type, where \c b is
 *     the bottom element. The bottom element cannot be stored in the pool, it
 *     is exclusively used to mark empty cells. The pool initially contains
93
 *     \c std::distance(i, j) elements which are copied during construction from
94
 *     the range \c [i, j]. A concrete class satisfying the value pool concept
95 96 97 98 99 100 101
 *     might provide additional template parameters for specifying allocators.
 *     </td>
 *   </tr>
 *   <tr>
 *     <td>\code{.cpp} Allocate(c) \endcode</td>
 *     <td>\c int</td>
 *     <td>
102 103 104 105
 *     Allocates an element/index "pair" from the pool. Returns -1, if no
 *     element is available, i.e., the pool is empty. Otherwise, returns the
 *     index of the element in the pool. The value of the pool element is
 *     written into parameter reference \c c.
106 107 108 109 110 111 112 113 114 115
 *     </td>
 *   </tr>
 *   <tr>
 *     <td>\code{.cpp} Free(d, e) \endcode</td>
 *     <td>\c void</td>
 *     <td>Returns an element \c d to the pool, where \c e is its index. The
 *     values of \c d and \c e have to match the values of the previous call to
 *     \c Allocate. For each allocated element, \c Free must be called exactly
 *     once.</td>
 *   </tr>
116 117 118 119 120 121 122 123 124
 *   <tr>
 *     <td>\code{.cpp} GetMinimumElementCountForGuaranteedCapacity(f)
 *     \endcode</td>
 *     <td>\c void</td>
 *     <td>Static method, returns the count of indices, the user has to
 *     initialize the pool with in order to guarantee a count of \c f elements
 *     (irrespective of concurrency effects).
 *      </td>
 *   </tr>
125 126 127 128 129 130 131 132 133 134 135 136 137 138
 * </table>
 *
 * \}
 */

/**
 * Wait-free value pool using array construction
 *
 * \concept{CPP_CONCEPTS_VALUE_POOL}
 *
 * \ingroup CPP_CONTAINERS_POOLS
 *
 * \see LockFreeTreeValuePool
 *
139
 * \tparam Type Element type (must support atomic operations such as \c int).
140 141 142
 * \tparam Undefined Bottom element (cannot be stored in the pool)
 * \tparam Allocator Allocator used to allocate the pool array
 */
143 144 145
template<typename Type,
  Type Undefined,
  class Allocator = embb::base::Allocator< embb::base::Atomic<Type> > >
146 147
class WaitFreeArrayValuePool {
 private:
148 149
  int size_;
  embb::base::Atomic<Type>* pool_array_;
150
  WaitFreeArrayValuePool();
151
  Allocator allocator_;
152 153 154 155 156 157 158 159 160 161 162

  // Prevent copy-construction
  WaitFreeArrayValuePool(const WaitFreeArrayValuePool&);

  // Prevent assignment
  WaitFreeArrayValuePool& operator=(const WaitFreeArrayValuePool&);

 public:
  /**
   * Constructs a pool and fills it with the elements in the specified range.
   *
163
   * \memory Dynamically allocates <tt>n*sizeof(embb::base::Atomic<Type>)</tt>
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
   *         bytes, where <tt>n = std::distance(first, last)</tt> is the number
   *         of pool elements.
   *
   * \notthreadsafe
   *
   * \see CPP_CONCEPTS_VALUE_POOL
   */
  template<typename ForwardIterator>
  WaitFreeArrayValuePool(
    ForwardIterator first,
    /**< [IN] Iterator pointing to the first element of the range the pool is
              filled with */
    ForwardIterator last
    /**< [IN] Iterator pointing to the last plus one element of the range the
              pool is filled with */
  );

  /**
182 183 184 185 186 187 188 189 190 191 192 193
   * Due to concurrency effects, a pool might provide less elements than managed
   * by it. However, usually one wants to guarantee a minimal capacity. The
   * count of elements, that must be given to the pool when to guarantee \c
   * capacity elements is computed using this function.
   *
   * \return count of indices the pool has to be initialized with
   */
  static size_t GetMinimumElementCountForGuaranteedCapacity(
    size_t capacity
    /**< [IN] count of indices that shall be guaranteed */);

  /**
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
   * Destructs the pool.
   *
   * \notthreadsafe
   */
  ~WaitFreeArrayValuePool();

  /**
   * Allocates an element from the pool.
   *
   * \return Index of the element if the pool is not empty, otherwise \c -1.
   *
   * \waitfree
   *
   * \see CPP_CONCEPTS_VALUE_POOL
   */
  int Allocate(
210
    Type & element
211 212 213 214 215 216 217 218
    /**< [IN,OUT] Reference to the allocated element. Unchanged, if the
                  operation was not successful. */
  );

  /**
   * Returns an element to the pool.
   *
   * \note The element must have been allocated with Allocate().
219
   *
220 221 222 223 224
   * \waitfree
   *
   * \see CPP_CONCEPTS_VALUE_POOL
   */
  void Free(
225
    Type element,
226 227 228 229 230 231 232 233 234 235 236
    /**< [IN] Element to be returned to the pool */
    int index
    /**< [IN] Index of the element as obtained by Allocate() */
  );
};
} // namespace containers
} // namespace embb

#include <embb/containers/internal/wait_free_array_value_pool-inl.h>

#endif  // EMBB_CONTAINERS_WAIT_FREE_ARRAY_VALUE_POOL_H_