ffc099eb54
Even though malloc via the cxx_heap never fails, the implementation of calloc should better not rely on this assumption.
139 lines
3.1 KiB
C++
139 lines
3.1 KiB
C++
/*
|
|
* \brief Simplistic malloc and free implementation
|
|
* \author Norman Feske
|
|
* \date 2006-07-21
|
|
*
|
|
* Malloc and free are required by the C++ exception handling.
|
|
* Therefore, we provide it here.
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2006-2017 Genode Labs GmbH
|
|
*
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
* under the terms of the GNU Affero General Public License version 3.
|
|
*/
|
|
|
|
/* Genode includes */
|
|
#include <base/env.h>
|
|
#include <base/heap.h>
|
|
#include <util/string.h>
|
|
#include <util/reconstructible.h>
|
|
|
|
/* base-internal includes */
|
|
#include <base/internal/globals.h>
|
|
#include <base/internal/unmanaged_singleton.h>
|
|
|
|
using namespace Genode;
|
|
|
|
|
|
static Heap *cxx_heap_ptr;
|
|
|
|
|
|
Heap &cxx_heap()
|
|
{
|
|
class Cxx_heap_uninitialized : Exception { };
|
|
if (!cxx_heap_ptr)
|
|
throw Cxx_heap_uninitialized();
|
|
|
|
return *cxx_heap_ptr;
|
|
}
|
|
|
|
|
|
/**
|
|
* Return heap partition for the private use within the cxx library.
|
|
*
|
|
* For creating the exception object, the C++ runtime calls
|
|
* '__cxa_allocate_exception', which, in turn, calls 'malloc'. The cxx library
|
|
* uses a local implementation of 'malloc' using a dedicated heap instance.
|
|
*/
|
|
void Genode::init_cxx_heap(Env &env)
|
|
{
|
|
/*
|
|
* Exception frames are small. Hence, a small static backing store suffices
|
|
* for the cxx heap partition in the normal case. The 'env.ram()' session
|
|
* is used only if the demand exceeds the capacity of the 'initial_block'.
|
|
*/
|
|
static char initial_block[1024*sizeof(long)];
|
|
|
|
cxx_heap_ptr = unmanaged_singleton<Heap>(&env.ram(), &env.rm(), Heap::UNLIMITED,
|
|
initial_block, sizeof(initial_block));
|
|
}
|
|
|
|
|
|
typedef unsigned long Block_header;
|
|
|
|
|
|
extern "C" void *malloc(size_t size)
|
|
{
|
|
/* enforce size to be a multiple of 4 bytes */
|
|
size = (size + 3) & ~3;
|
|
|
|
/*
|
|
* We store the size of the allocation at the very
|
|
* beginning of the allocated block and return
|
|
* the subsequent address. This way, we can retrieve
|
|
* the size information when freeing the block.
|
|
*/
|
|
unsigned long real_size = size + sizeof(Block_header);
|
|
void *addr = 0;
|
|
if (!cxx_heap().alloc(real_size, &addr))
|
|
return 0;
|
|
|
|
*(Block_header *)addr = real_size;
|
|
return (Block_header *)addr + 1;
|
|
}
|
|
|
|
|
|
extern "C" void *calloc(size_t nmemb, size_t size)
|
|
{
|
|
void * const addr = malloc(nmemb*size);
|
|
|
|
if (addr == nullptr)
|
|
return nullptr;
|
|
|
|
Genode::memset(addr, 0, nmemb*size);
|
|
return addr;
|
|
}
|
|
|
|
|
|
extern "C" void free(void *ptr)
|
|
{
|
|
if (!ptr) return;
|
|
|
|
unsigned long *addr = ((unsigned long *)ptr) - 1;
|
|
cxx_heap().free(addr, *addr);
|
|
}
|
|
|
|
|
|
extern "C" void *realloc(void *ptr, Genode::size_t size)
|
|
{
|
|
if (!ptr)
|
|
return malloc(size);
|
|
|
|
if (!size) {
|
|
free(ptr);
|
|
return 0;
|
|
}
|
|
|
|
/* determine size of old block content (without header) */
|
|
unsigned long old_size = *((Block_header *)ptr - 1)
|
|
- sizeof(Block_header);
|
|
|
|
/* do not reallocate if new size is less than the current size */
|
|
if (size <= old_size)
|
|
return ptr;
|
|
|
|
/* allocate new block */
|
|
void *new_addr = malloc(size);
|
|
|
|
/* copy content from old block into new block */
|
|
if (new_addr)
|
|
memcpy(new_addr, ptr, Genode::min(old_size, (unsigned long)size));
|
|
|
|
/* free old block */
|
|
free(ptr);
|
|
|
|
return new_addr;
|
|
}
|