|
Packit Service |
310c69 |
/*
|
|
Packit Service |
310c69 |
* Copyright (c) 2020 Red Hat, Inc.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* This program is free software; you can redistribute it and/or
|
|
Packit Service |
310c69 |
* modify it under the terms of the GNU General Public License
|
|
Packit Service |
310c69 |
* as published by the Free Software Foundation; either version 2
|
|
Packit Service |
310c69 |
* of the License, or (at your option) any later version.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
310c69 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
310c69 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
310c69 |
* GNU General Public License for more details.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
310c69 |
* along with this program; if not, write to the Free Software
|
|
Packit Service |
310c69 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
Packit Service |
310c69 |
* 02110-1301, USA.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* $Id: //eng/uds-releases/jasper/src/uds/memoryAlloc.h#2 $
|
|
Packit Service |
310c69 |
*/
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#ifndef MEMORY_ALLOC_H
|
|
Packit Service |
310c69 |
#define MEMORY_ALLOC_H 1
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include <stdarg.h>
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#include "compiler.h"
|
|
Packit Service |
310c69 |
#include "cpu.h"
|
|
Packit Service |
310c69 |
#include "memoryDefs.h"
|
|
Packit Service |
310c69 |
#include "permassert.h"
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Allocate storage based on memory size and alignment, logging an error if
|
|
Packit Service |
310c69 |
* the allocation fails. The memory will be zeroed.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param size The size of an object
|
|
Packit Service |
310c69 |
* @param align The required alignment
|
|
Packit Service |
310c69 |
* @param what What is being allocated (for error logging)
|
|
Packit Service |
310c69 |
* @param ptr A pointer to hold the allocated memory
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @return UDS_SUCCESS or an error code
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
int allocateMemory(size_t size, size_t align, const char *what, void *ptr)
|
|
Packit Service |
310c69 |
__attribute__((warn_unused_result));
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Free storage
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param ptr The memory to be freed
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
void freeMemory(void *ptr);
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Allocate storage based on element counts, sizes, and alignment.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* This is a generalized form of our allocation use case: It allocates
|
|
Packit Service |
310c69 |
* an array of objects, optionally preceded by one object of another
|
|
Packit Service |
310c69 |
* type (i.e., a struct with trailing variable-length array), with the
|
|
Packit Service |
310c69 |
* alignment indicated.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* Why is this inline? The sizes and alignment will always be
|
|
Packit Service |
310c69 |
* constant, when invoked through the macros below, and often the
|
|
Packit Service |
310c69 |
* count will be a compile-time constant 1 or the number of extra
|
|
Packit Service |
310c69 |
* bytes will be a compile-time constant 0. So at least some of the
|
|
Packit Service |
310c69 |
* arithmetic can usually be optimized away, and the run-time
|
|
Packit Service |
310c69 |
* selection between allocation functions always can. In many cases,
|
|
Packit Service |
310c69 |
* it'll boil down to just a function call with a constant size.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param count The number of objects to allocate
|
|
Packit Service |
310c69 |
* @param size The size of an object
|
|
Packit Service |
310c69 |
* @param extra The number of additional bytes to allocate
|
|
Packit Service |
310c69 |
* @param align The required alignment
|
|
Packit Service |
310c69 |
* @param what What is being allocated (for error logging)
|
|
Packit Service |
310c69 |
* @param ptr A pointer to hold the allocated memory
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @return UDS_SUCCESS or an error code
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static INLINE int doAllocation(size_t count,
|
|
Packit Service |
310c69 |
size_t size,
|
|
Packit Service |
310c69 |
size_t extra,
|
|
Packit Service |
310c69 |
size_t align,
|
|
Packit Service |
310c69 |
const char *what,
|
|
Packit Service |
310c69 |
void *ptr)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
size_t totalSize = count * size + extra;
|
|
Packit Service |
310c69 |
// Overflow check:
|
|
Packit Service |
310c69 |
if ((size > 0) && (count > ((SIZE_MAX - extra) / size))) {
|
|
Packit Service |
310c69 |
/*
|
|
Packit Service |
310c69 |
* This is kind of a hack: We rely on the fact that SIZE_MAX would
|
|
Packit Service |
310c69 |
* cover the entire address space (minus one byte) and thus the
|
|
Packit Service |
310c69 |
* system can never allocate that much and the call will always
|
|
Packit Service |
310c69 |
* fail. So we can report an overflow as "out of memory" by asking
|
|
Packit Service |
310c69 |
* for "merely" SIZE_MAX bytes.
|
|
Packit Service |
310c69 |
*/
|
|
Packit Service |
310c69 |
totalSize = SIZE_MAX;
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
return allocateMemory(totalSize, align, what, ptr);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Reallocate dynamically allocated memory. There are no alignment guarantees
|
|
Packit Service |
310c69 |
* for the reallocated memory.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param ptr The memory to reallocate.
|
|
Packit Service |
310c69 |
* @param oldSize The old size of the memory
|
|
Packit Service |
310c69 |
* @param size The new size to allocate
|
|
Packit Service |
310c69 |
* @param what What is being allocated (for error logging)
|
|
Packit Service |
310c69 |
* @param newPtr A pointer to hold the reallocated pointer
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @return UDS_SUCCESS or an error code
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
int reallocateMemory(void *ptr,
|
|
Packit Service |
310c69 |
size_t oldSize,
|
|
Packit Service |
310c69 |
size_t size,
|
|
Packit Service |
310c69 |
const char *what,
|
|
Packit Service |
310c69 |
void *newPtr)
|
|
Packit Service |
310c69 |
__attribute__((warn_unused_result));
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Allocate one or more elements of the indicated type, logging an
|
|
Packit Service |
310c69 |
* error if the allocation fails. The memory will be zeroed.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param COUNT The number of objects to allocate
|
|
Packit Service |
310c69 |
* @param TYPE The type of objects to allocate. This type determines the
|
|
Packit Service |
310c69 |
* alignment of the allocated memory.
|
|
Packit Service |
310c69 |
* @param WHAT What is being allocated (for error logging)
|
|
Packit Service |
310c69 |
* @param PTR A pointer to hold the allocated memory
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @return UDS_SUCCESS or an error code
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
#define ALLOCATE(COUNT, TYPE, WHAT, PTR) \
|
|
Packit Service |
310c69 |
doAllocation(COUNT, sizeof(TYPE), 0, __alignof__(TYPE), WHAT, PTR)
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Allocate one object of an indicated type, followed by one or more
|
|
Packit Service |
310c69 |
* elements of a second type, logging an error if the allocation
|
|
Packit Service |
310c69 |
* fails. The memory will be zeroed.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param TYPE1 The type of the primary object to allocate. This type
|
|
Packit Service |
310c69 |
* determines the alignment of the allocated memory.
|
|
Packit Service |
310c69 |
* @param COUNT The number of objects to allocate
|
|
Packit Service |
310c69 |
* @param TYPE2 The type of array objects to allocate
|
|
Packit Service |
310c69 |
* @param WHAT What is being allocated (for error logging)
|
|
Packit Service |
310c69 |
* @param PTR A pointer to hold the allocated memory
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @return UDS_SUCCESS or an error code
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
#define ALLOCATE_EXTENDED(TYPE1, COUNT, TYPE2, WHAT, PTR) \
|
|
Packit Service |
310c69 |
__extension__ ({ \
|
|
Packit Service |
310c69 |
TYPE1 **_ptr = (PTR); \
|
|
Packit Service |
310c69 |
STATIC_ASSERT(__alignof__(TYPE1) >= __alignof__(TYPE2)); \
|
|
Packit Service |
310c69 |
int _result = doAllocation(COUNT, sizeof(TYPE2), sizeof(TYPE1), \
|
|
Packit Service |
310c69 |
__alignof__(TYPE1), WHAT, _ptr); \
|
|
Packit Service |
310c69 |
_result; \
|
|
Packit Service |
310c69 |
})
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Free memory allocated with ALLOCATE().
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param ptr Pointer to the memory to free
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static INLINE void FREE(void *ptr)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
freeMemory(ptr);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Allocate memory starting on a cache line boundary, logging an error if the
|
|
Packit Service |
310c69 |
* allocation fails. The memory will be zeroed.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param size The number of bytes to allocate
|
|
Packit Service |
310c69 |
* @param what What is being allocated (for error logging)
|
|
Packit Service |
310c69 |
* @param ptr A pointer to hold the allocated memory
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @return UDS_SUCCESS or an error code
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
__attribute__((warn_unused_result))
|
|
Packit Service |
310c69 |
static INLINE int allocateCacheAligned(size_t size,
|
|
Packit Service |
310c69 |
const char *what,
|
|
Packit Service |
310c69 |
void *ptr)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
return allocateMemory(size, CACHE_LINE_BYTES, what, ptr);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Duplicate a string.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param string The string to duplicate
|
|
Packit Service |
310c69 |
* @param what What is being allocated (for error logging)
|
|
Packit Service |
310c69 |
* @param newString A pointer to hold the duplicated string
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @return UDS_SUCCESS or an error code
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
int duplicateString(const char *string, const char *what, char **newString)
|
|
Packit Service |
310c69 |
__attribute__((warn_unused_result));
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Duplicate a buffer, logging an error if the allocation fails.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param ptr The buffer to copy
|
|
Packit Service |
310c69 |
* @param size The size of the buffer
|
|
Packit Service |
310c69 |
* @param what What is being duplicated (for error logging)
|
|
Packit Service |
310c69 |
* @param dupPtr A pointer to hold the allocated array
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @return UDS_SUCCESS or ENOMEM
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
int memdup(const void *ptr, size_t size, const char *what, void *dupPtr)
|
|
Packit Service |
310c69 |
__attribute__((warn_unused_result));
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Wrapper which permits freeing a const pointer.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param pointer the pointer to be freed
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static INLINE void freeConst(const void *pointer)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
union {
|
|
Packit Service |
310c69 |
const void *constP;
|
|
Packit Service |
310c69 |
void *notConst;
|
|
Packit Service |
310c69 |
} u = { .constP = pointer };
|
|
Packit Service |
310c69 |
FREE(u.notConst);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
/**
|
|
Packit Service |
310c69 |
* Wrapper which permits freeing a volatile pointer.
|
|
Packit Service |
310c69 |
*
|
|
Packit Service |
310c69 |
* @param pointer the pointer to be freed
|
|
Packit Service |
310c69 |
**/
|
|
Packit Service |
310c69 |
static INLINE void freeVolatile(volatile void *pointer)
|
|
Packit Service |
310c69 |
{
|
|
Packit Service |
310c69 |
union {
|
|
Packit Service |
310c69 |
volatile void *volP;
|
|
Packit Service |
310c69 |
void *notVol;
|
|
Packit Service |
310c69 |
} u = { .volP = pointer };
|
|
Packit Service |
310c69 |
FREE(u.notVol);
|
|
Packit Service |
310c69 |
}
|
|
Packit Service |
310c69 |
|
|
Packit Service |
310c69 |
#endif /* MEMORY_ALLOC_H */
|