µOS++ IIIe Reference  v6.3.15
“Perfekt ist nicht gut genug”
The third edition of µOS++, a POSIX inspired open source system, written in C++.
lifo.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the µOS++ distribution.
3  * (https://github.com/micro-os-plus)
4  * Copyright (c) 2016 Liviu Ionescu.
5  *
6  * Permission is hereby granted, free of charge, to any person
7  * obtaining a copy of this software and associated documentation
8  * files (the "Software"), to deal in the Software without
9  * restriction, including without limitation the rights to use,
10  * copy, modify, merge, publish, distribute, sublicense, and/or
11  * sell copies of the Software, and to permit persons to whom
12  * the Software is furnished to do so, subject to the following
13  * conditions:
14  *
15  * The above copyright notice and this permission notice shall be
16  * included in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25  * OTHER DEALINGS IN THE SOFTWARE.
26  */
27 
28 #include <cmsis-plus/memory/lifo.h>
29 #include <memory>
30 
31 // ----------------------------------------------------------------------------
32 
33 namespace os
34 {
35  namespace memory
36  {
37 
38  // ========================================================================
39 
44  {
45  trace::printf ("lifo::%s() @%p %s\n", __func__, this, this->name ());
46  }
47 
48 #pragma GCC diagnostic push
49 // Needed because 'alignment' is used only in trace calls.
50 #pragma GCC diagnostic ignored "-Wunused-parameter"
51 
76  void*
77  lifo::do_allocate (std::size_t bytes, std::size_t alignment)
78  {
79  std::size_t block_padding = calc_block_padding (alignment);
80  std::size_t alloc_size = rtos::memory::align_size (bytes, chunk_align);
81  alloc_size += block_padding;
82  alloc_size += chunk_offset;
83 
84  std::size_t block_minchunk = calc_block_minchunk (block_padding);
85  alloc_size = os::rtos::memory::max (alloc_size, block_minchunk);
86 
87  chunk_t* chunk = nullptr;
88 
89  while (true)
90  {
91  // Allocate only from the first block and only if it is
92  // the really first in the arena; this prevents fragmentation.
93  if (free_list_ == reinterpret_cast<chunk_t*> (arena_addr_))
94  {
95  chunk = free_list_;
96 
97  int rem = static_cast<int> (chunk->size - alloc_size);
98  if (rem >= 0)
99  {
100  if ((static_cast<std::size_t> (rem)) >= block_minchunk)
101  {
102  // If the chunk is larger than needed
103  // (at least one more chunk is available);
104  // break it into two chunks and return the top one.
105 
106  // Shrink bottom chunk to remaining size.
107  chunk->size = static_cast<std::size_t> (rem);
108 
109  // Compute where top chunk starts.
110  chunk =
111  reinterpret_cast<chunk_t *> (reinterpret_cast<char *> (chunk)
112  + rem);
113  chunk->size = alloc_size;
114 
115  // Splitting one chunk creates one more chunk.
116  ++free_chunks_;
117  }
118  else
119  {
120  // Found a chunk that is exactly the size or slightly
121  // larger than the requested size; return this chunk.
122 
123  // Always at the list head.
124  // The next chunk becomes the first list element.
125  free_list_ = chunk->next;
126 
127  // If this was the last chunk, the free list is empty.
128  }
129  }
130  }
131 
132  if (chunk != nullptr)
133  {
134  break;
135  }
136 
137  if (out_of_memory_handler_ == nullptr)
138  {
139 #if defined(OS_TRACE_LIBCPP_MEMORY_RESOURCE)
140  trace::printf ("lifo::%s(%u,%u)=0 @%p %s\n", __func__, bytes,
141  alignment, this, this->name ());
142 #endif
143 
144  return nullptr;
145  }
146 
147 #if defined(OS_TRACE_LIBCPP_MEMORY_RESOURCE)
148  trace::printf ("lifo::%s(%u,%u) @%p %s out of memory\n", __func__,
149  bytes, alignment, this, this->name ());
150 #endif
151  out_of_memory_handler_ ();
152 
153  // If the handler returned, assume it freed some memory
154  // and try again to allocate.
155  }
156 
157  void* aligned_payload = internal_align_ (chunk, bytes, alignment);
158 
159 #if defined(OS_TRACE_LIBCPP_MEMORY_RESOURCE)
160  trace::printf ("lifo::%s(%u,%u)=%p,%u @%p %s\n", __func__, bytes,
161  alignment, aligned_payload, alloc_size, this, name ());
162 #endif
163 
164  return aligned_payload;
165  }
166 
167 #pragma GCC diagnostic pop
168 
169  // --------------------------------------------------------------------------
170  } /* namespace memory */
171 } /* namespace os */
172 
173 // ----------------------------------------------------------------------------
constexpr std::size_t max(std::size_t a, std::size_t b)
Definition: os-memory.h:74
virtual void * do_allocate(std::size_t bytes, std::size_t alignment) override
Implementation of the memory allocator.
Definition: lifo.cpp:77
void * internal_align_(chunk_t *chunk, std::size_t bytes, std::size_t alignment)
Internal function to align a chunk.
System namespace.
constexpr std::size_t align_size(std::size_t size, std::size_t align) noexcept
Helper function to align size values.
Definition: os-memory.h:86
const char * name(void) const
Get object name.
Definition: os-decls.h:760
int printf(const char *format,...)
Write a formatted string to the trace device.
Definition: trace.cpp:74
virtual ~lifo() override
Destruct the memory resource object instance.
Definition: lifo.cpp:43