µOS++ IIIe Reference 7.0.0
The third edition of µOS++, a POSIX inspired open source framework, written in C++
Loading...
Searching...
No Matches
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
29#include <memory>
30
31// ----------------------------------------------------------------------------
32
33#if defined(__clang__)
34#pragma clang diagnostic ignored "-Wc++98-compat"
35#endif
36
37// ----------------------------------------------------------------------------
38
39namespace os
40{
41 namespace memory
42 {
43
44 // ========================================================================
45
47 {
48 trace::printf ("lifo::%s() @%p %s\n", __func__, this, this->name ());
49 }
50
51#pragma GCC diagnostic push
52// Needed because 'alignment' is used only in trace calls.
53#pragma GCC diagnostic ignored "-Wunused-parameter"
54
79 void*
80 lifo::do_allocate (std::size_t bytes, std::size_t alignment)
81 {
82 std::size_t block_padding = calc_block_padding (alignment);
83 std::size_t alloc_size = rtos::memory::align_size (bytes, chunk_align);
84 alloc_size += block_padding;
85 alloc_size += chunk_offset;
86
87 std::size_t block_minchunk = calc_block_minchunk (block_padding);
88 alloc_size = os::rtos::memory::max (alloc_size, block_minchunk);
89
90 chunk_t* chunk = nullptr;
91
92 while (true)
93 {
94 // Allocate only from the first block and only if it is
95 // the really first in the arena; this prevents fragmentation.
96 if (free_list_ == reinterpret_cast<chunk_t*> (arena_addr_))
97 {
98 chunk = free_list_;
99
100 int rem = static_cast<int> (chunk->size - alloc_size);
101 if (rem >= 0)
102 {
103 if ((static_cast<std::size_t> (rem)) >= block_minchunk)
104 {
105 // If the chunk is larger than needed
106 // (at least one more chunk is available);
107 // break it into two chunks and return the top one.
108
109 // Shrink bottom chunk to remaining size.
110 chunk->size = static_cast<std::size_t> (rem);
111
112 // Compute where top chunk starts.
113 chunk =
114 reinterpret_cast<chunk_t *> (reinterpret_cast<char *> (chunk)
115 + rem);
116 chunk->size = alloc_size;
117
118 // Splitting one chunk creates one more chunk.
119 ++free_chunks_;
120 }
121 else
122 {
123 // Found a chunk that is exactly the size or slightly
124 // larger than the requested size; return this chunk.
125
126 // Always at the list head.
127 // The next chunk becomes the first list element.
128 free_list_ = chunk->next;
129
130 // If this was the last chunk, the free list is empty.
131 }
132 }
133 }
134
135 if (chunk != nullptr)
136 {
137 break;
138 }
139
140 if (out_of_memory_handler_ == nullptr)
141 {
142#if defined(OS_TRACE_LIBCPP_MEMORY_RESOURCE)
143 trace::printf ("lifo::%s(%u,%u)=0 @%p %s\n", __func__, bytes,
144 alignment, this, this->name ());
145#endif
146
147 return nullptr;
148 }
149
150#if defined(OS_TRACE_LIBCPP_MEMORY_RESOURCE)
151 trace::printf ("lifo::%s(%u,%u) @%p %s out of memory\n", __func__,
152 bytes, alignment, this, this->name ());
153#endif
154 out_of_memory_handler_ ();
155
156 // If the handler returned, assume it freed some memory
157 // and try again to allocate.
158 }
159
160 void* aligned_payload = internal_align_ (chunk, bytes, alignment);
161
162#if defined(OS_TRACE_LIBCPP_MEMORY_RESOURCE)
163 trace::printf ("lifo::%s(%u,%u)=%p,%u @%p %s\n", __func__, bytes,
164 alignment, aligned_payload, alloc_size, this, name ());
165#endif
166
167 return aligned_payload;
168 }
169
170#pragma GCC diagnostic pop
171
172 // --------------------------------------------------------------------------
173 } /* namespace memory */
174} /* namespace os */
175
176// ----------------------------------------------------------------------------
void * internal_align_(chunk_t *chunk, std::size_t bytes, std::size_t alignment)
Internal function to align a chunk.
virtual ~lifo() override
Destruct the memory resource object instance.
Definition lifo.cpp:46
virtual void * do_allocate(std::size_t bytes, std::size_t alignment) override
Implementation of the memory allocator.
Definition lifo.cpp:80
const char * name(void) const
Get object name.
Definition os-decls.h:774
int printf(const char *format,...)
Write a formatted string to the trace device.
Definition trace.cpp:74
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:97
constexpr std::size_t max(std::size_t a, std::size_t b)
Definition os-memory.h:85
System namespace.