Files
integration/luprex/core/cpp/umm-malloc.hpp

109 lines
3.6 KiB
C++
Raw Normal View History

////////////////////////////////////////////////////////////////////
//
// To achieve determinism of replay logs, the driver is not allowed
// to touch the malloc heap. We've given the driver its own
// separate heap. The driver's heap is accessed using umm_malloc,
// umm_free, and umm_realloc.
//
// To initialize the umm heap, you allocate a single large
// block of RAM from the OS, perhaps 4M. You pass that block
// to umm_heap_init. The umm_malloc routine will allocate out of
// that block. The umm heap cannot grow, if the block fills up, umm_malloc
// will fail. It is fine to get the initial heap block from the
// regular system malloc! That doesn't compromise determinism,
// since you're always allocating the same 4M block.
//
// The UMM malloc library is distributed under the MIT license
// by Ralph Hempel. This is a slightly-modified version, you can
// find the original online. Mr. Hempel considers this to be a malloc
// for microcontrollers, but it works just fine on workstations.
// Of all the mallocs to choose from, I picked this one because it
// satisfies three main criteria: it works out of a fixed block
// of RAM, it's not terribly inefficient, and it's not too complicated
// to modify.
//
// Warning! Don't forget that using the C++ STL tends to use malloc
// all over the place. For example, if you create a std::string,
// you're using malloc! Don't use normal STL classes in the driver!
// Fortunately, most STL classes allow you to specify a custom
// allocator class. The following classes use the UMM allocator:
//
// UmmString - same as std::string.
// UmmVector<T> - same as std::vector<T>.
// UmmMap<K,V> - same as std::map<K,V>
// UmmSet<T> - same as std::set<T>
//
// Sadly, routines that accept std::string, std::vector, std::map,
// or std::set do not accept their Umm equivalents. It is possible
// to write a routine that accepts both std::string and UmmString
// by accepting a std::string_view parameter. Other than that,
// these types are separate.
//
////////////////////////////////////////////////////////////////////
#ifndef UMM_MALLOC_HPP
#define UMM_MALLOC_HPP
#include <stdint.h>
#include <stddef.h>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <utility>
void umm_init_heap(void *ptr, size_t size);
void *umm_malloc(size_t size);
void *umm_realloc(void *ptr, size_t size);
void umm_free(void *ptr);
void umm_info();
void *umm_malloc_ssl(size_t size, const char *file, int line);
void *umm_realloc_ssl(void *ptr, size_t size, const char *file, int line);
void umm_free_ssl(void *ptr, const char *file, int line);
template <class T>
class UmmAllocator
{
public:
using value_type = T;
UmmAllocator() noexcept {}
template <class U> UmmAllocator(UmmAllocator<U> const&) noexcept {}
value_type* allocate(std::size_t n)
{
return static_cast<value_type*>(umm_malloc(n*sizeof(value_type)));
}
void deallocate(value_type* p, std::size_t) noexcept
{
umm_free(p);
}
};
template <class T, class U>
bool operator==(UmmAllocator<T> const&, UmmAllocator<U> const&) noexcept
{
return true;
}
template <class T, class U>
bool operator!=(UmmAllocator<T> const&, UmmAllocator<U> const&) noexcept
{
return false;
}
using UmmString = std::basic_string<char, std::char_traits<char>, UmmAllocator<char>>;
template <class T>
using UmmVector = std::vector<T, UmmAllocator<T>>;
template <class K, class T, class C=std::less<K>>
using UmmMap = std::map<K, T, C, UmmAllocator<std::pair<const K, T>>>;
template <class K, class C=std::less<K>>
using UmmSet = std::set<K, C, UmmAllocator<K>>;
#endif // UMM_MALLOC_HPP