source: mainline/kernel/generic/src/mm/malloc.c@ fdc190f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since fdc190f was fdc190f, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

Split realloc()

  • Property mode set to 100644
File size: 6.0 KB
Line 
1/*
2 * Copyright (c) 2006 Ondrej Palkovsky
3 * Copyright (c) 2018 Jiří Zárevúcky
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <stdalign.h>
31#include <stddef.h>
32#include <stdlib.h>
33#include <align.h>
34#include <bitops.h>
35#include <mm/slab.h>
36#include <mem.h>
37#include <main/main.h> // malloc_init()
38
39/** Minimum size to be allocated by malloc */
40#define SLAB_MIN_MALLOC_W 4
41
42/** Maximum size to be allocated by malloc */
43#define SLAB_MAX_MALLOC_W 22
44
45/** Caches for malloc */
46static slab_cache_t *malloc_caches[SLAB_MAX_MALLOC_W - SLAB_MIN_MALLOC_W + 1];
47
48static const char *malloc_names[] = {
49 "malloc-16",
50 "malloc-32",
51 "malloc-64",
52 "malloc-128",
53 "malloc-256",
54 "malloc-512",
55 "malloc-1K",
56 "malloc-2K",
57 "malloc-4K",
58 "malloc-8K",
59 "malloc-16K",
60 "malloc-32K",
61 "malloc-64K",
62 "malloc-128K",
63 "malloc-256K",
64 "malloc-512K",
65 "malloc-1M",
66 "malloc-2M",
67 "malloc-4M"
68};
69
70void malloc_init(void)
71{
72 /* Initialize structures for malloc */
73 size_t i;
74 size_t size;
75
76 for (i = 0, size = (1 << SLAB_MIN_MALLOC_W);
77 i < (SLAB_MAX_MALLOC_W - SLAB_MIN_MALLOC_W + 1);
78 i++, size <<= 1) {
79 malloc_caches[i] = slab_cache_create(malloc_names[i], size, 0,
80 NULL, NULL, SLAB_CACHE_MAGDEFERRED);
81 }
82}
83
84static inline bool _is_pow2(size_t x)
85{
86 return (x & (x - 1)) == 0;
87}
88
89static void _check_sizes(size_t *alignment, size_t *size)
90{
91 assert(size);
92 assert(alignment);
93
94 /* Force size to be nonzero. */
95 if (*size == 0)
96 *size = 1;
97
98 /* Alignment must be a power of 2. */
99 assert(_is_pow2(*alignment));
100 assert(*alignment <= PAGE_SIZE);
101
102 if (*alignment < alignof(max_align_t))
103 *alignment = alignof(max_align_t);
104
105 *size = ALIGN_UP(*size, *alignment);
106
107 if (*size < (1 << SLAB_MIN_MALLOC_W))
108 *size = (1 << SLAB_MIN_MALLOC_W);
109}
110
111static slab_cache_t *cache_for_size(size_t size)
112{
113 assert(size > 0);
114 assert(size <= (1 << SLAB_MAX_MALLOC_W));
115
116 size_t idx = fnzb(size - 1) - SLAB_MIN_MALLOC_W + 1;
117
118 assert(idx < sizeof(malloc_caches) / sizeof(malloc_caches[0]));
119
120 slab_cache_t *cache = malloc_caches[idx];
121
122 assert(cache != NULL);
123 return cache;
124}
125
126// TODO: Expose publicly and use mem_alloc() and mem_free() instead of malloc()
127
128static void *mem_alloc(size_t, size_t) __attribute__((malloc));
129
130static void *mem_alloc(size_t alignment, size_t size)
131{
132 _check_sizes(&alignment, &size);
133
134 if (size > (1 << SLAB_MAX_MALLOC_W)) {
135 // TODO: Allocate big objects directly from coarse allocator.
136 assert(size <= (1 << SLAB_MAX_MALLOC_W));
137 }
138
139 /* We assume that slab objects are aligned naturally */
140 return slab_alloc(cache_for_size(size), FRAME_ATOMIC);
141}
142
143static void *mem_realloc(void *old_ptr, size_t alignment, size_t old_size,
144 size_t new_size)
145{
146 assert(old_ptr);
147 _check_sizes(&alignment, &old_size);
148 _check_sizes(&alignment, &new_size);
149
150 // TODO: handle big objects
151 assert(new_size <= (1 << SLAB_MAX_MALLOC_W));
152
153 slab_cache_t *old_cache = cache_for_size(old_size);
154 slab_cache_t *new_cache = cache_for_size(new_size);
155 if (old_cache == new_cache)
156 return old_ptr;
157
158 void *new_ptr = slab_alloc(new_cache, FRAME_ATOMIC);
159 if (!new_ptr)
160 return NULL;
161
162 memcpy(new_ptr, old_ptr, min(old_size, new_size));
163 slab_free(old_cache, old_ptr);
164 return new_ptr;
165}
166
167/**
168 * Free memory allocated using mem_alloc().
169 *
170 * @param ptr Pointer returned by mem_alloc().
171 * @param size Size used to call mem_alloc().
172 * @param alignment Alignment used to call mem_alloc().
173 */
174static void mem_free(void *ptr, size_t alignment, size_t size)
175{
176 if (!ptr)
177 return;
178
179 _check_sizes(&alignment, &size);
180
181 if (size > (1 << SLAB_MAX_MALLOC_W)) {
182 // TODO: Allocate big objects directly from coarse allocator.
183 assert(size <= (1 << SLAB_MAX_MALLOC_W));
184 }
185
186 return slab_free(cache_for_size(size), ptr);
187}
188
189static const size_t _offset = ALIGN_UP(sizeof(size_t), alignof(max_align_t));
190
191void *malloc(size_t size)
192{
193 void *obj = mem_alloc(alignof(max_align_t), size + _offset) + _offset;
194
195 /* Remember the allocation size just before the object. */
196 ((size_t *) obj)[-1] = size;
197 return obj;
198}
199
200void free(void *obj)
201{
202 /*
203 * We don't check integrity of size, so buffer over/underruns can
204 * corrupt it. That's ok, it ultimately only serves as a hint to
205 * select the correct slab cache. If the selected cache is not correct,
206 * slab_free() will detect it and panic.
207 */
208 size_t size = ((size_t *) obj)[-1];
209 mem_free(obj - _offset, alignof(max_align_t), size + _offset);
210}
211
212void *realloc(void *old_obj, size_t new_size)
213{
214 if (!old_obj)
215 return malloc(new_size);
216
217 size_t old_size = ((size_t *) old_obj)[-1];
218
219 void *new_obj = mem_realloc(old_obj - _offset, alignof(max_align_t),
220 old_size + _offset, new_size + _offset) + _offset;
221 if (!new_obj)
222 return NULL;
223
224 ((size_t *) new_obj)[-1] = new_size;
225 return new_obj;
226}
Note: See TracBrowser for help on using the repository browser.