2011-04-29 21:10:34 +02:00
|
|
|
#include "precompiled.h"
|
|
|
|
#include "lib/allocators/unique_range.h"
|
|
|
|
|
2011-07-18 11:21:56 +02:00
|
|
|
#include "lib/bits.h" // is_pow2, round_up
|
2011-04-29 21:10:34 +02:00
|
|
|
#include "lib/sysdep/cpu.h" // cpu_AtomicAdd
|
|
|
|
#include "lib/sysdep/rtl.h" // rtl_FreeAligned
|
|
|
|
|
|
|
|
|
2011-07-18 11:21:56 +02:00
|
|
|
// (hardwired index avoids RegisterUniqueRangeDeleter overhead for
|
|
|
|
// this commonly used allocator.)
|
|
|
|
static const IdxDeleter idxDeleterAligned = 1;
|
|
|
|
|
|
|
|
|
|
|
|
static void FreeNone(void* UNUSED(pointer), size_t UNUSED(size))
|
2011-04-29 21:10:34 +02:00
|
|
|
{
|
2011-07-18 11:21:56 +02:00
|
|
|
// (providing a deleter function for idxDeleterNone avoids
|
|
|
|
// having to check whether deleters[idxDeleter] == 0)
|
2011-04-29 21:10:34 +02:00
|
|
|
}
|
|
|
|
|
2011-07-18 11:21:56 +02:00
|
|
|
static void FreeAligned(void* pointer, size_t UNUSED(size))
|
2011-04-29 21:10:34 +02:00
|
|
|
{
|
|
|
|
return rtl_FreeAligned(pointer);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-18 11:21:56 +02:00
|
|
|
static UniqueRangeDeleter deleters[allocationAlignment] = { FreeNone, FreeAligned };
|
2011-04-29 21:10:34 +02:00
|
|
|
|
|
|
|
static IdxDeleter numDeleters = 2;
|
|
|
|
|
|
|
|
|
2011-07-18 11:21:56 +02:00
|
|
|
void RegisterUniqueRangeDeleter(UniqueRangeDeleter deleter, volatile IdxDeleter* idxDeleterOut)
|
2011-04-29 21:10:34 +02:00
|
|
|
{
|
2011-04-30 15:01:45 +02:00
|
|
|
ENSURE(deleter);
|
2011-07-18 11:21:56 +02:00
|
|
|
|
|
|
|
if(!cpu_CAS(idxDeleterOut, idxDeleterNone, -1)) // not the first call for this deleter
|
|
|
|
{
|
|
|
|
// wait until an index has been assigned
|
|
|
|
while(*idxDeleterOut <= 0)
|
|
|
|
cpu_Pause();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const IdxDeleter idxDeleter = cpu_AtomicAdd(&numDeleters, 1);
|
2011-04-30 15:01:45 +02:00
|
|
|
ENSURE(idxDeleter < (IdxDeleter)ARRAY_SIZE(deleters));
|
2011-04-29 21:10:34 +02:00
|
|
|
deleters[idxDeleter] = deleter;
|
2011-07-18 11:21:56 +02:00
|
|
|
COMPILER_FENCE;
|
|
|
|
*idxDeleterOut = idxDeleter; // linearization point
|
2011-04-29 21:10:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CallUniqueRangeDeleter(void* pointer, size_t size, IdxDeleter idxDeleter) throw()
|
|
|
|
{
|
|
|
|
ASSERT(idxDeleter < numDeleters);
|
|
|
|
// (some deleters do not tolerate null pointers)
|
|
|
|
if(pointer)
|
|
|
|
deleters[idxDeleter](pointer, size);
|
|
|
|
}
|
2011-07-18 11:21:56 +02:00
|
|
|
|
|
|
|
|
|
|
|
UniqueRange AllocateAligned(size_t size, size_t alignment)
|
|
|
|
{
|
|
|
|
ENSURE(is_pow2(alignment));
|
|
|
|
alignment = std::max(alignment, allocationAlignment);
|
|
|
|
|
|
|
|
const size_t alignedSize = round_up(size, alignment);
|
|
|
|
const UniqueRange::pointer p = rtl_AllocateAligned(alignedSize, alignment);
|
|
|
|
|
|
|
|
static volatile IdxDeleter idxDeleterAligned;
|
|
|
|
if(idxDeleterAligned == 0)
|
|
|
|
RegisterUniqueRangeDeleter(FreeAligned, &idxDeleterAligned);
|
|
|
|
|
|
|
|
return RVALUE(UniqueRange(p, size, idxDeleterAligned));
|
|
|
|
}
|