hazard_pointer.h 12.2 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
 *
 * 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_INTERNAL_HAZARD_POINTER_H_
#define EMBB_CONTAINERS_INTERNAL_HAZARD_POINTER_H_

#include <embb/base/atomic.h>
#include <embb/base/thread_specific_storage.h>
#include <embb/base/thread.h>
#include <embb/containers/wait_free_array_value_pool.h>
#include <embb/base/function.h>
#include <algorithm>

37
#if defined(EMBB_PLATFORM_COMPILER_MSVC)
38 39 40 41 42
#define EMBB_CONTAINERS_CPP_DEPENDANT_TYPENAME
#else
#define EMBB_CONTAINERS_CPP_DEPENDANT_TYPENAME typename
#endif

43 44 45 46 47 48 49 50 51 52
// forward declaration for white-box test, used in friend declaration of
// HazardPointer class.
namespace embb {
namespace containers {
namespace test {
class HazardPointerTest2;
}
}
}

53 54 55 56
namespace embb {
namespace containers {
namespace internal {
/**
57
 * This class contains a hazard pointer implementation following publication:
58
 *
59 60 61
 * Maged M. Michael. "Hazard pointers: Safe memory reclamation for lock-free
 * objects." IEEE Transactions on Parallel and Distributed Systems, 15.6 (2004)
 * : 491-504.
62
 *
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
 * Hazard pointers are a wait-free memory reclamation scheme for lock-free
 * algorithms. Loosely speaking, they act as garbage collector. The release of
 * objects contained within the memory, managed by the hazard pointer class, is
 * intercepted and possibly delayed to avoid concurrency bugs.
 *
 * Before accessing an object, threads announce their intention to do so (i.e.
 * the intention to dereference the respective pointer) to the hazard pointer
 * class. This is called guarding. From now on, the hazard pointer class will
 * prohibit the release or reuse of the guarded object. This is necessary, to
 * assure that the object is not released or reused while it is accessed and to
 * assure that it has not unnoticed changed (effectively avoiding the ABA
 * problem).
 *
 * Note that after guarding an object, a consecutive check that the object (i.e.
 * its pointer) is still valid is necessary; the object release could already
 * have been started when guarding the object. Guarding is repeated, until this
 * check eventually succeeds. Note that this "guard-and-check" loop makes the
 * usage of the hazard pointer class lock-free, even though its implementation
 * is wait-free.
 *
 * Internally, guarding is realized by providing each thread slots, where
 * pointers can be placed that should not be freed (so called guards). When
 * trying to release an object, it is checked if the object's pointer is
 * guarded, and if so this object is not released, but instead put into a
 * retired list for later release, when all guards for this object have been
 * removed.
 *
 * In contrast to the original implementation, our implementation consumes only
 * fixed-size memory. Note that the number of threads accessing the hazard
 * pointer object accounts quadratic for the memory consumption: managed objects
 * are provided from outside and the number of accessors accounts quadric for
 * the minimum count of those objects.
95
 *
96 97 98 99 100 101 102 103
 * Also in contrast to the original implementation, we do not provide a HelpScan
 * functionality, which gives threads the possibility, to not participate in the
 * garbage collection anymore: other threads will help to clean-up the objects
 * protected by the exiting thread. The reason is, that the only use-case would
 * be a crashing thread, not participating anymore. However, as the thread has
 * to signal its exit himself, this is not possible to realize anyways. In the
 * end, it is still guaranteed that all memory is properly returned (in the
 * destructor).
104
 *
105 106 107 108 109
 * Additionally, the original implementation holds a threshold, which determines
 * when objects shall be freed. In this implementation, we free whenever it is
 * possibly to do so, as we want to keep the memory footprint as low as
 * possible. We also don't see a performance drop in the current algorithms that
 * are using hazard pointers, when not using a threshold.
110
 *
111 112
 * \tparam GuardType the type of the guards. Usually the pointer type of some
 *         object to protect.
113 114
 */
template< typename GuardType >
115
class HazardPointer  {
116 117
 public:
  /**
118 119 120 121 122 123 124 125 126 127
   * The user of the hazard pointer class has to provide the memory that is
   * managed here. The user has to take into account, that releasing of memory
   * might be delayed. He has therefore to provide more memory than he wants to
   * guarantee at each point in time. More specific, on top of the guaranteed
   * count of objects, he has to provide the additional count of objects that
   * can be (worst-case) contained in the retired lists and therefore are not
   * released yet. The size sum of all retired lists is guardsPerThread *
   * accessorCount * accessorCount, which is computed using this function. So
   * the result of function denotes to the user, how many objects he has to
   * allocate additionally to the guaranteed count.
128
   *
129
   * \waitfree
130
   */
131 132 133 134 135 136 137 138 139
  static size_t ComputeMaximumRetiredObjectCount(
    size_t guardsPerThread,
      /**<[IN] the count of guards per thread*/
      int accessors = -1
      /**<[IN] Number of accessors. Determines, how many threads will access
               the hazard pointer object. Default value -1 will allow the
               maximum amount of threads as defined with
               \c embb::base::Thread::GetThreadsMaxCount()*/
      );
140 141

