Blame source/uds/memoryAlloc.h

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 */