Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

287 lines (222 sloc) 7.416 kB
/*
* Copyright (c) 2009 Openmoko Inc.
*
* Authors Marek Lindner <marek@openmoko.com>
*
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <malloc-simple.h>
#include <wikilib.h>
#include <msg.h>
#include <string.h>
#ifndef __c33 // ugly hack but for now it works...
void malloc_init_simple(void) { }
void malloc_status_simple(void) { }
void *malloc_simple(uint32_t size, uint32_t tag)
{
return malloc(size);
}
void free_simple(void *ptr, uint32_t tag)
{
free(ptr);
}
#else // __c33
extern uint8_t __START_heap;
extern uint8_t __END_heap;
#define MEM_SIZE (&__END_heap - &__START_heap)
#define RAM_START (&__START_heap)
// page size should not be smaller than struct malloc_page
#define PAGE_SIZE (256)
#define MEMORY_DEBUG 1
#define MAGIC_NUMBER 0x12345678
#define NUM_PAGES (MEM_SIZE / PAGE_SIZE)
#define CTRL_PAGE 1
#define GET_PAGE(curr_page, num_pages) (((uint8_t *)(curr_page)) + ((num_pages) * PAGE_SIZE))
enum mem_status {
MEM_UNUSED,
MEM_INUSE
};
struct malloc_page
{
uint32_t magicNumber;
uint32_t filler[10];
struct malloc_page *next;
struct malloc_page *prev;
uint32_t size; // number of pages
uint32_t alloc_tag;
uint32_t free_tag;
enum mem_status status;
};
struct malloc_page *first_page = (struct malloc_page *)RAM_START;
static void init_page(struct malloc_page *page)
{
ASSERT(page);
page->magicNumber = MAGIC_NUMBER;
page->prev = NULL;
page->next = NULL;
page->size = 0;
page->status = MEM_UNUSED;
page->alloc_tag = MEM_TAG_UNUSED;
page->free_tag = MEM_TAG_UNUSED;
}
static struct malloc_page *page_new(struct malloc_page *curr_page, uint32_t needed_pages)
{
struct malloc_page *new_page = (struct malloc_page *)GET_PAGE(curr_page, needed_pages + 1);
init_page(new_page);
ASSERT(curr_page);
ASSERT(curr_page->magicNumber == MAGIC_NUMBER);
curr_page->next = new_page;
new_page->prev = curr_page;
// one more for the malloc control page
new_page->size = curr_page->size - needed_pages - CTRL_PAGE;
curr_page->size = needed_pages;
return new_page;
}
void malloc_init_simple(void)
{
memset(first_page, 0, sizeof(struct malloc_page));
init_page(first_page);
first_page->size = NUM_PAGES;
}
void *malloc_simple(uint32_t size, uint32_t tag)
{
struct malloc_page *curr_page, *new_page;
uint32_t needed_pages = size / PAGE_SIZE;
if (size % PAGE_SIZE) {
needed_pages++;
}
for (curr_page = first_page; curr_page != NULL; curr_page = curr_page->next) {
ASSERT(curr_page);
ASSERT(curr_page->magicNumber == MAGIC_NUMBER);
if (curr_page->status != MEM_UNUSED) {
continue;
}
// free memory but not enough space for us due to memory fragmentation
if ((curr_page->next != NULL) && (curr_page->size < needed_pages)) {
continue;
}
// end of memory reached - out of memory
if ((curr_page->next == NULL) && (curr_page->size < needed_pages + CTRL_PAGE)) {
break;
}
// the memory lying ahead has no control structure - we need to create it
if (curr_page->next == NULL) {
new_page = page_new(curr_page, needed_pages);
}
curr_page->alloc_tag = tag;
curr_page->free_tag = MEM_TAG_UNUSED;
curr_page->status = MEM_INUSE;
ASSERT(curr_page);
ASSERT(curr_page->magicNumber == MAGIC_NUMBER);
return (void *)GET_PAGE(curr_page, 1);
}
// out of memory
return NULL;
}
void free_simple(void *ptr, uint32_t tag)
{
struct malloc_page *my_page, *curr_page;
if (!ptr) {
return;
}
if ((uint8_t *)ptr < RAM_START + PAGE_SIZE){
return;
}
my_page = (struct malloc_page *)GET_PAGE(ptr, -1);
ASSERT(my_page);
ASSERT(my_page->magicNumber == MAGIC_NUMBER);
// double free
if (my_page->status == MEM_UNUSED) {
#if MEMORY_DEBUG
msg(MSG_INFO, "MEMORY DEBUG: possible double free detected - trying to free %p again\n",
ptr);
msg(MSG_INFO, "MEMORY DEBUG: alloc tag: %d, old free tag: %d, curr free tag: %d)\n",
my_page->alloc_tag, my_page->free_tag, tag);
#endif
return;
}
my_page->status = MEM_UNUSED;
my_page->free_tag = tag;
//msg(MSG_INFO, "freeing: alloc tag: %d, free tag %d\n", my_page->alloc_tag, tag);
// we may be able to merge larger chunks of free space that follows the current chunk
for (curr_page = my_page->next; curr_page != NULL; curr_page = curr_page->next) {
ASSERT(curr_page->magicNumber == MAGIC_NUMBER);
if (curr_page->status != MEM_UNUSED) {
break;
}
my_page->size += curr_page->size + CTRL_PAGE;
my_page->next = curr_page->next;
if (curr_page->next) {
ASSERT(curr_page->next->magicNumber == MAGIC_NUMBER);
curr_page->next->prev = my_page;
}
}
// merge free space that preceeds the current chunk
for (curr_page = my_page->prev; curr_page != NULL; curr_page = curr_page->prev) {
ASSERT(curr_page->magicNumber == MAGIC_NUMBER);
if (curr_page->status != MEM_UNUSED) {
break;
}
curr_page->size += curr_page->next->size + CTRL_PAGE;
// save the tags from the item that is being deleted now
curr_page->alloc_tag = curr_page->next->alloc_tag;
curr_page->free_tag = curr_page->next->free_tag;
ASSERT(curr_page->next);
ASSERT(curr_page->next->magicNumber == MAGIC_NUMBER);
curr_page->next = curr_page->next->next;
curr_page->next->prev = curr_page;
}
}
void malloc_status_simple(void)
{
struct malloc_page *curr_page;
uint32_t mem_inuse = 0, mem_frag = 0, malloc_pages = 0, free_mem = 0;
msg(MSG_INFO, "\nmemory status:\n");
for (curr_page = first_page; curr_page != NULL; curr_page = curr_page->next) {
malloc_pages++;
ASSERT(curr_page);
ASSERT(curr_page->magicNumber == MAGIC_NUMBER);
if (curr_page->status == MEM_INUSE) {
mem_inuse += curr_page->size;
}
if ((curr_page->status == MEM_UNUSED) && (curr_page->next != NULL)) {
mem_frag += curr_page->size;
}
free_mem = curr_page->size;
#if MEMORY_DEBUG
if (curr_page->magicNumber != MAGIC_NUMBER) {
msg(MSG_INFO,
"MEMORY DEBUG: invalid magic number (%08x - expected %08x) - alloc tag: %d, prev alloc tag: %d\n",
curr_page->magicNumber, MAGIC_NUMBER,
curr_page->alloc_tag,
(curr_page->prev != NULL ? curr_page->prev->alloc_tag : 0));
}
if (curr_page->status == MEM_INUSE) {
msg(MSG_INFO, "MEMORY DEBUG: used mem - alloc tag: %d, size: %d\n",
curr_page->alloc_tag, curr_page->size * PAGE_SIZE);
}
// do not show end of memory page
else if (curr_page->next != NULL) {
msg(MSG_INFO, "MEMORY DEBUG: fragmented mem - alloc tag: %d, size: %d, free tag: %d\n",
curr_page->alloc_tag, curr_page->size * PAGE_SIZE, curr_page->free_tag);
}
#endif
}
msg(MSG_INFO, " * memory allocated: %d\n * memory fragmented: %d\n",
mem_inuse * PAGE_SIZE, mem_frag * PAGE_SIZE);
msg(MSG_INFO, " * num control pages: %d\n * free memory: %d\n * total memory: %d\n",
malloc_pages, free_mem * PAGE_SIZE, MEM_SIZE);
}
#endif
Jump to Line
Something went wrong with that request. Please try again.