common.c

00001 /*
00002  * Copyright (c) 2009 Martin Decky
00003  * Copyright (c) 2009 Tomas Bures
00004  * Copyright (c) 2009 Lubomir Bulej
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted provided that the following conditions
00009  * are met:
00010  *
00011  * - Redistributions of source code must retain the above copyright
00012  *   notice, this list of conditions and the following disclaimer.
00013  * - Redistributions in binary form must reproduce the above copyright
00014  *   notice, this list of conditions and the following disclaimer in the
00015  *   documentation and/or other materials provided with the distribution.
00016  * - The name of the author may not be used to endorse or promote products
00017  *   derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00020  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00021  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00022  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00023  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00024  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00025  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00026  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00028  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  */
00030 
00031 #include <malloc.h>
00032 #include <as.h>
00033 #include <adt/list.h>
00034 #include <stdio.h>
00035 #include <stdlib.h>
00036 #include <errno.h>
00037 #include "../tester.h"
00038 #include "common.h"
00039 
00040 /*
00041  * Global error flag. The flag is set if an error
00042  * is encountered (overlapping blocks, inconsistent
00043  * block data, etc.)
00044  */
00045 bool error_flag = false;
00046 
00047 /*
00048  * Memory accounting: the amount of allocated memory and the
00049  * number and list of allocated blocks.
00050  */
00051 size_t mem_allocated;
00052 size_t mem_blocks_count;
00053 
00054 static LIST_INITIALIZE(mem_blocks);
00055 static LIST_INITIALIZE(mem_areas);
00056 
00060 void init_mem(void)
00061 {
00062         mem_allocated = 0;
00063         mem_blocks_count = 0;
00064 }
00065 
00071 void done_mem(void)
00072 {
00073         link_t *link;
00074         
00075         while ((link = list_head(&mem_blocks)) != NULL) {
00076                 mem_block_t *block = list_get_instance(link, mem_block_t, link);
00077                 free_block(block);
00078         }
00079         
00080         while ((link = list_head(&mem_areas)) != NULL) {
00081                 mem_area_t *area = list_get_instance(link, mem_area_t, link);
00082                 unmap_area(area);
00083         }
00084 }
00085 
00086 static bool overlap_match(link_t *link, void *addr, size_t size)
00087 {
00088         mem_block_t *block = list_get_instance(link, mem_block_t, link);
00089         
00090         /* Entry block control structure <mbeg, mend) */
00091         uint8_t *mbeg = (uint8_t *) block;
00092         uint8_t *mend = (uint8_t *) block + sizeof(mem_block_t);
00093         
00094         /* Entry block memory <bbeg, bend) */
00095         uint8_t *bbeg = (uint8_t *) block->addr;
00096         uint8_t *bend = (uint8_t *) block->addr + block->size;
00097         
00098         /* Data block <dbeg, dend) */
00099         uint8_t *dbeg = (uint8_t *) addr;
00100         uint8_t *dend = (uint8_t *) addr + size;
00101         
00102         /* Check for overlaps */
00103         if (((mbeg >= dbeg) && (mbeg < dend)) ||
00104             ((mend > dbeg) && (mend <= dend)) ||
00105             ((bbeg >= dbeg) && (bbeg < dend)) ||
00106             ((bend > dbeg) && (bend <= dend)))
00107                 return true;
00108         
00109         return false;
00110 }
00111 
00123 static int test_overlap(void *addr, size_t size)
00124 {
00125         bool fnd = false;
00126         
00127         list_foreach(mem_blocks, link) {
00128                 if (overlap_match(link, addr, size)) {
00129                         fnd = true;
00130                         break;
00131                 }
00132         }
00133         
00134         return fnd;
00135 }
00136 
00137 static void check_consistency(const char *loc)
00138 {
00139         /* Check heap consistency */
00140         void *prob = heap_check();
00141         if (prob != NULL) {
00142                 TPRINTF("\nError: Heap inconsistency at %p in %s.\n",
00143                     prob, loc);
00144                 TSTACKTRACE();
00145                 error_flag = true;
00146         }
00147 }
00148 
00161 static void *checked_malloc(size_t size)
00162 {
00163         void *data;
00164         
00165         /* Allocate the chunk of memory */
00166         data = malloc(size);
00167         check_consistency("checked_malloc");
00168         if (data == NULL)
00169                 return NULL;
00170         
00171         /* Check for overlaps with other chunks */
00172         if (test_overlap(data, size)) {
00173                 TPRINTF("\nError: Allocated block overlaps with another "
00174                     "previously allocated block.\n");
00175                 TSTACKTRACE();
00176                 error_flag = true;
00177         }
00178         
00179         return data;
00180 }
00181 
00182 
00183 /* Allocate block
00184  *
00185  * Allocate a block of memory of @size bytes and add record about it into
00186  * the mem_blocks list. Return a pointer to the block holder structure or
00187  * NULL if the allocation failed.
00188  *
00189  * If the allocation is illegal (e.g. the memory does not come from the
00190  * right region or some of the allocated blocks overlap with others),
00191  * set the global error_flag.
00192  *
00193  * @param size Size of the memory block
00194  *
00195  */
00196 mem_block_t *alloc_block(size_t size)
00197 {
00198         /* Check for allocation limit */
00199         if (mem_allocated >= MAX_ALLOC)
00200                 return NULL;
00201         
00202         /* Allocate the block holder */
00203         mem_block_t *block =
00204             (mem_block_t *) checked_malloc(sizeof(mem_block_t));
00205         if (block == NULL)
00206                 return NULL;
00207         
00208         link_initialize(&block->link);
00209         
00210         /* Allocate the block memory */
00211         block->addr = checked_malloc(size);
00212         if (block->addr == NULL) {
00213                 free(block);
00214                 check_consistency("alloc_block");
00215                 return NULL;
00216         }
00217         
00218         block->size = size;
00219         
00220         /* Register the allocated block */
00221         list_append(&block->link, &mem_blocks);
00222         mem_allocated += size + sizeof(mem_block_t);
00223         mem_blocks_count++;
00224         
00225         return block;
00226 }
00227 
00236 void free_block(mem_block_t *block)
00237 {
00238         /* Unregister the block */
00239         list_remove(&block->link);
00240         mem_allocated -= block->size + sizeof(mem_block_t);
00241         mem_blocks_count--;
00242         
00243         /* Free the memory */
00244         free(block->addr);
00245         check_consistency("free_block (a)");
00246         free(block);
00247         check_consistency("free_block (b)");
00248 }
00249 
00259 static inline uint8_t block_expected_value(mem_block_t *block, uint8_t *pos)
00260 {
00261         return ((uintptr_t) block ^ (uintptr_t) pos) & 0xff;
00262 }
00263 
00271 void fill_block(mem_block_t *block)
00272 {
00273         for (uint8_t *pos = block->addr, *end = pos + block->size;
00274             pos < end; pos++)
00275                 *pos = block_expected_value(block, pos);
00276         
00277         check_consistency("fill_block");
00278 }
00279 
00288 void check_block(mem_block_t *block)
00289 {
00290         for (uint8_t *pos = block->addr, *end = pos + block->size;
00291             pos < end; pos++) {
00292                 if (*pos != block_expected_value(block, pos)) {
00293                         TPRINTF("\nError: Corrupted content of a data block.\n");
00294                         TSTACKTRACE();
00295                         error_flag = true;
00296                         return;
00297                 }
00298         }
00299 }
00300 
00308 mem_block_t *get_random_block(void)
00309 {
00310         if (mem_blocks_count == 0)
00311                 return NULL;
00312         
00313         unsigned int idx = rand() % mem_blocks_count;
00314         link_t *entry = list_nth(&mem_blocks, idx);
00315         
00316         if (entry == NULL) {
00317                 TPRINTF("\nError: Corrupted list of allocated memory blocks.\n");
00318                 TSTACKTRACE();
00319                 error_flag = true;
00320         }
00321         
00322         return list_get_instance(entry, mem_block_t, link);
00323 }
00324 
00325 /* Map memory area
00326  *
00327  * Map a memory area of @size bytes and add record about it into
00328  * the mem_areas list. Return a pointer to the area holder structure or
00329  * NULL if the mapping failed.
00330  *
00331  * @param size Size of the memory area
00332  *
00333  */
00334 mem_area_t *map_area(size_t size)
00335 {
00336         /* Allocate the area holder */
00337         mem_area_t *area =
00338             (mem_area_t *) checked_malloc(sizeof(mem_area_t));
00339         if (area == NULL)
00340                 return NULL;
00341         
00342         link_initialize(&area->link);
00343         
00344         /* Map the memory area */
00345         void *addr = as_get_mappable_page(size);
00346         if (addr == NULL) {
00347                 free(area);
00348                 check_consistency("map_area (a)");
00349                 return NULL;
00350         }
00351         
00352         area->addr = as_area_create(addr, size, AS_AREA_WRITE | AS_AREA_READ);
00353         if (area->addr == (void *) -1) {
00354                 free(area);
00355                 check_consistency("map_area (b)");
00356                 return NULL;
00357         }
00358         
00359         area->size = size;
00360         
00361         /* Register the allocated area */
00362         list_append(&area->link, &mem_areas);
00363         
00364         return area;
00365 }
00366 
00375 void unmap_area(mem_area_t *area)
00376 {
00377         /* Unregister the area */
00378         list_remove(&area->link);
00379         
00380         /* Free the memory */
00381         int ret = as_area_destroy(area->addr);
00382         if (ret != EOK)
00383                 error_flag = true;
00384         
00385         free(area);
00386         check_consistency("unmap_area");
00387 }
00388 
00398 static inline uint8_t area_expected_value(mem_area_t *area, uint8_t *pos)
00399 {
00400         return ((uintptr_t) area ^ (uintptr_t) pos) & 0xaa;
00401 }
00402 
00410 void fill_area(mem_area_t *area)
00411 {
00412         for (uint8_t *pos = area->addr, *end = pos + area->size;
00413             pos < end; pos++)
00414                 *pos = area_expected_value(area, pos);
00415         
00416         check_consistency("fill_area");
00417 }

Generated on Thu Jun 2 07:45:43 2011 for HelenOS/USB by  doxygen 1.4.7