source: finroc_plugins_data_ports/common/tPortBufferPool.h @ 136:c3e65240f9fd

14.08
Last change on this file since 136:c3e65240f9fd was 136:c3e65240f9fd, checked in by Max Reichardt <max.reichardt@…>, 12 months ago

Fixes subtle memory issue on shutdown: Makes port buffer pools always initially add an unused buffer to pool if underlying buffer pool class requires an unused buffer for safe deleting (before, inward-connected input proxy ports (standard implementation) with their initial data buffer still assigned would cause a memory error on deletion).

File size: 8.3 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 modify
8// it under the terms of the GNU General Public License as published by
9// the Free Software Foundation; either version 2 of the License, or
10// (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 along
18// with this program; if not, write to the Free Software Foundation, Inc.,
19// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20//
21//----------------------------------------------------------------------
22/*!\file    plugins/data_ports/common/tPortBufferPool.h
23 *
24 * \author  Max Reichardt
25 *
26 * \date    2012-10-30
27 *
28 * \brief   Contains tPortBufferPool
29 *
30 * \b tPortBufferPool
31 *
32 * Pool of buffers used in ports - for a specific data type.
33 *
34 */
35//----------------------------------------------------------------------
36#ifndef __plugins__data_ports__common__tPortBufferPool_h__
37#define __plugins__data_ports__common__tPortBufferPool_h__
38
39//----------------------------------------------------------------------
40// External includes (system with <>, local with "")
41//----------------------------------------------------------------------
42#include "rrlib/buffer_pools/tBufferPool.h"
43#include "rrlib/rtti/rtti.h"
44#include "core/definitions.h"
45#include "core/internal/tGarbageDeleter.h"
46
47//----------------------------------------------------------------------
48// Internal includes with ""
49//----------------------------------------------------------------------
50#include "plugins/data_ports/common/tAbstractPortBufferManager.h"
51#include "plugins/data_ports/optimized/cheaply_copied_types.h"
52
53//----------------------------------------------------------------------
54// Namespace declaration
55//----------------------------------------------------------------------
56namespace finroc
57{
58namespace data_ports
59{
60namespace common
61{
62
63//----------------------------------------------------------------------
64// Forward declarations / typedefs / enums
65//----------------------------------------------------------------------
66
67//----------------------------------------------------------------------
68// Class declaration
69//----------------------------------------------------------------------
70//! Port buffer pool
71/*!
72 * Pool of buffers used in ports - for a specific data type.
73 *
74 * In order to be real-time-capable, enough buffers need to be allocated initially...
75 * otherwise the application becomes real-time-capable later - after enough buffers
76 * have been allocated.
77 *
78 * \tparam TBufferManager Buffer manager type (derived from tAbstractPortBufferManager)
79 * \tparam CONCURRENCY specifies if threads can return (write) and retrieve (read) buffers from the pool concurrently.
80 */
81template <typename TBufferManager, rrlib::concurrent_containers::tConcurrency CONCURRENCY>
82class tPortBufferPool : private rrlib::util::tNoncopyable
83{
84
85  /*!
86   * As buffers (at least their management information (reference counter etc.))
87   * could be accessed by a thread while it is returned to possibly deleted pool -
88   * deleting of these buffers should happen when its safe.
89   * Therefore, this deleter passes them to tGarbageDeleter.
90   */
91  struct tPortBufferDeleter
92  {
93    void operator()(TBufferManager* p) const
94    {
95      core::internal::tGarbageDeleter::DeleteDeferred<TBufferManager>(p);
96    }
97  };
98
99  typedef rrlib::buffer_pools::tBufferPool < TBufferManager, CONCURRENCY, rrlib::buffer_pools::management::QueueBased,
100          rrlib::buffer_pools::deleting::ComplainOnMissingBuffers, rrlib::buffer_pools::recycling::UseOwnerStorageInBuffer,
101          tPortBufferDeleter > tBufferPoolSingleThreaded;
102
103  typedef rrlib::buffer_pools::tBufferPool < TBufferManager, CONCURRENCY, rrlib::buffer_pools::management::QueueBased,
104          rrlib::buffer_pools::deleting::CollectGarbage, rrlib::buffer_pools::recycling::UseOwnerStorageInBuffer,
105          tPortBufferDeleter > tBufferPoolConcurrent;
106
107  /*! Type of wrapped buffer pool */
108  typedef typename std::conditional < CONCURRENCY == rrlib::concurrent_containers::tConcurrency::NONE,
109          tBufferPoolSingleThreaded, tBufferPoolConcurrent >::type tBufferPool;
110
111//----------------------------------------------------------------------
112// Public methods and typedefs
113//----------------------------------------------------------------------
114public:
115
116  /*! std::unique_ptr returned by this class that will automatically recycle buffer when out of scope */
117  typedef typename tBufferPool::tPointer tPointer;
118
119  /*!
120   * \param data_type Type of buffers in pool
121   * \param intial_size Number of buffer to allocate initially
122   */
123  tPortBufferPool(const rrlib::rtti::tType& data_type, int initial_size) :
124    buffer_pool()
125  {
126    AllocateAdditionalBuffers(data_type, std::max<size_t>(initial_size, tBufferPool::MinUnusedBuffersRequired()));
127  }
128
129  tPortBufferPool() : buffer_pool()
130  {}
131
132  /*!
133   * Allocates the specified number of additional buffers and adds them to pool
134   *
135   * \param data_type Data type of buffers to add
136   * \param count Number of buffers to allocate and add
137   */
138  inline void AllocateAdditionalBuffers(const rrlib::rtti::tType& data_type, size_t count)
139  {
140    for (size_t i = 0; i < count; i++)
141    {
142      CreateBuffer(data_type);
143    }
144  }
145
146//  /*!
147//   * \return Data Type of buffers in pool
148//   */
149//  inline rrlib::rtti::tType GetDataType() const
150//  {
151//    return data_type;
152//  }
153
154  /*!
155   * \param cheaply_copyable_type_index Index of 'cheaply copied' data type of pool
156   * \return Returns unused buffer. If there are no buffers that can be reused, a new buffer is allocated.
157   */
158  inline tPointer GetUnusedBuffer(uint32_t cheaply_copyable_type_index)
159  {
160    tPointer buffer = buffer_pool.GetUnusedBuffer();
161    if (buffer)
162    {
163      return std::move(buffer);
164    }
165    return CreateBuffer(optimized::GetType(cheaply_copyable_type_index));
166  }
167
168  /*!
169   * \param data_type Data type of buffers in this pool
170   * \param possibly_create_buffer Create new buffer if there is none in pool at the moment?
171   * \return Returns unused buffer. If there are no buffers that can be reused, a new buffer is possibly allocated.
172   */
173  inline tPointer GetUnusedBuffer(const rrlib::rtti::tType& data_type, bool possibly_create_buffer = true)
174  {
175    tPointer buffer = buffer_pool.GetUnusedBuffer();
176    if (buffer)
177    {
178      return std::move(buffer);
179    }
180    return possibly_create_buffer ? CreateBuffer(data_type) : tPointer();
181  }
182
183  /*!
184   * \return Returns internal buffer management backend for special manual tweaking of buffer pool.
185   */
186  typename tBufferPool::tBufferManagement& InternalBufferManagement()
187  {
188    return buffer_pool.InternalBufferManagement();
189  }
190
191//----------------------------------------------------------------------
192// Private fields and methods
193//----------------------------------------------------------------------
194private:
195
196  /*! Data Type of buffers in pool */
197  //const rrlib::rtti::tType data_type;  This information would be redundant
198
199  /*! Wrapped buffer pool */
200  tBufferPool buffer_pool;
201
202
203  /*
204   * \param data_type Data type of buffers in this pool
205   * \return Create new buffer/instance of port data and add to pool
206   */
207  tPointer CreateBuffer(const rrlib::rtti::tType& data_type)
208  {
209    std::unique_ptr<TBufferManager> new_buffer(TBufferManager::CreateInstance(data_type));
210
211    // In case we have a string: allocate a certain buffer size (for RT capabilities with smaller payload) -
212    // We do not need this check for 'cheaply copied' types - therefore the concurrency condition
213    if (CONCURRENCY != rrlib::concurrent_containers::tConcurrency::NONE && new_buffer->GetObject().GetType().GetRttiName() == typeid(tString).name())
214    {
215      static_cast<rrlib::rtti::tGenericObject&>(new_buffer->GetObject()).GetData<tString>().reserve(512);  // TODO: move to parameter in some config.h
216    }
217    return buffer_pool.AddBuffer(std::move(new_buffer));
218  }
219
220};
221
222//----------------------------------------------------------------------
223// End of namespace declaration
224//----------------------------------------------------------------------
225}
226}
227}
228
229#endif
Note: See TracBrowser for help on using the repository browser.