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

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

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 9.9 KB
Line 
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
31#include <stdlib.h>
32#include <as.h>
33#include <adt/list.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <errno.h>
37#include "../tester.h"
38#include "common.h"
39
40/*
41 * Global error flag. The flag is set if an error
42 * is encountered (overlapping blocks, inconsistent
43 * block data, etc.)
44 */
45bool error_flag = false;
46
47/*
48 * Memory accounting: the amount of allocated memory and the
49 * number and list of allocated blocks.
50 */
51size_t mem_allocated;
52size_t mem_blocks_count;
53
54static LIST_INITIALIZE(mem_blocks);
55static LIST_INITIALIZE(mem_areas);
56
57/** Initializes the memory accounting structures.
58 *
59 */
60void init_mem(void)
61{
62 mem_allocated = 0;
63 mem_blocks_count = 0;
64}
65
66/** Cleanup all allocated memory blocks and mapped areas.
67 *
68 * Set the global error_flag if an error occurs.
69 *
70 */
71void done_mem(void)
72{
73 link_t *link;
74
75 while ((link = list_first(&mem_blocks)) != NULL) {
76 mem_block_t *block = list_get_instance(link, mem_block_t, link);
77 free_block(block);
78 }
79
80 while ((link = list_first(&mem_areas)) != NULL) {
81 mem_area_t *area = list_get_instance(link, mem_area_t, link);
82 unmap_area(area);
83 }
84}
85
86static bool overlap_match(mem_block_t *block, void *addr, size_t size)
87{
88 /* Entry block control structure <mbeg, mend) */
89 uint8_t *mbeg = (uint8_t *) block;
90 uint8_t *mend = (uint8_t *) block + sizeof(mem_block_t);
91
92 /* Entry block memory <bbeg, bend) */
93 uint8_t *bbeg = (uint8_t *) block->addr;
94 uint8_t *bend = (uint8_t *) block->addr + block->size;
95
96 /* Data block <dbeg, dend) */
97 uint8_t *dbeg = (uint8_t *) addr;
98 uint8_t *dend = (uint8_t *) addr + size;
99
100 /* Check for overlaps */
101 if (((mbeg >= dbeg) && (mbeg < dend)) ||
102 ((mend > dbeg) && (mend <= dend)) ||
103 ((bbeg >= dbeg) && (bbeg < dend)) ||
104 ((bend > dbeg) && (bend <= dend)))
105 return true;
106
107 return false;
108}
109
110/** Test overlap
111 *
112 * Test whether a block starting at @addr overlaps with another,
113 * previously allocated memory block or its control structure.
114 *
115 * @param addr Initial address of the block
116 * @param size Size of the block
117 *
118 * @return False if the block does not overlap.
119 *
120 */
121static int test_overlap(void *addr, size_t size)
122{
123 bool fnd = false;
124
125 list_foreach(mem_blocks, link, mem_block_t, block) {
126 if (overlap_match(block, addr, size)) {
127 fnd = true;
128 break;
129 }
130 }
131
132 return fnd;
133}
134
135static void check_consistency(const char *loc)
136{
137 /* Check heap consistency */
138 void *prob = heap_check();
139 if (prob != NULL) {
140 TPRINTF("\nError: Heap inconsistency at %p in %s.\n",
141 prob, loc);
142 TSTACKTRACE();
143 error_flag = true;
144 }
145}
146
147/** Checked malloc
148 *
149 * Allocate @size bytes of memory and check whether the chunk comes
150 * from the non-mapped memory region and whether the chunk overlaps
151 * with other, previously allocated, chunks.
152 *
153 * @param size Amount of memory to allocate
154 *
155 * @return NULL if the allocation failed. Sets the global error_flag to
156 * true if the allocation succeeded but is illegal.
157 *
158 */
159static void *checked_malloc(size_t size)
160{
161 void *data;
162
163 /* Allocate the chunk of memory */
164 data = malloc(size);
165 check_consistency("checked_malloc");
166 if (data == NULL)
167 return NULL;
168
169 /* Check for overlaps with other chunks */
170 if (test_overlap(data, size)) {
171 TPRINTF("\nError: Allocated block overlaps with another "
172 "previously allocated block.\n");
173 TSTACKTRACE();
174 error_flag = true;
175 }
176
177 return data;
178}
179
180
181/* Allocate block
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;
199
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;
205
206 link_initialize(&block->link);
207
208 /* Allocate the block memory */
209 block->addr = checked_malloc(size);
210 if (block->addr == NULL) {
211 free(block);
212 check_consistency("alloc_block");
213 return NULL;
214 }
215
216 block->size = size;
217
218 /* Register the allocated block */
219 list_append(&block->link, &mem_blocks);
220 mem_allocated += size + sizeof(mem_block_t);
221 mem_blocks_count++;
222
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--;
240
241 /* Free the memory */
242 free(block->addr);
243 check_consistency("free_block (a)");
244 free(block);
245 check_consistency("free_block (b)");
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{
271 for (uint8_t *pos = block->addr, *end = pos + block->size;
272 pos < end; pos++)
273 *pos = block_expected_value(block, pos);
274
275 check_consistency("fill_block");
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{
288 for (uint8_t *pos = block->addr, *end = pos + block->size;
289 pos < end; pos++) {
290 if (*pos != block_expected_value(block, pos)) {
291 TPRINTF("\nError: Corrupted content of a data block.\n");
292 TSTACKTRACE();
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;
310
311 unsigned long idx = rand() % mem_blocks_count;
312 link_t *entry = list_nth(&mem_blocks, idx);
313
314 if (entry == NULL) {
315 TPRINTF("\nError: Corrupted list of allocated memory blocks.\n");
316 TSTACKTRACE();
317 error_flag = true;
318 }
319
320 return list_get_instance(entry, mem_block_t, link);
321}
322
323/* Map memory area
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;
339
340 link_initialize(&area->link);
341
342 area->addr = as_area_create(AS_AREA_ANY, size,
343 AS_AREA_WRITE | AS_AREA_READ | AS_AREA_CACHEABLE,
344 AS_AREA_UNPAGED);
345 if (area->addr == AS_MAP_FAILED) {
346 free(area);
347 check_consistency("map_area (a)");
348 return NULL;
349 }
350
351 area->size = size;
352
353 /* Register the allocated area */
354 list_append(&area->link, &mem_areas);
355
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);
371
372 /* Free the memory */
373 errno_t ret = as_area_destroy(area->addr);
374 if (ret != EOK)
375 error_flag = true;
376
377 free(area);
378 check_consistency("unmap_area");
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{
404 for (uint8_t *pos = area->addr, *end = pos + area->size;
405 pos < end; pos++)
406 *pos = area_expected_value(area, pos);
407
408 check_consistency("fill_area");
409}
Note: See TracBrowser for help on using the repository browser.