mirror of
https://github.com/adtools/clib2.git
synced 2025-12-08 14:59:05 +00:00
Unused slabs which get recycled are no longer reinitialized from scratch if their chunk size matches what the allocator needed. If the chunk size matches, the list of available chunks is left unchanged, and just the various counters are reset. Added __get_slab_stats() function. Added support for global __slab_purge_threshold tuning variable. Added a short test program for the slab allocator. The malloc-test program was linked against the wrong object file in GNUmakefile.68k. Fixed.
454 lines
16 KiB
C
454 lines
16 KiB
C
/*
|
|
* $Id: stdlib.h,v 1.19 2008-04-30 14:34:03 obarthel Exp $
|
|
*
|
|
* :ts=4
|
|
*
|
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
|
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
|
* All rights reserved.
|
|
*
|
|
* 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.
|
|
*
|
|
* - Neither the name of Olaf Barthel nor the names of contributors
|
|
* may be used to endorse or promote products derived from this
|
|
* software without specific prior written permission.
|
|
*
|
|
* 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 OWNER 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.
|
|
*
|
|
*****************************************************************************
|
|
*
|
|
* Documentation and source code for this library, and the most recent library
|
|
* build are available from <http://sourceforge.net/projects/clib2>.
|
|
*
|
|
*****************************************************************************
|
|
*/
|
|
|
|
#ifndef _STDLIB_H
|
|
#define _STDLIB_H
|
|
|
|
/****************************************************************************/
|
|
|
|
#ifndef _STDDEF_H
|
|
#include <stddef.h>
|
|
#endif /* _STDDEF_H */
|
|
|
|
/****************************************************************************/
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif /* __cplusplus */
|
|
|
|
/****************************************************************************/
|
|
|
|
/* Maximum number of bytes in a multibyte character */
|
|
#define MB_CUR_MAX 2
|
|
|
|
/****************************************************************************/
|
|
|
|
/* The maximum value that can be returned by the rand() function */
|
|
#define RAND_MAX 2147483647
|
|
|
|
/****************************************************************************/
|
|
|
|
/* Return values to be passed to exit() */
|
|
#define EXIT_FAILURE 20
|
|
#define EXIT_SUCCESS 0
|
|
|
|
/****************************************************************************/
|
|
|
|
/* Data structures used by the div() and ldiv() functions */
|
|
typedef struct { int quot; int rem; } div_t;
|
|
typedef struct { long quot; long rem; } ldiv_t;
|
|
|
|
/****************************************************************************/
|
|
|
|
extern int mblen(const char *s, size_t n);
|
|
extern int mbtowc(wchar_t *pwc, const char *s, size_t n);
|
|
extern int wctomb(char *s, wchar_t wchar);
|
|
extern size_t mbstowcs(wchar_t *pwcs, const char *s, size_t n);
|
|
extern size_t wcstombs(char *s, const wchar_t *pwcs, size_t n);
|
|
|
|
/****************************************************************************/
|
|
|
|
extern void *malloc(size_t size);
|
|
extern void *calloc(size_t num_elements,size_t element_size);
|
|
extern void free(void *ptr);
|
|
extern void *realloc(void *ptr,size_t size);
|
|
|
|
#ifdef __MEM_DEBUG
|
|
extern void *__malloc(size_t size,const char *file,int line);
|
|
extern void *__calloc(size_t num_elements,size_t element_size,const char *file,int line);
|
|
extern void __free(void *ptr,const char *file,int line);
|
|
extern void *__realloc(void *ptr,size_t size,const char *file,int line);
|
|
|
|
#define malloc(size) __malloc((size),__FILE__,__LINE__)
|
|
#define calloc(num_elements,element_size) __calloc((num_elements),(element_size),__FILE__,__LINE__)
|
|
#define free(ptr) __free((ptr),__FILE__,__LINE__)
|
|
#define realloc(ptr,size) __realloc((ptr),(size),__FILE__,__LINE__)
|
|
#endif /* __MEM_DEBUG */
|
|
|
|
/****************************************************************************/
|
|
|
|
extern int abs(int x);
|
|
extern long labs(long x);
|
|
extern div_t div(int n,int d);
|
|
extern ldiv_t ldiv(long n,long d);
|
|
|
|
/****************************************************************************/
|
|
|
|
extern int rand(void);
|
|
extern void srand(unsigned seed);
|
|
|
|
/****************************************************************************/
|
|
|
|
extern int system(const char *command);
|
|
|
|
/****************************************************************************/
|
|
|
|
extern void exit(int status);
|
|
extern void abort(void);
|
|
|
|
/****************************************************************************/
|
|
|
|
extern int atexit(void (*)(void));
|
|
|
|
/****************************************************************************/
|
|
|
|
extern char * getenv(const char *name);
|
|
|
|
/****************************************************************************/
|
|
|
|
extern void * bsearch(const void *key, const void *base, size_t count, size_t size,
|
|
int (*compare)(const void * key,const void * value));
|
|
extern void qsort(void *base,size_t count,size_t size,
|
|
int (*compare)(const void * element1,const void * element2));
|
|
|
|
/****************************************************************************/
|
|
|
|
extern double strtod(const char *str, char ** ptr);
|
|
extern long strtol(const char *str, char **ptr, int base);
|
|
extern unsigned long strtoul(const char *str, char **ptr, int base);
|
|
|
|
/****************************************************************************/
|
|
|
|
extern double atof(const char *str);
|
|
extern int atoi(const char *str);
|
|
extern long atol(const char *str);
|
|
|
|
/****************************************************************************/
|
|
|
|
/* The following is not part of the ISO 'C' (1994) standard. */
|
|
|
|
/****************************************************************************/
|
|
|
|
extern void _exit(int status);
|
|
extern int rand_r(unsigned int * seed);
|
|
|
|
/****************************************************************************/
|
|
|
|
/*
|
|
* You can switch the built-in memory allocator, which is a thin wrapper
|
|
* around the AmigaOS built-in memory management system, to use a slab
|
|
* allocator. For this to work, you need to declare a global variable
|
|
* and set it to the size of the slabs to be used. This variable must
|
|
* be initialized at load time when the clib2 startup code runs:
|
|
*
|
|
* unsigned long __slab_max_size = 4096;
|
|
*/
|
|
|
|
extern unsigned long __slab_max_size;
|
|
|
|
/*
|
|
* The slab allocator will periodically free all currently unused memory.
|
|
* You can control how much memory should be released, instead of
|
|
* releasing everything.
|
|
*
|
|
* This would make the slab allocator release only up to 512 KBytes of
|
|
* unused memory at a time:
|
|
*
|
|
* unsigned long __slab_purge_threshold = 512 * 1024;
|
|
*/
|
|
|
|
extern unsigned long __slab_purge_threshold;
|
|
|
|
/****************************************************************************/
|
|
|
|
/*
|
|
* If you are using the slab allocator and need to quickly release the
|
|
* memory of all slabs which are currently unused, you can call the
|
|
* following function to do so.
|
|
*
|
|
* Please note that this function works within the context of the memory
|
|
* allocation system and is not safe to call from interrupt code. It may
|
|
* break a Forbid() or Disable() condition.
|
|
*/
|
|
extern void __free_unused_slabs(void);
|
|
|
|
/****************************************************************************/
|
|
|
|
/*
|
|
* You can obtain runtime statistics about the slab allocator by
|
|
* invoking the __get_slab_usage() function which in turn invokes
|
|
* your callback function for each single slab currently in play.
|
|
*
|
|
* Your callback function must return 0 if it wants to be called again,
|
|
* for the next slab, or return -1 to stop. Note that your callback
|
|
* function may not be called if the slab allocator is currently
|
|
* not operational.
|
|
*
|
|
* Please note that this function works within the context of the memory
|
|
* allocation system and is not safe to call from interrupt code. It may
|
|
* break a Forbid() or Disable() condition.
|
|
*/
|
|
|
|
/****************************************************************************/
|
|
|
|
/* This is what your callback function will see when it is invoked. */
|
|
struct __slab_usage_information
|
|
{
|
|
/* The size of all slabs, in bytes. */
|
|
size_t sui_slab_size;
|
|
|
|
/* Number of allocations which are not managed by slabs, but
|
|
* are handled separate.
|
|
*/
|
|
size_t sui_num_single_allocations;
|
|
|
|
/* Total number of bytes allocated for memory not managed
|
|
* by slabs. This includes the management overhead for
|
|
* each allocation.
|
|
*/
|
|
size_t sui_total_single_allocation_size;
|
|
|
|
/* Number of slabs currently in play. This can be 0. */
|
|
size_t sui_num_slabs;
|
|
|
|
/* Number of currently unused slabs which contain no data. */
|
|
size_t sui_num_empty_slabs;
|
|
|
|
/* Number of slabs in use which are completely filled with data. */
|
|
size_t sui_num_full_slabs;
|
|
|
|
/* Total number of bytes allocated for all slabs. */
|
|
size_t sui_total_slab_allocation_size;
|
|
|
|
/*
|
|
* The following data is updated for each slab which
|
|
* your callback function sees.
|
|
*/
|
|
|
|
/* Index number of the slab being reported (0 = no slabs are in use). */
|
|
int sui_slab_index;
|
|
|
|
/* How large are the memory chunks managed by this slab? */
|
|
size_t sui_chunk_size;
|
|
|
|
/* How many memory chunks fit into this slab? */
|
|
size_t sui_num_chunks;
|
|
|
|
/* How many memory chunks in this slab are being used? */
|
|
size_t sui_num_chunks_used;
|
|
|
|
/* How many time was this slab reused without reinitializing
|
|
* it all over again from scratch?
|
|
*/
|
|
size_t sui_num_reused;
|
|
};
|
|
|
|
/****************************************************************************/
|
|
|
|
typedef int (*__slab_usage_callback)(const struct __slab_usage_information * sui);
|
|
|
|
/****************************************************************************/
|
|
|
|
void __get_slab_usage(__slab_usage_callback callback);
|
|
|
|
/****************************************************************************/
|
|
|
|
/*
|
|
* You can obtain runtime statistics about the memory allocations
|
|
* which the slab allocator did not fit into slabs. This works
|
|
* just like __get_slab_usage() in that the callback function
|
|
* you provide will be called for each single allocation that
|
|
* is not part of a slab.
|
|
*
|
|
* Your callback function must return 0 if it wants to be called again,
|
|
* for the next slab, or return -1 to stop. Note that your callback
|
|
* function may not be called if the slab allocator did not
|
|
* allocate memory outside of slabs.
|
|
*
|
|
* Please note that this function works within the context of the memory
|
|
* allocation system and is not safe to call from interrupt code. It may
|
|
* break a Forbid() or Disable() condition.
|
|
*/
|
|
|
|
/* This is what your callback function will see when it is invoked. */
|
|
struct __slab_allocation_information
|
|
{
|
|
/* Number of allocations which are not managed by slabs, but
|
|
* are handled separate.
|
|
*/
|
|
size_t sai_num_single_allocations;
|
|
|
|
/* Total number of bytes allocated for memory not managed
|
|
* by slabs. This includes the management overhead for
|
|
* each allocation.
|
|
*/
|
|
size_t sai_total_single_allocation_size;
|
|
|
|
/*
|
|
* The following data is updated for each slab which
|
|
* your callback function sees.
|
|
*/
|
|
|
|
/* Index number of the allocation being reported (0 = no allocations
|
|
* outside of slabs are in use).
|
|
*/
|
|
int sai_allocation_index;
|
|
|
|
/* Size of this allocation, as requested by the program which
|
|
* called malloc(), realloc() or alloca().
|
|
*/
|
|
size_t sai_allocation_size;
|
|
|
|
/* Total size of this allocation, including management data
|
|
* structure overhead.
|
|
*/
|
|
size_t sai_total_allocation_size;
|
|
};
|
|
|
|
/****************************************************************************/
|
|
|
|
typedef int (*__slab_allocation_callback)(const struct __slab_allocation_information * sui);
|
|
|
|
/****************************************************************************/
|
|
|
|
void __get_slab_allocations(__slab_allocation_callback callback);
|
|
|
|
/****************************************************************************/
|
|
|
|
/*
|
|
* You can obtain information about the memory managed by the slab allocator,
|
|
* as well as additional information about the slab allocator's performance
|
|
* in JSON format. This format can be used for more detailed analysis.
|
|
*
|
|
* You supply a function which will be called for each line of the JSON
|
|
* data produced. You can store this data in a file, or in the clipboard,
|
|
* for later use. Your function must return 0 if it wants to be called
|
|
* again, or return -1 if it wants to stop (e.g. if an error occured
|
|
* when writing the JSON data to disk). The same "user_data" pointer which
|
|
* you pass to __get_slab_stats() will be passed to your callback function.
|
|
*
|
|
* Please note that this function works within the context of the memory
|
|
* allocation system and is not safe to call from interrupt code. It may
|
|
* break a Forbid() or Disable() condition.
|
|
*/
|
|
|
|
typedef int (* __slab_status_callback)(void * user_data, const char * line, size_t line_length);
|
|
|
|
/****************************************************************************/
|
|
|
|
extern void __get_slab_stats(void * user_data, __slab_status_callback callback);
|
|
|
|
/****************************************************************************/
|
|
|
|
/*
|
|
* You can request to use the alloca() variant that actually does allocate
|
|
* memory from the system rather than the current stack frame, which will
|
|
* ease stack requirements but may not release allocate memory immediately.
|
|
* In order to do so, add #define __USE_CLIB2_ALLOCA to your program, or
|
|
* -D__USE_CLIB2_ALLOCA to your build makefile. For GCC you will also have
|
|
* to compile your program with the -fno-builtin switch to override the
|
|
* built-in alloca() function.
|
|
*/
|
|
|
|
#if defined(alloca)
|
|
#undef alloca
|
|
#endif /* alloca */
|
|
|
|
#if defined(__GNUC__) && !defined(__USE_CLIB2_ALLOCA)
|
|
#define alloca(size) __builtin_alloca(size)
|
|
#else
|
|
extern void * alloca(size_t size);
|
|
|
|
#ifdef __MEM_DEBUG
|
|
extern void * __alloca(size_t size,const char *file,int line);
|
|
|
|
#define alloca(size) __alloca((size),__FILE__,__LINE__)
|
|
#else
|
|
/* This is necessary because some applications key off the fact that
|
|
alloca is a symbol defined by the preprocessor. */
|
|
#define alloca alloca
|
|
#endif /* __MEM_DEBUG */
|
|
#endif /* __GNUC__ */
|
|
|
|
/****************************************************************************/
|
|
|
|
extern int setenv(const char *name, const char *value, int overwrite);
|
|
extern int putenv(const char *string);
|
|
extern int unsetenv(const char *name);
|
|
extern char * mktemp(char * name_template);
|
|
extern int mkstemp(char *name_template);
|
|
extern char * mkdtemp(char *name_template);
|
|
|
|
/****************************************************************************/
|
|
|
|
/* The following is not part of the ISO 'C' (1994) standard, but it should
|
|
be part of ISO/IEC 9899:1999, also known as "C99". */
|
|
|
|
/****************************************************************************/
|
|
|
|
#if defined(__GNUC__) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L))
|
|
|
|
/****************************************************************************/
|
|
|
|
extern long long strtoll(const char *str, char **ptr, int base);
|
|
extern unsigned long long strtoull(const char *str, char **ptr, int base);
|
|
extern long long atoll(const char *str);
|
|
|
|
/****************************************************************************/
|
|
|
|
typedef struct { long long quot; long long rem; } lldiv_t;
|
|
|
|
/****************************************************************************/
|
|
|
|
extern long long llabs(long long x);
|
|
extern lldiv_t lldiv(long long n,long long d);
|
|
|
|
/****************************************************************************/
|
|
|
|
#endif /* __GNUC__ || (__STDC_VERSION__ && __STDC_VERSION__ >= 199901L) */
|
|
|
|
/****************************************************************************/
|
|
|
|
extern float strtof(const char *str, char ** ptr);
|
|
|
|
/****************************************************************************/
|
|
|
|
extern void _Exit(int status);
|
|
|
|
/****************************************************************************/
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif /* __cplusplus */
|
|
|
|
/****************************************************************************/
|
|
|
|
#endif /* _STDLIB_H */
|