source: finroc_plugins_data_ports/common/tReferenceCountingBufferManager.h @ 41:eb5957b12387

Last change on this file since 41:eb5957b12387 was 19:6e4d6cc5bc07, checked in by Max Reichardt <mreichardt@…>, 7 years ago

Fixed GetContentString() method in tAbstractPortBufferManager

File size: 7.2 KB
Line 
1//
2// You received this file as part of Finroc
3// A Framework for intelligent robot control
4//
5// Copyright (C) Finroc GbR (finroc.org)
6//
7// This program is free software; you can redistribute it and/or
8// modify it under the terms of the GNU General Public License
9// as published by the Free Software Foundation; either version 2
10// of the License, or (at your option) any later version.
11//
12// This program is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with this program; if not, write to the Free Software
19// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20//
21//----------------------------------------------------------------------
22/*!\file    plugins/data_ports/common/tReferenceCountingBufferManager.h
23 *
24 * \author  Max Reichardt
25 *
26 * \date    2012-11-03
27 *
28 * \brief   Contains tReferenceCountingBufferManager
29 *
30 * \b tReferenceCountingBufferManager
31 *
32 * This class manages a single port buffer.
33 * It handles information on locks, data type, timestamp etc.
34 *
35 */
36//----------------------------------------------------------------------
37#ifndef __plugins__data_ports__common__tReferenceCountingBufferManager_h__
38#define __plugins__data_ports__common__tReferenceCountingBufferManager_h__
39
40//----------------------------------------------------------------------
41// External includes (system with <>, local with "")
42//----------------------------------------------------------------------
43#include "core/log_messages.h"
44
45//----------------------------------------------------------------------
46// Internal includes with ""
47//----------------------------------------------------------------------
48#include "plugins/data_ports/common/tAbstractPortBufferManager.h"
49
50//----------------------------------------------------------------------
51// Namespace declaration
52//----------------------------------------------------------------------
53namespace finroc
54{
55namespace data_ports
56{
57namespace common
58{
59
60//----------------------------------------------------------------------
61// Forward declarations / typedefs / enums
62//----------------------------------------------------------------------
63
64//----------------------------------------------------------------------
65// Class declaration
66//----------------------------------------------------------------------
67//! Manages a port buffer using a concurrent reference and reuse counter.
68/*!
69 * This class manages a single port buffer.
70 * It handles information on locks, data type, timestamp etc.
71 */
72class tReferenceCountingBufferManager : public tAbstractPortBufferManager<rrlib::concurrent_containers::tQueueability::FULL_OPTIMIZED>
73{
74
75//----------------------------------------------------------------------
76// Public methods and typedefs
77//----------------------------------------------------------------------
78public:
79
80  /*!
81   * Mask for lowest bits from reuse counter to use in port pointer tag
82   * order to avoid the ABA problem
83   */
84  enum { cTAG_MASK = 0x7 };
85  enum { cREUSE_COUNTER_MASK = 0xFFFF };
86
87  /*!
88   * Adds Locks
89   *
90   * \param locks_to_add number of locks to add
91   * \return current pointer tag
92   */
93  inline int AddLocks(int locks_to_add)
94  {
95    return reference_and_reuse_counter.fetch_add(locks_to_add << 16) & cTAG_MASK;
96  }
97
98  /*!
99   * Adds Locks
100   *
101   * \param locks_to_add number of locks to add
102   * \param check_tag Check that reference counter tag is still this specified value
103   */
104  inline void AddLocks(int locks_to_add, int check_tag)
105  {
106    __attribute__((unused)) int old_value = reference_and_reuse_counter.fetch_add(locks_to_add << 16);
107    assert((old_value & cTAG_MASK) == check_tag && "corrupted tag detected");
108  }
109
110  /*!
111   * \return Pointer tag to use with curent reference counter
112   */
113  inline int GetPointerTag() const
114  {
115    return reference_and_reuse_counter.load() & cTAG_MASK;
116  }
117
118  /*!
119   * Initializes reference counter for next use (set tag etc.)
120   *
121   * \param initial_number_of_locks Set reference counter to this value initially
122   * \return Pointer tag to use for this buffer publishing operation
123   */
124  inline int InitReferenceCounter(int initial_number_of_locks)
125  {
126    int new_use_count = (reference_and_reuse_counter.load() + 1) & cREUSE_COUNTER_MASK;
127    reference_and_reuse_counter.store((initial_number_of_locks << 16) | new_use_count);
128    return new_use_count & cTAG_MASK;
129  }
130
131  /*!
132   * Releases locks
133   *
134   * \param locks_to_release number of locks to release
135   * \return Previous reference_and_reuse_counter value (only meant for class-internal use)
136   */
137  template <typename TDeleterType, typename TThis = tReferenceCountingBufferManager>
138  inline int ReleaseLocks(int locks_to_release)
139  {
140    int old_value = reference_and_reuse_counter.fetch_sub(locks_to_release << 16);
141    int old_counter = old_value >> 16;
142    assert(old_counter - locks_to_release >= 0 && "negative reference counter detected");
143    if (old_counter - locks_to_release == 0)
144    {
145      TDeleterType deleter;
146      deleter(static_cast<TThis*>(this));
147    }
148    //FINROC_LOG_PRINT(DEBUG, "Locks Left ", (old_counter - locks_to_release), " ", this, " ", GetContentString());
149    return old_value;
150  }
151
152  /*!
153   * Releases locks
154   *
155   * \param locks_to_release number of locks to release
156   * \param check_tag Check that reference counter tag is still this specified value
157   */
158  template <typename TDeleterType, typename TThis = tReferenceCountingBufferManager>
159  inline void ReleaseLocks(int locks_to_release, int check_tag)
160  {
161    __attribute__((unused)) int old_value = ReleaseLocks<TDeleterType, TThis>(locks_to_release);
162    assert((old_value & cTAG_MASK) == check_tag && "corrupted tag detected");
163  }
164
165  /*!
166   * Try to lock port buffer manager
167   * Will only succeed if number of locks is greater than zero
168   * and pointer tag matches
169   *
170   * \return Returns whether locking succeeded
171   */
172  inline bool TryLock(int locks_to_add, int pointer_tag)
173  {
174    int current_value = reference_and_reuse_counter.load();
175    while (((current_value >> 16) > 0) && (current_value & cTAG_MASK) == pointer_tag)
176    {
177      int new_value = current_value + (locks_to_add << 16);
178      if (reference_and_reuse_counter.compare_exchange_strong(current_value, new_value))
179      {
180        return true;
181      }
182    }
183    return false;
184  }
185
186  /*!
187   * \return True, if reference counter is one (aka manager is only referenced by one ("this") pointer)
188   */
189  bool Unique() const
190  {
191    return (reference_and_reuse_counter.load() >> 16) == 1;
192  }
193
194//----------------------------------------------------------------------
195// Protected fields and methods
196//----------------------------------------------------------------------
197protected:
198
199  /*! Upper 16 bit: reference counter - lower 16 bit: reuse counter */
200  std::atomic<int> reference_and_reuse_counter;
201
202
203  tReferenceCountingBufferManager() : reference_and_reuse_counter(0) {}
204
205};
206
207//----------------------------------------------------------------------
208// End of namespace declaration
209//----------------------------------------------------------------------
210}
211}
212}
213
214
215#endif
Note: See TracBrowser for help on using the repository browser.