| | |
| | | /* |
| | | Simple DirectMedia Layer |
| | | Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org> |
| | | Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org> |
| | | |
| | | This software is provided 'as-is', without any express or implied |
| | | warranty. In no event will the authors be held liable for any damages |
| | |
| | | misrepresented as being the original software. |
| | | 3. This notice may not be removed or altered from any source distribution. |
| | | */ |
| | | #include "SDL_config.h" |
| | | |
| | | #if defined(__clang_analyzer__) && !defined(SDL_DISABLE_ANALYZE_MACROS) |
| | | #define SDL_DISABLE_ANALYZE_MACROS 1 |
| | | #endif |
| | | |
| | | #include "../SDL_internal.h" |
| | | |
| | | /* This file contains portable memory management functions for SDL */ |
| | | |
| | | #include "SDL_stdinc.h" |
| | | #include "SDL_atomic.h" |
| | | #include "SDL_error.h" |
| | | |
| | | #if defined(HAVE_MALLOC) |
| | | |
| | | void *SDL_malloc(size_t size) |
| | | { |
| | | return malloc(size); |
| | | } |
| | | |
| | | void *SDL_calloc(size_t nmemb, size_t size) |
| | | { |
| | | return calloc(nmemb, size); |
| | | } |
| | | |
| | | void *SDL_realloc(void *ptr, size_t size) |
| | | { |
| | | return realloc(ptr, size); |
| | | } |
| | | |
| | | void SDL_free(void *ptr) |
| | | { |
| | | free(ptr); |
| | | } |
| | | |
| | | #else /* the rest of this is a LOT of tapdancing to implement malloc. :) */ |
| | | |
| | | #ifndef HAVE_MALLOC |
| | | #define LACKS_SYS_TYPES_H |
| | | #define LACKS_STDIO_H |
| | | #define LACKS_STRINGS_H |
| | | #define LACKS_STRING_H |
| | | #define LACKS_STDLIB_H |
| | | #define ABORT |
| | | #define USE_LOCKS 1 |
| | | #define USE_DL_PREFIX |
| | | |
| | | /* |
| | | This is a version (aka dlmalloc) of malloc/free/realloc written by |
| | |
| | | #define MMAP_CLEARS 0 /* WINCE and some others apparently don't clear */ |
| | | #endif /* WIN32 */ |
| | | |
| | | #ifdef __OS2__ |
| | | #define INCL_DOS |
| | | #include <os2.h> |
| | | #define HAVE_MMAP 1 |
| | | #define HAVE_MORECORE 0 |
| | | #define LACKS_SYS_MMAN_H |
| | | #endif /* __OS2__ */ |
| | | |
| | | #if defined(DARWIN) || defined(_DARWIN) |
| | | /* Mac OSX docs advise not to use sbrk; it seems better to use mmap */ |
| | | #ifndef HAVE_MORECORE |
| | |
| | | #define MALLINFO_FIELD_TYPE size_t |
| | | #endif /* MALLINFO_FIELD_TYPE */ |
| | | |
| | | #ifndef memset |
| | | #define memset SDL_memset |
| | | #endif |
| | | #ifndef memcpy |
| | | #define memcpy SDL_memcpy |
| | | #define malloc SDL_malloc |
| | | #define calloc SDL_calloc |
| | | #define realloc SDL_realloc |
| | | #define free SDL_free |
| | | #endif |
| | | |
| | | /* |
| | | mallopt tuning options. SVID/XPG defines four standard parameter |
| | |
| | | #define IS_MMAPPED_BIT (SIZE_T_ONE) |
| | | #define USE_MMAP_BIT (SIZE_T_ONE) |
| | | |
| | | #ifndef WIN32 |
| | | #if !defined(WIN32) && !defined (__OS2__) |
| | | #define CALL_MUNMAP(a, s) munmap((a), (s)) |
| | | #define MMAP_PROT (PROT_READ|PROT_WRITE) |
| | | #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) |
| | |
| | | #endif /* MAP_ANONYMOUS */ |
| | | |
| | | #define DIRECT_MMAP(s) CALL_MMAP(s) |
| | | |
| | | #elif defined(__OS2__) |
| | | |
| | | /* OS/2 MMAP via DosAllocMem */ |
| | | static void* os2mmap(size_t size) { |
| | | void* ptr; |
| | | if (DosAllocMem(&ptr, size, OBJ_ANY|PAG_COMMIT|PAG_READ|PAG_WRITE) && |
| | | DosAllocMem(&ptr, size, PAG_COMMIT|PAG_READ|PAG_WRITE)) |
| | | return MFAIL; |
| | | return ptr; |
| | | } |
| | | |
| | | #define os2direct_mmap(n) os2mmap(n) |
| | | |
| | | /* This function supports releasing coalesed segments */ |
| | | static int os2munmap(void* ptr, size_t size) { |
| | | while (size) { |
| | | ULONG ulSize = size; |
| | | ULONG ulFlags = 0; |
| | | if (DosQueryMem(ptr, &ulSize, &ulFlags) != 0) |
| | | return -1; |
| | | if ((ulFlags & PAG_BASE) == 0 ||(ulFlags & PAG_COMMIT) == 0 || |
| | | ulSize > size) |
| | | return -1; |
| | | if (DosFreeMem(ptr) != 0) |
| | | return -1; |
| | | ptr = ( void * ) ( ( char * ) ptr + ulSize ); |
| | | size -= ulSize; |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | #define CALL_MMAP(s) os2mmap(s) |
| | | #define CALL_MUNMAP(a, s) os2munmap((a), (s)) |
| | | #define DIRECT_MMAP(s) os2direct_mmap(s) |
| | | |
| | | #else /* WIN32 */ |
| | | |
| | | /* Win32 MMAP via VirtualAlloc */ |
| | |
| | | unique mparams values are initialized only once. |
| | | */ |
| | | |
| | | #ifndef WIN32 |
| | | #if !defined(WIN32) && !defined(__OS2__) |
| | | /* By default use posix locks */ |
| | | #include <pthread.h> |
| | | #define MLOCK_T pthread_mutex_t |
| | |
| | | #endif /* HAVE_MORECORE */ |
| | | |
| | | static MLOCK_T magic_init_mutex = PTHREAD_MUTEX_INITIALIZER; |
| | | |
| | | #elif defined(__OS2__) |
| | | #define MLOCK_T HMTX |
| | | #define INITIAL_LOCK(l) DosCreateMutexSem(0, l, 0, FALSE) |
| | | #define ACQUIRE_LOCK(l) DosRequestMutexSem(*l, SEM_INDEFINITE_WAIT) |
| | | #define RELEASE_LOCK(l) DosReleaseMutexSem(*l) |
| | | #if HAVE_MORECORE |
| | | static MLOCK_T morecore_mutex; |
| | | #endif /* HAVE_MORECORE */ |
| | | static MLOCK_T magic_init_mutex; |
| | | |
| | | #else /* WIN32 */ |
| | | /* |
| | |
| | | } |
| | | RELEASE_MAGIC_INIT_LOCK(); |
| | | |
| | | #ifndef WIN32 |
| | | #if !defined(WIN32) && !defined(__OS2__) |
| | | mparams.page_size = malloc_getpagesize; |
| | | mparams.granularity = ((DEFAULT_GRANULARITY != 0) ? |
| | | DEFAULT_GRANULARITY : mparams.page_size); |
| | | #elif defined (__OS2__) |
| | | /* if low-memory is used, os2munmap() would break |
| | | if it were anything other than 64k */ |
| | | mparams.page_size = 4096u; |
| | | mparams.granularity = 65536u; |
| | | #else /* WIN32 */ |
| | | { |
| | | SYSTEM_INFO system_info; |
| | |
| | | internal_malloc_stats(mstate m) |
| | | { |
| | | if (!PREACTION(m)) { |
| | | #ifndef LACKS_STDIO_H |
| | | size_t maxfp = 0; |
| | | #endif |
| | | size_t fp = 0; |
| | | size_t used = 0; |
| | | check_malloc_state(m); |
| | | if (is_initialized(m)) { |
| | | msegmentptr s = &m->seg; |
| | | #ifndef LACKS_STDIO_H |
| | | maxfp = m->max_footprint; |
| | | #endif |
| | | fp = m->footprint; |
| | | used = fp - (m->topsize + TOP_FOOT_SIZE); |
| | | |
| | |
| | | |
| | | #endif /* !HAVE_MALLOC */ |
| | | |
| | | #ifdef HAVE_MALLOC |
| | | #define real_malloc malloc |
| | | #define real_calloc calloc |
| | | #define real_realloc realloc |
| | | #define real_free free |
| | | #else |
| | | #define real_malloc dlmalloc |
| | | #define real_calloc dlcalloc |
| | | #define real_realloc dlrealloc |
| | | #define real_free dlfree |
| | | #endif |
| | | |
| | | /* Memory functions used by SDL that can be replaced by the application */ |
| | | static struct |
| | | { |
| | | SDL_malloc_func malloc_func; |
| | | SDL_calloc_func calloc_func; |
| | | SDL_realloc_func realloc_func; |
| | | SDL_free_func free_func; |
| | | SDL_atomic_t num_allocations; |
| | | } s_mem = { |
| | | real_malloc, real_calloc, real_realloc, real_free, { 0 } |
| | | }; |
| | | |
| | | void SDL_GetMemoryFunctions(SDL_malloc_func *malloc_func, |
| | | SDL_calloc_func *calloc_func, |
| | | SDL_realloc_func *realloc_func, |
| | | SDL_free_func *free_func) |
| | | { |
| | | if (malloc_func) { |
| | | *malloc_func = s_mem.malloc_func; |
| | | } |
| | | if (calloc_func) { |
| | | *calloc_func = s_mem.calloc_func; |
| | | } |
| | | if (realloc_func) { |
| | | *realloc_func = s_mem.realloc_func; |
| | | } |
| | | if (free_func) { |
| | | *free_func = s_mem.free_func; |
| | | } |
| | | } |
| | | |
| | | int SDL_SetMemoryFunctions(SDL_malloc_func malloc_func, |
| | | SDL_calloc_func calloc_func, |
| | | SDL_realloc_func realloc_func, |
| | | SDL_free_func free_func) |
| | | { |
| | | if (!malloc_func) { |
| | | return SDL_InvalidParamError("malloc_func"); |
| | | } |
| | | if (!calloc_func) { |
| | | return SDL_InvalidParamError("calloc_func"); |
| | | } |
| | | if (!realloc_func) { |
| | | return SDL_InvalidParamError("realloc_func"); |
| | | } |
| | | if (!free_func) { |
| | | return SDL_InvalidParamError("free_func"); |
| | | } |
| | | |
| | | s_mem.malloc_func = malloc_func; |
| | | s_mem.calloc_func = calloc_func; |
| | | s_mem.realloc_func = realloc_func; |
| | | s_mem.free_func = free_func; |
| | | return 0; |
| | | } |
| | | |
| | | int SDL_GetNumAllocations(void) |
| | | { |
| | | return SDL_AtomicGet(&s_mem.num_allocations); |
| | | } |
| | | |
| | | void *SDL_malloc(size_t size) |
| | | { |
| | | void *mem; |
| | | |
| | | if (!size) { |
| | | size = 1; |
| | | } |
| | | |
| | | mem = s_mem.malloc_func(size); |
| | | if (mem) { |
| | | SDL_AtomicIncRef(&s_mem.num_allocations); |
| | | } |
| | | return mem; |
| | | } |
| | | |
| | | void *SDL_calloc(size_t nmemb, size_t size) |
| | | { |
| | | void *mem; |
| | | |
| | | if (!nmemb || !size) { |
| | | nmemb = 1; |
| | | size = 1; |
| | | } |
| | | |
| | | mem = s_mem.calloc_func(nmemb, size); |
| | | if (mem) { |
| | | SDL_AtomicIncRef(&s_mem.num_allocations); |
| | | } |
| | | return mem; |
| | | } |
| | | |
| | | void *SDL_realloc(void *ptr, size_t size) |
| | | { |
| | | void *mem; |
| | | |
| | | if (!ptr && !size) { |
| | | size = 1; |
| | | } |
| | | |
| | | mem = s_mem.realloc_func(ptr, size); |
| | | if (mem && !ptr) { |
| | | SDL_AtomicIncRef(&s_mem.num_allocations); |
| | | } |
| | | return mem; |
| | | } |
| | | |
| | | void SDL_free(void *ptr) |
| | | { |
| | | if (!ptr) { |
| | | return; |
| | | } |
| | | |
| | | s_mem.free_func(ptr); |
| | | (void)SDL_AtomicDecRef(&s_mem.num_allocations); |
| | | } |
| | | |
| | | /* vi: set ts=4 sw=4 expandtab: */ |