  /**
142
   * Initializes the hazard pointer object
143
   *
144
   * \notthreadsafe
145
   *
146
   * \memory We dynamically allocate the following:
147
   *
148 149 150
   * (sizeof(Atomic<int>) * accessors) + (sizeof(Atomic<GuardType>) *
   * guards_per_thread * accessors) + (2*sizeof(GuardType) *
   * guards_per_thread * accessors^2)
151
   *
152 153
   * The last addend is the dominant one, as accessorCount accounts
   * quadratically for it.
154
   */
155 156 157 158
  HazardPointer(
    embb::base::Function<void, GuardType> free_guard_callback,
    /**<[IN] Callback to the function that shall be called when a retired
             guard can be deleted */
159
    GuardType undefined_guard,
160
    /**<[IN] The guard value denoting "not guarded"*/
161
    int guards_per_thread,
162 163 164 165 166 167 168 169 170 171 172 173
    /**<[IN] Number of guards per thread*/
    int accessors = -1
    /**<[IN] Number of accessors. Determines, how many threads will access
              this hazard pointer object. Default value -1 will allow the
              maximum amount of threads as defined with
              \c embb::base::Thread::GetThreadsMaxCount()*/
    );

  /**
   * Deallocates internal data structures. Additionally releases all objects
   * currently held in the retired lists, using the release functor passed in
   * the constructor.
174
   *
175
   * \notthreadsafe
176
   */
177
  ~HazardPointer();
178 179

  /**
180 181 182 183 184 185
   * Guards \c to_guard. If the guarded_element is passed to \c EnqueueForDeletion
   * it is prevented from release from now on. The user must have a check, that
   * EnqueueForDeletion has not been called on to_guard, before the guarding took
   * effect.
   *
   * \waitfree
186
   */
187 188 189 190 191 192
  void Guard(
    int guard_position,
    /**<[IN] position to place guard*/
    GuardType to_guard
    /**<[IN] element to guard*/
    );
193

194
  /**
195 196 197 198
   * Enqueue guarded element for deletion. If not guarded, it is deleted
   * immediately. If it is guarded, it is added to a thread local retired list,
   * and deleted in a subsequent call to \c EnqueueForDeletion, when no guard is
   * placed on it anymore.
199
   */
200 201 202 203
  void EnqueueForDeletion(
    GuardType guarded_element
    /**<[IN] element to logically delete*/
    );
204

205
  /**
206 207 208
   * Explicitly remove guard from thread local slot.
   *
   * \waitfree
209
   */
210
  void RemoveGuard(int guard_position);
211

212 213
 private:
  /**
214 215
   * HazardPointerTest2 is a white-box test, needing access to private members
   * of this class. So declaring it as friend.
216
   */
217
  friend class embb::containers::test::HazardPointerTest2;
218 219

  /**
220 221 222 223 224
   * This number determines the amount of maximal accessors (threads) that
   * will access this hazard pointer instance. Note that a thread once
   * accessing this object will be permanently count as accessor, even if not
   * participating anymore. If too many threads access this object, an
   * exception is thrown.
225
   */
226
  unsigned int max_accessors_count_;
227 228

  /**
229
   * The guard value denoting "not guarded"
230
   */
231
  GuardType undefined_guard_;
232 233

  /**
234
   * The maximal count of guards that can be set per thread.
235
   */
236
  int max_guards_per_thread_;
237 238

  /**
239 240 241
   * The functor that is called to release an object. This is called by this
   * class, when it is safe to do so, i.e., no thread accesses this object
   * anymore.
242
   */
243
  embb::base::Function<void, GuardType> release_object_callback_;
244 245

  /**
246 247 248
   * Mapping from EMBB thread id to hazard pointer thread ids. Hazard pointer
   * thread ids are in range [0;accesor_count-1]. The position of a EMBB thread
   * id in that array determines the respective hazard pointer thread id.
249
   */
250
  embb::base::Atomic<int>* thread_id_mapping_;
251 252

  /**
253 254
   * The hazard pointer guards, represented as array. Each thread has a fixed
   * set of slots (guardsPerThread) within this array.
255
   */
256
  embb::base::Atomic<GuardType>* guards_;
257 258

  /**
259
   * \see threadLocalRetiredLists documentation
260
   */
261
  GuardType* thread_local_retired_lists_temp_;
262 263

  /**
264 265 266
   * A list of lists, represented as single array. Each thread maintains a list
   * of retired pointers, that are objects that are logically released but not
   * released because some thread placed a guard on it.
267
   */
268
  GuardType* thread_local_retired_lists_;
269 270

  /**
271 272 273 274 275 276 277
   * Each thread is assigned a thread index (starting with 0). Get the index of
   * the current thread. Note that this is not the global index, but an hazard
   * pointer class internal one. The user is free to define less accessors than
   * the amount of default threads. This is useful, as the number of accessors
   * accounts quadratic for the memory consumption, so the user should have the
   * possibility to avoid memory wastage when only having a small, fixed size,
   * number of accessors.
278
   *
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
   * @return current (hazard pointer object local) thread index
   */
  unsigned int GetObjectLocalThreadIndex();

  /**
   * Copy retired list \c sourceList to retired list \c targetList
   */
  static void CopyRetiredList(
    GuardType* source_list,
    /**<[IN] the source retired list*/
    GuardType* target_list,
    /**<[IN] the target retired list*/
    unsigned int single_retired_list_size,
    /**<[IN] the size of a thread local retired list*/
    GuardType undefined_guard
    /**<[IN] the undefined guard (usually the NULL pointer)*/
    );

  static void UpdateRetiredList(
    GuardType* retired_list,
    /**<[IN] the old retired list*/
    GuardType* updated_retired_list,
    /**<[IN] the updated retired list*/
    unsigned int retired_list_size,
    /**<[IN] the size of a thread local retired list*/
    GuardType to_retire,
    /**<[IN] the element to retire*/
    GuardType considered_hazard,
    /**<[IN] the currently considered hazard*/
    GuardType undefined_guard
    /**<[IN] the undefined guard (usually the NULL pointer)*/
    );
311 312 313 314 315 316 317 318
};
} // namespace internal
} // namespace containers
} // namespace embb

#include "./hazard_pointer-inl.h"

#endif  // EMBB_CONTAINERS_INTERNAL_HAZARD_POINTER_H_