source: mainline/uspace/app/tester/mm/common.c

Last change on this file was 44e8541, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 20 months ago

Move stdlib.h and some of its function into /common

  • Property mode set to 100644
File size: 9.9 KB
RevLine 
[013a5d7]1/*
2 * Copyright (c) 2009 Martin Decky
3 * Copyright (c) 2009 Tomas Bures
4 * Copyright (c) 2009 Lubomir Bulej
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * - The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
[38d150e]31#include <stdlib.h>
[013a5d7]32#include <as.h>
33#include <adt/list.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <errno.h>
[44e8541]37#include <malloc.h>
[013a5d7]38#include "../tester.h"
39#include "common.h"
40
41/*
42 * Global error flag. The flag is set if an error
43 * is encountered (overlapping blocks, inconsistent
44 * block data, etc.)
45 */
46bool error_flag = false;
47
48/*
49 * Memory accounting: the amount of allocated memory and the
50 * number and list of allocated blocks.
51 */
52size_t mem_allocated;
53size_t mem_blocks_count;
54
55static LIST_INITIALIZE(mem_blocks);
56static LIST_INITIALIZE(mem_areas);
57
58/** Initializes the memory accounting structures.
59 *
60 */
61void init_mem(void)
62{
63 mem_allocated = 0;
64 mem_blocks_count = 0;
65}
66
67/** Cleanup all allocated memory blocks and mapped areas.
68 *
69 * Set the global error_flag if an error occurs.
70 *
71 */
72void done_mem(void)
73{
74 link_t *link;
[a35b458]75
[b72efe8]76 while ((link = list_first(&mem_blocks)) != NULL) {
[013a5d7]77 mem_block_t *block = list_get_instance(link, mem_block_t, link);
78 free_block(block);
79 }
[a35b458]80
[b72efe8]81 while ((link = list_first(&mem_areas)) != NULL) {
[013a5d7]82 mem_area_t *area = list_get_instance(link, mem_area_t, link);
83 unmap_area(area);
84 }
85}
86
[feeac0d]87static bool overlap_match(mem_block_t *block, void *addr, size_t size)
[013a5d7]88{
89 /* Entry block control structure <mbeg, mend) */
90 uint8_t *mbeg = (uint8_t *) block;
91 uint8_t *mend = (uint8_t *) block + sizeof(mem_block_t);
[a35b458]92
[013a5d7]93 /* Entry block memory <bbeg, bend) */
94 uint8_t *bbeg = (uint8_t *) block->addr;
95 uint8_t *bend = (uint8_t *) block->addr + block->size;
[a35b458]96
[013a5d7]97 /* Data block <dbeg, dend) */
98 uint8_t *dbeg = (uint8_t *) addr;
99 uint8_t *dend = (uint8_t *) addr + size;
[a35b458]100
[013a5d7]101 /* Check for overlaps */
102 if (((mbeg >= dbeg) && (mbeg < dend)) ||
103 ((mend > dbeg) && (mend <= dend)) ||
104 ((bbeg >= dbeg) && (bbeg < dend)) ||
105 ((bend > dbeg) && (bend <= dend)))
106 return true;
[a35b458]107
[013a5d7]108 return false;
109}
110
111/** Test overlap
112 *
113 * Test whether a block starting at @addr overlaps with another,
114 * previously allocated memory block or its control structure.
115 *
116 * @param addr Initial address of the block
117 * @param size Size of the block
118 *
119 * @return False if the block does not overlap.
120 *
121 */
122static int test_overlap(void *addr, size_t size)
123{
124 bool fnd = false;
[a35b458]125
[feeac0d]126 list_foreach(mem_blocks, link, mem_block_t, block) {
127 if (overlap_match(block, addr, size)) {
[013a5d7]128 fnd = true;
129 break;
130 }
131 }
[a35b458]132
[013a5d7]133 return fnd;
134}
135
[1b3e854]136static void check_consistency(const char *loc)
137{
138 /* Check heap consistency */
139 void *prob = heap_check();
140 if (prob != NULL) {
141 TPRINTF("\nError: Heap inconsistency at %p in %s.\n",
142 prob, loc);
143 TSTACKTRACE();
144 error_flag = true;
145 }
146}
147
[013a5d7]148/** Checked malloc
149 *
150 * Allocate @size bytes of memory and check whether the chunk comes
151 * from the non-mapped memory region and whether the chunk overlaps
152 * with other, previously allocated, chunks.
153 *
154 * @param size Amount of memory to allocate
155 *
156 * @return NULL if the allocation failed. Sets the global error_flag to
157 * true if the allocation succeeded but is illegal.
158 *
159 */
160static void *checked_malloc(size_t size)
161{
162 void *data;
[a35b458]163
[013a5d7]164 /* Allocate the chunk of memory */
165 data = malloc(size);
[1b3e854]166 check_consistency("checked_malloc");
[013a5d7]167 if (data == NULL)
168 return NULL;
[a35b458]169
[013a5d7]170 /* Check for overlaps with other chunks */
171 if (test_overlap(data, size)) {
172 TPRINTF("\nError: Allocated block overlaps with another "
173 "previously allocated block.\n");
[1b3e854]174 TSTACKTRACE();
[013a5d7]175 error_flag = true;
176 }
[a35b458]177
[013a5d7]178 return data;
179}
180
[7c3fb9b]181/** Allocate block
[013a5d7]182 *
183 * Allocate a block of memory of @size bytes and add record about it into
184 * the mem_blocks list. Return a pointer to the block holder structure or
185 * NULL if the allocation failed.
186 *
187 * If the allocation is illegal (e.g. the memory does not come from the
188 * right region or some of the allocated blocks overlap with others),
189 * set the global error_flag.
190 *
191 * @param size Size of the memory block
192 *
193 */
194mem_block_t *alloc_block(size_t size)
195{
196 /* Check for allocation limit */
197 if (mem_allocated >= MAX_ALLOC)
198 return NULL;
[a35b458]199
[013a5d7]200 /* Allocate the block holder */
201 mem_block_t *block =
202 (mem_block_t *) checked_malloc(sizeof(mem_block_t));
203 if (block == NULL)
204 return NULL;
[a35b458]205
[013a5d7]206 link_initialize(&block->link);
[a35b458]207
[013a5d7]208 /* Allocate the block memory */
209 block->addr = checked_malloc(size);
210 if (block->addr == NULL) {
211 free(block);
[1b3e854]212 check_consistency("alloc_block");
[013a5d7]213 return NULL;
214 }
[a35b458]215
[013a5d7]216 block->size = size;
[a35b458]217
[013a5d7]218 /* Register the allocated block */
219 list_append(&block->link, &mem_blocks);
220 mem_allocated += size + sizeof(mem_block_t);
221 mem_blocks_count++;
[a35b458]222
[013a5d7]223 return block;
224}
225
226/** Free block
227 *
228 * Free the block of memory and the block control structure allocated by
229 * alloc_block. Set the global error_flag if an error occurs.
230 *
231 * @param block Block control structure
232 *
233 */
234void free_block(mem_block_t *block)
235{
236 /* Unregister the block */
237 list_remove(&block->link);
238 mem_allocated -= block->size + sizeof(mem_block_t);
239 mem_blocks_count--;
[a35b458]240
[013a5d7]241 /* Free the memory */
242 free(block->addr);
[1b3e854]243 check_consistency("free_block (a)");
[013a5d7]244 free(block);
[1b3e854]245 check_consistency("free_block (b)");
[013a5d7]246}
247
248/** Calculate expected value
249 *
250 * Compute the expected value of a byte located at @pos in memory
251 * block described by @block.
252 *
253 * @param block Memory block control structure
254 * @param pos Position in the memory block data area
255 *
256 */
257static inline uint8_t block_expected_value(mem_block_t *block, uint8_t *pos)
258{
259 return ((uintptr_t) block ^ (uintptr_t) pos) & 0xff;
260}
261
262/** Fill block
263 *
264 * Fill the memory block controlled by @block with data.
265 *
266 * @param block Memory block control structure
267 *
268 */
269void fill_block(mem_block_t *block)
270{
[8ebe212]271 for (uint8_t *pos = block->addr, *end = pos + block->size;
[013a5d7]272 pos < end; pos++)
273 *pos = block_expected_value(block, pos);
[a35b458]274
[1b3e854]275 check_consistency("fill_block");
[013a5d7]276}
277
278/** Check block
279 *
280 * Check whether the block @block contains the data it was filled with.
281 * Set global error_flag if an error occurs.
282 *
283 * @param block Memory block control structure
284 *
285 */
286void check_block(mem_block_t *block)
287{
[8ebe212]288 for (uint8_t *pos = block->addr, *end = pos + block->size;
[013a5d7]289 pos < end; pos++) {
290 if (*pos != block_expected_value(block, pos)) {
291 TPRINTF("\nError: Corrupted content of a data block.\n");
[1b3e854]292 TSTACKTRACE();
[013a5d7]293 error_flag = true;
294 return;
295 }
296 }
297}
298
299/** Get random block
300 *
301 * Select a random memory block from the list of allocated blocks.
302 *
303 * @return Block control structure or NULL if the list is empty.
304 *
305 */
306mem_block_t *get_random_block(void)
307{
308 if (mem_blocks_count == 0)
309 return NULL;
[a35b458]310
[be12474]311 unsigned long idx = rand() % mem_blocks_count;
[013a5d7]312 link_t *entry = list_nth(&mem_blocks, idx);
[a35b458]313
[013a5d7]314 if (entry == NULL) {
315 TPRINTF("\nError: Corrupted list of allocated memory blocks.\n");
[1b3e854]316 TSTACKTRACE();
[013a5d7]317 error_flag = true;
318 }
[a35b458]319
[013a5d7]320 return list_get_instance(entry, mem_block_t, link);
321}
322
[7c3fb9b]323/** Map memory area
[013a5d7]324 *
325 * Map a memory area of @size bytes and add record about it into
326 * the mem_areas list. Return a pointer to the area holder structure or
327 * NULL if the mapping failed.
328 *
329 * @param size Size of the memory area
330 *
331 */
332mem_area_t *map_area(size_t size)
333{
334 /* Allocate the area holder */
335 mem_area_t *area =
336 (mem_area_t *) checked_malloc(sizeof(mem_area_t));
337 if (area == NULL)
338 return NULL;
[a35b458]339
[013a5d7]340 link_initialize(&area->link);
[a35b458]341
[faba839]342 area->addr = as_area_create(AS_AREA_ANY, size,
[6aeca0d]343 AS_AREA_WRITE | AS_AREA_READ | AS_AREA_CACHEABLE,
344 AS_AREA_UNPAGED);
[faba839]345 if (area->addr == AS_MAP_FAILED) {
[013a5d7]346 free(area);
[fbcdeb8]347 check_consistency("map_area (a)");
[013a5d7]348 return NULL;
349 }
[a35b458]350
[013a5d7]351 area->size = size;
[a35b458]352
[013a5d7]353 /* Register the allocated area */
354 list_append(&area->link, &mem_areas);
[a35b458]355
[013a5d7]356 return area;
357}
358
359/** Unmap area
360 *
361 * Unmap the memory area and free the block control structure.
362 * Set the global error_flag if an error occurs.
363 *
364 * @param area Memory area control structure
365 *
366 */
367void unmap_area(mem_area_t *area)
368{
369 /* Unregister the area */
370 list_remove(&area->link);
[a35b458]371
[013a5d7]372 /* Free the memory */
[b7fd2a0]373 errno_t ret = as_area_destroy(area->addr);
[013a5d7]374 if (ret != EOK)
375 error_flag = true;
[a35b458]376
[013a5d7]377 free(area);
[1b3e854]378 check_consistency("unmap_area");
[013a5d7]379}
380
381/** Calculate expected value
382 *
383 * Compute the expected value of a byte located at @pos in memory
384 * area described by @area.
385 *
386 * @param area Memory area control structure
387 * @param pos Position in the memory area data area
388 *
389 */
390static inline uint8_t area_expected_value(mem_area_t *area, uint8_t *pos)
391{
392 return ((uintptr_t) area ^ (uintptr_t) pos) & 0xaa;
393}
394
395/** Fill area
396 *
397 * Fill the memory area controlled by @area with data.
398 *
399 * @param area Memory area control structure
400 *
401 */
402void fill_area(mem_area_t *area)
403{
[8ebe212]404 for (uint8_t *pos = area->addr, *end = pos + area->size;
[013a5d7]405 pos < end; pos++)
406 *pos = area_expected_value(area, pos);
[a35b458]407
[1b3e854]408 check_consistency("fill_area");
[013a5d7]409}
Note: See TracBrowser for help on using the repository browser.