comrogue-pi/kernel/lib/heap_tcache.c

336 lines
9.2 KiB
C
Raw Normal View History

/*
* This file is part of the COMROGUE Operating System for Raspberry Pi
*
* Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises
* All rights reserved.
*
* This program is free for commercial and non-commercial use as long as the following conditions are
* adhered to.
*
* Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices
* in the code are not to be removed.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of conditions and
* the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
* the following disclaimer in the documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* "Raspberry Pi" is a trademark of the Raspberry Pi Foundation.
*/
/*
* This code is based on/inspired by jemalloc-3.3.1. Please see LICENSE.jemalloc for further details.
*/
#include <comrogue/compiler_macros.h>
#include <comrogue/types.h>
#include <comrogue/scode.h>
#include <comrogue/intlib.h>
#include <comrogue/internals/mmu.h>
#include <comrogue/internals/seg.h>
#include "heap_internals.h"
#ifdef _H_THIS_FILE
#undef _H_THIS_FILE
_DECLARE_H_THIS_FILE
#endif
/*------------------------------
* Thread-level cache functions
*------------------------------
*/
/*
* Record a thread cache event, which may cause a garbage collection.
*
* Parameters:
* - phd = Pointer to the HEAPDATA block.
* - ptcache = Pointer to thread cache to record an event for.
*
* Returns:
* Nothing.
*/
void _HeapTCacheEvent(PHEAPDATA phd, PTCACHE ptcache)
{
if (TCACHE_GC_INCR == 0)
return;
ptcache->cEvents++;
_H_ASSERT(phd, ptcache->cEvents <= TCACHE_GC_INCR);
if (ptcache->cEvents == TCACHE_GC_INCR)
_HeapTCacheEventHard(phd, ptcache);
}
/*
* Destroys the current thread's cache if it exists.
*
* Parameters:
* - phd = Pointer to the HEAPDATA block.
*
* Returns:
* Nothing.
*/
void _HeapTCacheFlush(PHEAPDATA phd)
{
PTCACHE ptcache = NULL; /* pointer to thread cache */
IThreadLocal_Get(phd->pthrlTCache, (PPVOID)(&ptcache));
if (ptcache)
IThreadLocal_Set(phd->pthrlTCache, NULL);
if (ptcache > TCACHE_STATE_MAX)
_HeapTCacheDestroy(phd, ptcache);
}
/*
* Returns whether the thread cache is enabled for this thread.
*
* Parameters:
* - phd = Pointer to the HEAPDATA block.
*
* Returns:
* - TRUE = If the thread cache is enabled for this thread.
* - FALSE = If the thread cache is disabled for this thread.
*/
BOOL _HeapTCacheIsEnabled(PHEAPDATA phd)
{
TCACHE_ENABLE te; /* enable state */
IThreadLocal_Get(phd->pthrlTCacheEnable, (PPVOID)(&te));
if (te == TCACHE_ENABLE_DEFAULT)
{
te = (phd->uiFlags & PHDFLAGS_NOTCACHE) ? TCACHE_DISABLED : TCACHE_ENABLED;
IThreadLocal_Set(phd->pthrlTCacheEnable, (PVOID)te);
}
return MAKEBOOL(te);
}
/*
* Retrieve the thread cache for this thread, creating it if necessary and desired.
*
* Parameters:
* - phd = Pointer to the HEAPDATA block.
* - fCreate = TRUE to create the thread cache if it does not exist, FALSE to skip that step.
*
* Returns:
* - NULL = The cache was disabled or not created.
* - Other = Pointer to the thread cache.
*/
PTCACHE _HeapTCacheGet(PHEAPDATA phd, BOOL fCreate)
{
PTCACHE ptcache = NULL; /* pointer to thread cache */
IThreadLocal_Get(phd->pthrlTCache, (PPVOID)(&ptcache));
if ((UINT_PTR)ptcache <= (UINT_PTR)TCACHE_STATE_MAX)
{
if (ptcache == TCACHE_STATE_DISABLED)
return NULL; /* cache disabled */
if (ptcache == NULL)
{
if (!fCreate)
return NULL;
if (!_HeapTCacheIsEnabled(phd))
{ /* disabled, record that fact */
_HeapTCacheSetEnabled(phd, FALSE);
return NULL;
}
return _HeapTCacheCreate(phd, _HeapChooseArena(phd, NULL));
}
if (ptcache == TCACHE_STATE_PURGATORY)
{
IThreadLocal_Set(phd->pthrlTCache, (PVOID)TCACHE_STATE_REINCARNATED);
return NULL;
}
if (ptcache == TCACHE_STATE_REINCARNATED)
return NULL;
/* NOT REACHED */
}
return ptcache;
}
/*
* Set the enable state of the thread cache for this thread.
*
* Parameters:
* - phd = Pointer to the HEAPDATA block.
* - fEnabled = TRUE to enable the cache, FALSE to disable it.
*
* Returns:
* Nothing.
*/
void _HeapTCacheSetEnabled(PHEAPDATA phd, BOOL fEnabled)
{
TCACHE_ENABLE te; /* enable state */
PTCACHE ptcache = NULL; /* pointer to thread cache */
te = fEnabled ? TCACHE_ENABLED : TCACHE_DISABLED;
IThreadLocal_Set(phd->pthrlTCacheEnable, (PVOID)te);
IThreadLocal_Get(phd->pthrlTCache, (PPVOID)(&ptcache));
if (fEnabled)
{
if (ptcache == TCACHE_STATE_DISABLED)
IThreadLocal_Set(phd->pthrlTCache, NULL);
}
else
{
if (ptcache > TCACHE_STATE_MAX)
{
_HeapTCacheDestroy(phd, ptcache);
ptcache = NULL;
}
if (ptcache == NULL)
IThreadLocal_Set(phd->pthrlTCache, (PVOID)TCACHE_STATE_DISABLED);
}
}
PVOID _HeapTCacheAllocEasy(PHEAPDATA phd, PTCACHEBIN ptbin)
{
return NULL; /* TODO */
}
PVOID _HeapTCacheAllocSmall(PHEAPDATA phd, PTCACHE ptcache, SIZE_T sz, BOOL fZero)
{
return NULL; /* TODO */
}
PVOID _HeapTCacheAllocLarge(PHEAPDATA phd, PTCACHE ptcache, SIZE_T sz, BOOL fZero)
{
return NULL; /* TODO */
}
void _HeapTCacheDAllocSmall(PHEAPDATA phd, PTCACHE ptcache, PVOID pv, SIZE_T ndxBin)
{
/* TODO */
}
void _HeapTCacheDAllocLarge(PHEAPDATA phd, PTCACHE ptcache, PVOID pv, SIZE_T sz)
{
/* TODO */
}
SIZE_T _HeapTCacheSAlloc(PHEAPDATA phd, PCVOID pv)
{
return 0; /* TODO */
}
void _HeapTCacheEventHard(PHEAPDATA phd, PTCACHE ptcache)
{
/* TODO */
}
PVOID _HeapTCacheAllocSmallHard(PHEAPDATA phd, PTCACHE ptcache, PTCACHEBIN ptbin, SIZE_T ndxBin)
{
return NULL; /* TODO */
}
void _HeapTCacheBinFlushSmall(PHEAPDATA phd, PTCACHEBIN ptbin, SIZE_T ndxBin, UINT32 nRem, PTCACHE ptcache)
{
/* TODO */
}
void _HeapTCacheBinFlushLarge(PHEAPDATA phd, PTCACHEBIN ptbin, SIZE_T ndxBin, UINT32 nRem, PTCACHE ptcache)
{
/* TODO */
}
void _HeapTCacheArenaAssociate(PHEAPDATA phd, PTCACHE ptcache, PARENA pArena)
{
/* TODO */
}
void _HeapTCacheArenaDisassociate(PHEAPDATA phd, PTCACHE ptcache)
{
/* TODO */
}
PTCACHE _HeapTCacheCreate(PHEAPDATA phd, PARENA pArena)
{
return NULL; /* TODO */
}
void _HeapTCacheDestroy(PHEAPDATA phd, PTCACHE ptcache)
{
/* TODO */
}
void _HeapTCacheStatsMerge(PHEAPDATA phd, PTCACHE ptcache, PARENA pArena)
{
/* TODO */
}
static void tcacheCleanup(PVOID pvContents, PVOID pvArg)
{
/*
PHEAPDATA phd = (PHEAPDATA)pvArg;
PTCACHE ptcache = (PTCACHE)pvContents;
*/
/* TODO */
}
HRESULT _HeapTCacheSetup(PHEAPDATA phd, IThreadLocalFactory *pthrlf)
{
register UINT32 i; /* loop counter */
HRESULT hr;
/* figure out the size of the largest max class */
if (phd->nTCacheMaxClassBits < 0 || (1U << phd->nTCacheMaxClassBits) < SMALL_MAXCLASS)
phd->cbTCacheMaxClass = SMALL_MAXCLASS;
else if ((1U << phd->nTCacheMaxClassBits) > phd->szArenaMaxClass)
phd->cbTCacheMaxClass = phd->szArenaMaxClass;
else
phd->cbTCacheMaxClass = (1U << phd->nTCacheMaxClassBits);
/* figure out bins count */
phd->nHBins = NBINS + (phd->cbTCacheMaxClass >> SYS_PAGE_BITS);
/* initialize the info block */
phd->ptcbi = (PTCACHEBININFO)_HeapBaseAlloc(phd, phd->nHBins * sizeof(TCACHEBININFO));
if (!(phd->ptcbi))
return E_OUTOFMEMORY;
phd->nStackElems = 0;
for (i = 0; i < NBINS; i++)
{
if ((phd->aArenaBinInfo[i].nRegions << 1) <= TCACHE_NSLOTS_SMALL_MAX)
phd->ptcbi[i].nCachedMax = (phd->aArenaBinInfo[i].nRegions << 1);
else
phd->ptcbi[i].nCachedMax = TCACHE_NSLOTS_SMALL_MAX;
phd->nStackElems += phd->ptcbi[i].nCachedMax;
}
for (; i < phd->nHBins; i++)
{
phd->ptcbi[i].nCachedMax = TCACHE_NSLOTS_LARGE;
phd->nStackElems += phd->ptcbi[i].nCachedMax;
}
/* Create the thread-local values */
hr = IThreadLocalFactory_CreateThreadLocal(pthrlf, NULL, &(phd->pthrlTCache));
if (FAILED(hr))
goto error0;
IThreadLocal_SetCleanupFunc(phd->pthrlTCache, tcacheCleanup, phd);
hr = IThreadLocalFactory_CreateThreadLocal(pthrlf, (PVOID)TCACHE_ENABLE_DEFAULT, &(phd->pthrlTCacheEnable));
if (FAILED(hr))
goto error1;
return S_OK;
error1:
IUnknown_Release(phd->pthrlTCache);
error0:
return hr;
}
void _HeapTCacheShutdown(PHEAPDATA phd)
{
IUnknown_Release(phd->pthrlTCacheEnable);
IUnknown_Release(phd->pthrlTCache);
}