/* * The wrapper for allocating/releasing dynamic memory inside the kernel * * Version: $Id: kernel.c,v 1.3 2003/02/14 09:22:36 wensong Exp $ * * Authors: Wensong Zhang * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ #include #include #include /* for list_head */ #include typedef struct memblock_s { struct list_head list; void *ptr; size_t size; } memblock_t; /* * The list of memory blocks (one simple list) */ static LIST_HEAD(memblock_list); static rwlock_t memblock_lock = RW_LOCK_UNLOCKED; static int memblock_add(void *ptr, size_t size) { memblock_t *m; if (!(m = kmalloc(sizeof(memblock_t), GFP_ATOMIC))) return -ENOMEM; m->ptr = ptr; m->size = size; write_lock(&memblock_lock); list_add(&m->list, &memblock_list); write_unlock(&memblock_lock); return 0; } static void memblock_del(memblock_t *m) { write_lock(&memblock_lock); list_del(&m->list); write_unlock(&memblock_lock); kfree(m); } static memblock_t *memblock_get(void *ptr) { struct list_head *l; memblock_t *m; read_lock(&memblock_lock); list_for_each(l, &memblock_list) { m = list_entry(l, memblock_t, list); if (m->ptr == ptr) { /* HIT */ read_unlock(&memblock_lock); return m; } } read_unlock(&memblock_lock); return NULL; } void *malloc(size_t size) { void *ptr; if (size == 0) return NULL; if (!(ptr = kmalloc(size, GFP_ATOMIC))) return NULL; if (memblock_add(ptr, size)) { kfree(ptr); return NULL; } return ptr; } void free(void *ptr) { memblock_t *m; if (!ptr) return; if (!(m = memblock_get(ptr))) { printk(KERN_ERR "bug: free non-exist memory\n"); return; } memblock_del(m); kfree(ptr); } void *realloc(void *ptr, size_t size) { memblock_t *m; void *new = NULL; if (ptr) { if (!(m = memblock_get(ptr))) { printk(KERN_ERR "bug: realloc non-exist memory\n"); return NULL; } if (size == m->size) return ptr; if (size != 0) { if (!(new = kmalloc(size, GFP_ATOMIC))) return NULL; memmove(new, ptr, min(size, m->size)); if (memblock_add(new, size)) { kfree(new); return NULL; } } memblock_del(m); kfree(ptr); } else { if (size != 0) { if (!(new = kmalloc(size, GFP_ATOMIC))) return NULL; if (memblock_add(new, size)) { kfree(new); return NULL; } } } return new; }