Files
epics-base/modules/libcom/src/freeList/freeListLib.c
Michael Davidsaver 1595ed8860 quieting clang-tidy, non-functional changes
Changes to syntax which should not effect generated code
2023-08-28 14:17:00 +02:00

206 lines
5.6 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* SPDX-License-Identifier: EPICS
* EPICS Base is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* Author: Marty Kraimer Date: 04-19-94 */
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include "valgrind/valgrind.h"
#ifndef NVALGRIND
/* buffer around allocations to detect out of bounds access */
#define REDZONE sizeof(double)
#else
#define REDZONE 0
#endif
#include "cantProceed.h"
#include "epicsMutex.h"
#include "freeList.h"
#include "adjustment.h"
#include "errlog.h"
#include "epicsString.h"
#include "epicsAtomic.h"
#include "epicsExport.h"
/* Bypass free list and directly call malloc() every time? */
int freeListBypass
#ifdef EPICS_FREELIST_DEBUG
= 1;
#else
= 2; /* checks environment $EPICS_FREELIST_BYPASS */
#endif
epicsExportAddress(int, freeListBypass);
typedef struct allocMem {
struct allocMem *next;
void *memory;
}allocMem;
typedef struct {
int size;
int nmalloc;
void *head;
allocMem *mallochead;
size_t nBlocksAvailable;
epicsMutexId lock;
}FREELISTPVT;
LIBCOM_API void epicsStdCall
freeListInitPvt(void **ppvt,int size,int nmalloc)
{
FREELISTPVT *pfl;
int bypass = epicsAtomicGetIntT(&freeListBypass);
if(bypass==2) {
const char *str = getenv("EPICS_FREELIST_BYPASS");
if(str && epicsStrCaseCmp(str, "YES")==0) {
bypass = 1;
} else if(!str || str[0]=='\0' || epicsStrCaseCmp(str, "NO")==0) {
bypass = 0;
} else {
errlogPrintf(ERL_WARNING " EPICS_FREELIST_BYPASS expected to be YES, NO, or empty. Not \"%s\"\n", str);
}
epicsAtomicSetIntT(&freeListBypass, bypass);
}
pfl = callocMustSucceed(1,sizeof(FREELISTPVT), "freeListInitPvt");
pfl->size = adjustToWorstCaseAlignment(size);
if(!bypass)
pfl->nmalloc = nmalloc; /* nmalloc==0 to bypass */
pfl->head = NULL;
pfl->mallochead = NULL;
pfl->nBlocksAvailable = 0u;
pfl->lock = epicsMutexMustCreate();
*ppvt = (void *)pfl;
VALGRIND_CREATE_MEMPOOL(pfl, REDZONE, 0);
}
LIBCOM_API void * epicsStdCall freeListCalloc(void *pvt)
{
FREELISTPVT *pfl = pvt;
void *ptemp;
if(!pfl->nmalloc)
ptemp = calloc(1u, pfl->size);
else if(!!(ptemp = freeListMalloc(pvt)))
memset((char *)ptemp,0,pfl->size);
return(ptemp);
}
LIBCOM_API void * epicsStdCall freeListMalloc(void *pvt)
{
FREELISTPVT *pfl = pvt;
void *ptemp;
void **ppnext;
allocMem *pallocmem;
int i;
if(!pfl->nmalloc)
return malloc(pfl->size);
epicsMutexMustLock(pfl->lock);
ptemp = pfl->head;
if(ptemp==0) {
/* layout of each block. nmalloc+1 REDZONEs for nmallocs.
* The first sizeof(void*) bytes are used to store a pointer
* to the next free block.
*
* | RED | size0 ------ | RED | size1 | ... | RED |
* | | next | ----- |
*/
ptemp = (void *)malloc(pfl->nmalloc*(pfl->size+REDZONE)+REDZONE);
if(ptemp==0) {
epicsMutexUnlock(pfl->lock);
return(0);
}
pallocmem = (allocMem *)calloc(1,sizeof(allocMem));
if(pallocmem==0) {
epicsMutexUnlock(pfl->lock);
free(ptemp);
return(0);
}
pallocmem->memory = ptemp; /* real allocation */
ptemp = REDZONE + (char *) ptemp; /* skip first REDZONE */
if(pfl->mallochead)
pallocmem->next = pfl->mallochead;
pfl->mallochead = pallocmem;
for(i=0; i<pfl->nmalloc; i++) {
ppnext = ptemp;
VALGRIND_MEMPOOL_ALLOC(pfl, ptemp, sizeof(void*));
*ppnext = pfl->head;
pfl->head = ptemp;
ptemp = ((char *)ptemp) + pfl->size+REDZONE;
}
ptemp = pfl->head;
pfl->nBlocksAvailable += pfl->nmalloc;
}
ppnext = pfl->head;
pfl->head = *ppnext;
pfl->nBlocksAvailable--;
epicsMutexUnlock(pfl->lock);
VALGRIND_MEMPOOL_FREE(pfl, ptemp);
VALGRIND_MEMPOOL_ALLOC(pfl, ptemp, pfl->size);
return(ptemp);
}
LIBCOM_API void epicsStdCall freeListFree(void *pvt,void*pmem)
{
FREELISTPVT *pfl = pvt;
void **ppnext;
if(!pfl->nmalloc) {
free(pmem);
return;
}
VALGRIND_MEMPOOL_FREE(pvt, pmem);
VALGRIND_MEMPOOL_ALLOC(pvt, pmem, sizeof(void*));
epicsMutexMustLock(pfl->lock);
ppnext = pmem;
*ppnext = pfl->head;
pfl->head = pmem;
pfl->nBlocksAvailable++;
epicsMutexUnlock(pfl->lock);
}
LIBCOM_API void epicsStdCall freeListCleanup(void *pvt)
{
FREELISTPVT *pfl = pvt;
allocMem *phead;
allocMem *pnext;
VALGRIND_DESTROY_MEMPOOL(pvt);
phead = pfl->mallochead;
while(phead) {
pnext = phead->next;
free(phead->memory);
free(phead);
phead = pnext;
}
epicsMutexDestroy(pfl->lock);
free(pvt);
}
LIBCOM_API size_t epicsStdCall freeListItemsAvail(void *pvt)
{
FREELISTPVT *pfl = pvt;
size_t nBlocksAvailable;
epicsMutexMustLock(pfl->lock);
nBlocksAvailable = pfl->nBlocksAvailable;
epicsMutexUnlock(pfl->lock);
return nBlocksAvailable;
}