109 lines
3.6 KiB
C++
109 lines
3.6 KiB
C++
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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
|