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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since e6eee2b was 38c773e7, checked in by Martin Decky <martin@…>, 14 years ago

make really sure the test does not trip over and fell on its own running chain saw

  • Property mode set to 100644
File size: 9.5 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 <malloc.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_head(&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_head(&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(link_t *link, void *addr, size_t size)
87{
88 mem_block_t *block = list_get_instance(link, mem_block_t, link);
89
90 /* Entry block control structure <mbeg, mend) */
91 uint8_t *mbeg = (uint8_t *) block;
92 uint8_t *mend = (uint8_t *) block + sizeof(mem_block_t);
93
94 /* Entry block memory <bbeg, bend) */
95 uint8_t *bbeg = (uint8_t *) block->addr;
96 uint8_t *bend = (uint8_t *) block->addr + block->size;
97
98 /* Data block <dbeg, dend) */
99 uint8_t *dbeg = (uint8_t *) addr;
100 uint8_t *dend = (uint8_t *) addr + size;
101
102 /* Check for overlaps */
103 if (((mbeg >= dbeg) && (mbeg < dend)) ||
104 ((mend > dbeg) && (mend <= dend)) ||
105 ((bbeg >= dbeg) && (bbeg < dend)) ||
106 ((bend > dbeg) && (bend <= dend)))
107 return true;
108
109 return false;
110}
111
112/** Test overlap
113 *
114 * Test whether a block starting at @addr overlaps with another,
115 * previously allocated memory block or its control structure.
116 *
117 * @param addr Initial address of the block
118 * @param size Size of the block
119 *
120 * @return False if the block does not overlap.
121 *
122 */
123static int test_overlap(void *addr, size_t size)
124{
125 bool fnd = false;
126
127 list_foreach(mem_blocks, link) {
128 if (overlap_match(link, addr, size)) {
129 fnd = true;
130 break;
131 }
132 }
133
134 return fnd;
135}
136
137/** Checked malloc
138 *
139 * Allocate @size bytes of memory and check whether the chunk comes
140 * from the non-mapped memory region and whether the chunk overlaps
141 * with other, previously allocated, chunks.
142 *
143 * @param size Amount of memory to allocate
144 *
145 * @return NULL if the allocation failed. Sets the global error_flag to
146 * true if the allocation succeeded but is illegal.
147 *
148 */
149static void *checked_malloc(size_t size)
150{
151 void *data;
152
153 /* Allocate the chunk of memory */
154 data = malloc(size);
155 if (data == NULL)
156 return NULL;
157
158 /* Check for overlaps with other chunks */
159 if (test_overlap(data, size)) {
160 TPRINTF("\nError: Allocated block overlaps with another "
161 "previously allocated block.\n");
162 error_flag = true;
163 }
164
165 return data;
166}
167
168
169/* Allocate block
170 *
171 * Allocate a block of memory of @size bytes and add record about it into
172 * the mem_blocks list. Return a pointer to the block holder structure or
173 * NULL if the allocation failed.
174 *
175 * If the allocation is illegal (e.g. the memory does not come from the
176 * right region or some of the allocated blocks overlap with others),
177 * set the global error_flag.
178 *
179 * @param size Size of the memory block
180 *
181 */
182mem_block_t *alloc_block(size_t size)
183{
184 /* Check for allocation limit */
185 if (mem_allocated >= MAX_ALLOC)
186 return NULL;
187
188 /* Allocate the block holder */
189 mem_block_t *block =
190 (mem_block_t *) checked_malloc(sizeof(mem_block_t));
191 if (block == NULL)
192 return NULL;
193
194 link_initialize(&block->link);
195
196 /* Allocate the block memory */
197 block->addr = checked_malloc(size);
198 if (block->addr == NULL) {
199 free(block);
200 return NULL;
201 }
202
203 block->size = size;
204
205 /* Register the allocated block */
206 list_append(&block->link, &mem_blocks);
207 mem_allocated += size + sizeof(mem_block_t);
208 mem_blocks_count++;
209
210 return block;
211}
212
213/** Free block
214 *
215 * Free the block of memory and the block control structure allocated by
216 * alloc_block. Set the global error_flag if an error occurs.
217 *
218 * @param block Block control structure
219 *
220 */
221void free_block(mem_block_t *block)
222{
223 /* Unregister the block */
224 list_remove(&block->link);
225 mem_allocated -= block->size + sizeof(mem_block_t);
226 mem_blocks_count--;
227
228 /* Free the memory */
229 free(block->addr);
230 free(block);
231}
232
233/** Calculate expected value
234 *
235 * Compute the expected value of a byte located at @pos in memory
236 * block described by @block.
237 *
238 * @param block Memory block control structure
239 * @param pos Position in the memory block data area
240 *
241 */
242static inline uint8_t block_expected_value(mem_block_t *block, uint8_t *pos)
243{
244 return ((uintptr_t) block ^ (uintptr_t) pos) & 0xff;
245}
246
247/** Fill block
248 *
249 * Fill the memory block controlled by @block with data.
250 *
251 * @param block Memory block control structure
252 *
253 */
254void fill_block(mem_block_t *block)
255{
256 for (uint8_t *pos = block->addr, *end = pos + block->size;
257 pos < end; pos++)
258 *pos = block_expected_value(block, pos);
259}
260
261/** Check block
262 *
263 * Check whether the block @block contains the data it was filled with.
264 * Set global error_flag if an error occurs.
265 *
266 * @param block Memory block control structure
267 *
268 */
269void check_block(mem_block_t *block)
270{
271 for (uint8_t *pos = block->addr, *end = pos + block->size;
272 pos < end; pos++) {
273 if (*pos != block_expected_value(block, pos)) {
274 TPRINTF("\nError: Corrupted content of a data block.\n");
275 error_flag = true;
276 return;
277 }
278 }
279}
280
281/** Get random block
282 *
283 * Select a random memory block from the list of allocated blocks.
284 *
285 * @return Block control structure or NULL if the list is empty.
286 *
287 */
288mem_block_t *get_random_block(void)
289{
290 if (mem_blocks_count == 0)
291 return NULL;
292
293 unsigned int idx = rand() % mem_blocks_count;
294 link_t *entry = list_nth(&mem_blocks, idx);
295
296 if (entry == NULL) {
297 TPRINTF("\nError: Corrupted list of allocated memory blocks.\n");
298 error_flag = true;
299 }
300
301 return list_get_instance(entry, mem_block_t, link);
302}
303
304/* Map memory area
305 *
306 * Map a memory area of @size bytes and add record about it into
307 * the mem_areas list. Return a pointer to the area holder structure or
308 * NULL if the mapping failed.
309 *
310 * @param size Size of the memory area
311 *
312 */
313mem_area_t *map_area(size_t size)
314{
315 /* Allocate the area holder */
316 mem_area_t *area =
317 (mem_area_t *) checked_malloc(sizeof(mem_area_t));
318 if (area == NULL)
319 return NULL;
320
321 link_initialize(&area->link);
322
323 /* Map the memory area */
324 void *addr = as_get_mappable_page(size);
325 if (addr == NULL) {
326 free(area);
327 return NULL;
328 }
329
330 area->addr = as_area_create(addr, size, AS_AREA_WRITE | AS_AREA_READ);
331 if (area->addr == (void *) -1) {
332 free(area);
333 return NULL;
334 }
335
336 area->size = size;
337
338 /* Register the allocated area */
339 list_append(&area->link, &mem_areas);
340
341 return area;
342}
343
344/** Unmap area
345 *
346 * Unmap the memory area and free the block control structure.
347 * Set the global error_flag if an error occurs.
348 *
349 * @param area Memory area control structure
350 *
351 */
352void unmap_area(mem_area_t *area)
353{
354 /* Unregister the area */
355 list_remove(&area->link);
356
357 /* Free the memory */
358 int ret = as_area_destroy(area->addr);
359 if (ret != EOK)
360 error_flag = true;
361
362 free(area);
363}
364
365/** Calculate expected value
366 *
367 * Compute the expected value of a byte located at @pos in memory
368 * area described by @area.
369 *
370 * @param area Memory area control structure
371 * @param pos Position in the memory area data area
372 *
373 */
374static inline uint8_t area_expected_value(mem_area_t *area, uint8_t *pos)
375{
376 return ((uintptr_t) area ^ (uintptr_t) pos) & 0xaa;
377}
378
379/** Fill area
380 *
381 * Fill the memory area controlled by @area with data.
382 *
383 * @param area Memory area control structure
384 *
385 */
386void fill_area(mem_area_t *area)
387{
388 for (uint8_t *pos = area->addr, *end = pos + area->size;
389 pos < end; pos++)
390 *pos = area_expected_value(area, pos);
391}
Note: See TracBrowser for help on using the repository browser.