free_list.cpp
Go to the documentation of this file.
1 
2 /*********************************************************************
3 * Software License Agreement (BSD License)
4 *
5 * Copyright (c) 2010, Willow Garage, Inc.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
18 * * Neither the name of the Willow Garage nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *********************************************************************/
35 
36 #include <lockfree/free_list.h>
37 #include <allocators/aligned.h>
38 
39 using namespace ros;
40 
41 namespace lockfree
42 {
43 
44 FreeList::FreeList()
45 : blocks_(0)
46 , next_(0)
47 , block_size_(0)
48 , block_count_(0)
49 {
50 }
51 
52 FreeList::FreeList(uint32_t block_size, uint32_t block_count)
53 : blocks_(0)
54 , next_(0)
55 , block_size_(0)
56 , block_count_(0)
57 {
58  initialize(block_size, block_count);
59 }
60 
62 {
63  for (uint32_t i = 0; i < block_count_; ++i)
64  {
65  next_[i].~atomic_uint32_t();
66  }
67 
70 }
71 
72 void FreeList::initialize(uint32_t block_size, uint32_t block_count)
73 {
75  ROS_ASSERT(!next_);
76 
77  block_size_ = block_size;
78  block_count_ = block_count;
79 
80  head_.store(0);
81  alloc_count_.store(0);
82 
83  blocks_ = (uint8_t*)allocators::alignedMalloc(block_size * block_count, ROSRT_CACHELINE_SIZE);
85 
86  memset(blocks_, 0xCD, block_size * block_count);
87 
88  for (uint32_t i = 0; i < block_count_; ++i)
89  {
90  new (next_ + i) atomic_uint32_t();
91 
92  if (i == block_count_ - 1)
93  {
94  next_[i].store(0xffffffffUL);
95  }
96  else
97  {
98  next_[i].store(i + 1);
99  }
100  }
101 }
102 
104 {
105  return alloc_count_.load() == 0;
106 }
107 
109 {
110 #if FREE_LIST_DEBUG
111  initDebug();
112 #endif
113 
115 
116  while (true)
117  {
118  uint64_t head = head_.load(memory_order_consume);
119 
120 #if FREE_LIST_DEBUG
121  typename Debug::Item i;
122  i.head = head;
123  i.time = ros::WallTime::now();
124  i.op = Debug::Alloc;
125 #endif
126 
127  if (getVal(head) == 0xffffffffULL)
128  {
129 #if FREE_LIST_DEBUG
130  debug_->items.push_back(i);
131 #endif
132  return 0; // Allocation failed
133  }
134 
136 
137  // Load the next index
138  uint64_t new_head = next_[getVal(head)].load();
139 
141 
142  // Increment the tag to avoid ABA
143  setTag(new_head, getTag(head) + 1);
144 
145 #if FREE_LIST_DEBUG
146  i.new_head = new_head;
147 #endif
148 
150 
151  // If setting head to next is successful, return the item at next
152  if (head_.compare_exchange_strong(head, new_head))
153  {
154 #if FREE_LIST_DEBUG
155  i.addr = blocks_ + (block_size_ * getVal(head));
156  i.success = 1;
157  debug_->items.push_back(i);
158 #endif
159  alloc_count_.fetch_add(1);
160  return static_cast<void*>(blocks_ + (block_size_ * getVal(head)));
161  }
162 
163 #if FREE_LIST_DEBUG
164  i.success = 0;
165  debug_->items.push_back(i);
166 #endif
167  }
168 }
169 
170 void FreeList::free(void const* mem)
171 {
172  if (!mem)
173  {
174  return;
175  }
176 
177 #if FREE_LIST_DEBUG
178  initDebug();
179 #endif
180 
181  uint32_t index = (static_cast<uint8_t const*>(mem) - blocks_) / block_size_;
182 
183  ROS_ASSERT(((static_cast<uint8_t const*>(mem) - blocks_) % block_size_) == 0);
184  ROS_ASSERT(owns(mem));
185 
186  while (true)
187  {
188  // Load head
189  uint64_t head = head_.load(memory_order_consume);
190 
191 #if FREE_LIST_DEBUG
192  typename Debug::Item i;
193  i.head = head;
194  i.time = ros::WallTime::now();
195  i.op = Debug::Free;
196 #endif
197 
199 
200  uint64_t new_head = head;
201  // set new head to the index of the block we're currently freeing
202  setVal(new_head, index);
203  // Increment the tag to avoid ABA
204  setTag(new_head, getTag(new_head) + 1);
205 
206 
208 
209  // Store head as next index for this item
210  next_[index].store(getVal(head));
211 
213 
214 #if FREE_LIST_DEBUG
215  i.new_head = new_head;
216 #endif
217 
219 
220  // If setting the head to next is successful, return
221  if (head_.compare_exchange_strong(head, new_head))
222  {
223 #if FREE_LIST_DEBUG
224  i.success = 1;
225  i.addr = blocks_ + (block_size_ * index);
226  debug_->items.push_back(i);
227 #endif
228  alloc_count_.fetch_sub(1);
229  return;
230  }
231 
232 #if FREE_LIST_DEBUG
233  i.success = 0;
234  debug_->items.push_back(i);
235 #endif
236  }
237 }
238 
239 bool FreeList::owns(void const* mem)
240 {
241  uint32_t sub = (static_cast<uint8_t const*>(mem) - blocks_);
242  return sub < block_count_ * block_size_;
243 }
244 
245 } // namespace lockfree
246 
lockfree::FreeList::blocks_
uint8_t * blocks_
Definition: free_list.h:191
lockfree::FreeList::free
void free(void const *mem)
Free a block of memory allocated from this FreeList.
Definition: free_list.cpp:170
allocators::alignedMalloc
void * alignedMalloc(size_t size, size_t alignment)
ROSRT_CACHELINE_SIZE
#define ROSRT_CACHELINE_SIZE
Definition: free_list.h:46
lockfree::FreeList::getTag
uint32_t getTag(uint64_t val)
Definition: free_list.h:171
atomic_uint32_t
atomic< uint32_t > atomic_uint32_t
lockfree::FreeList::block_size_
uint32_t block_size_
Definition: free_list.h:196
ros
lockfree::FreeList::owns
bool owns(void const *mem)
Returns whether or not this FreeList owns a block of memory.
Definition: free_list.cpp:239
lockfree::FreeList::alloc_count_
ros::atomic_uint32_t alloc_count_
Definition: free_list.h:194
lockfree::FreeList::initialize
void initialize(uint32_t block_size, uint32_t block_count)
Initialize this FreeList. Only use if you used to default constructor.
Definition: free_list.cpp:72
memory_order_consume
memory_order_consume
lockfree::FreeList::~FreeList
~FreeList()
Definition: free_list.cpp:61
lockfree::FreeList::block_count_
uint32_t block_count_
Definition: free_list.h:197
lockfree::FreeList::head_
ros::atomic_uint64_t head_
Definition: free_list.h:193
allocators::alignedFree
void alignedFree(void *aligned)
ros::WallTime::now
static WallTime now()
FREELIST_DEBUG_YIELD
#define FREELIST_DEBUG_YIELD()
Definition: free_list.h:51
free_list.h
lockfree::FreeList::FreeList
FreeList()
Default constructor. You must call initialize() if you use this constructor.
Definition: free_list.cpp:44
lockfree::FreeList::allocate
void * allocate()
Allocate a single block from this FreeList.
Definition: free_list.cpp:108
lockfree::FreeList::setTag
void setTag(uint64_t &val, uint32_t tag)
Definition: free_list.h:181
lockfree::FreeList::setVal
void setVal(uint64_t &val, uint32_t v)
Definition: free_list.h:186
lockfree::FreeList::hasOutstandingAllocations
bool hasOutstandingAllocations()
Returns whether or not this FreeList currently has any outstanding allocations.
Definition: free_list.cpp:103
ROS_ASSERT
#define ROS_ASSERT(cond)
aligned.h
lockfree::FreeList::getVal
uint32_t getVal(uint64_t val)
Definition: free_list.h:176
lockfree::FreeList::next_
ros::atomic_uint32_t * next_
Definition: free_list.h:192
lockfree
Definition: free_list.h:54


lockfree
Author(s): Josh Faust
autogenerated on Wed Mar 2 2022 00:54:15