aboutsummaryrefslogtreecommitdiff
path: root/drivers/unix/memory_pool_static_malloc.cpp
diff options
context:
space:
mode:
authorJuan Linietsky2014-02-09 22:10:30 -0300
committerJuan Linietsky2014-02-09 22:10:30 -0300
commit0b806ee0fc9097fa7bda7ac0109191c9c5e0a1ac (patch)
tree276c4d099e178eb67fbd14f61d77b05e3808e9e3 /drivers/unix/memory_pool_static_malloc.cpp
parent0e49da1687bc8192ed210947da52c9e5c5f301bb (diff)
downloadgodot-0b806ee0fc9097fa7bda7ac0109191c9c5e0a1ac.tar.gz
godot-0b806ee0fc9097fa7bda7ac0109191c9c5e0a1ac.tar.zst
godot-0b806ee0fc9097fa7bda7ac0109191c9c5e0a1ac.zip
Diffstat (limited to 'drivers/unix/memory_pool_static_malloc.cpp')
-rw-r--r--drivers/unix/memory_pool_static_malloc.cpp419
1 files changed, 419 insertions, 0 deletions
diff --git a/drivers/unix/memory_pool_static_malloc.cpp b/drivers/unix/memory_pool_static_malloc.cpp
new file mode 100644
index 000000000..fa1266b2d
--- /dev/null
+++ b/drivers/unix/memory_pool_static_malloc.cpp
@@ -0,0 +1,419 @@
+/*************************************************************************/
+/* memory_pool_static_malloc.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "memory_pool_static_malloc.h"
+#include "error_macros.h"
+#include "os/memory.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include "os/copymem.h"
+#include "os/os.h"
+
+/**
+ * NOTE NOTE NOTE NOTE
+ * in debug mode, this prepends the memory size to the allocated block
+ * so BE CAREFUL!
+ */
+
+
+void* MemoryPoolStaticMalloc::alloc(size_t p_bytes,const char *p_description) {
+
+ #if DFAULT_ALIGNMENT == 1
+
+ return _alloc(p_bytes, p_description);
+
+ #else
+
+ int total = p_bytes + DEFAULT_ALIGNMENT;
+ uint8_t* ptr = (uint8_t*)_alloc(total, p_description);
+ ERR_FAIL_COND_V( !ptr, ptr );
+ int ofs = (DEFAULT_ALIGNMENT - ((uintptr_t)ptr & (DEFAULT_ALIGNMENT - 1)));
+ ptr[ofs-1] = ofs;
+ return (void*)(ptr + ofs);
+ #endif
+};
+
+void* MemoryPoolStaticMalloc::_alloc(size_t p_bytes,const char *p_description) {
+
+ ERR_FAIL_COND_V(p_bytes==0,0);
+
+ MutexLock lock(mutex);
+
+#ifdef DEBUG_MEMORY_ENABLED
+ void *mem=malloc(p_bytes+sizeof(RingPtr)); /// add for size and ringlist
+
+ if (!mem) {
+ printf("**ERROR: out of memory while allocating %i bytes by %s?\n",(int) p_bytes, p_description);
+ printf("**ERROR: memory usage is %i\n", (int)get_total_usage());
+ };
+
+ ERR_FAIL_COND_V(!mem,0); //out of memory, or unreasonable request
+
+ /* setup the ringlist element */
+
+ RingPtr *ringptr = (RingPtr*)mem;
+
+ /* setup the ringlist element data (description and size ) */
+
+ ringptr->size = p_bytes;
+ ringptr->descr=p_description;
+
+ if (ringlist) { /* existing ringlist */
+
+ /* assign next */
+ ringptr->next = ringlist->next;
+ ringlist->next = ringptr;
+ /* assign prev */
+ ringptr->prev = ringlist;
+ ringptr->next->prev = ringptr;
+ } else { /* non existing ringlist */
+
+ ringptr->next=ringptr;
+ ringptr->prev=ringptr;
+ ringlist=ringptr;
+
+ }
+
+ total_mem+=p_bytes;
+
+ /* update statistics */
+ if (total_mem > max_mem )
+ max_mem = total_mem;
+
+ total_pointers++;
+
+ if (total_pointers > max_pointers)
+ max_pointers=total_pointers;
+
+ return ringptr + 1; /* return memory after ringptr */
+
+#else
+ void *mem=malloc(p_bytes);
+
+ ERR_FAIL_COND_V(!mem,0); //out of memory, or unreasonable request
+ return mem;
+#endif
+}
+
+
+void* MemoryPoolStaticMalloc::realloc(void *p_memory,size_t p_bytes) {
+
+ #if DFAULT_ALIGNMENT == 1
+
+ return _realloc(p_memory,p_bytes);
+ #else
+ if (!p_memory)
+ return alloc(p_bytes);
+
+ int total = p_bytes + DEFAULT_ALIGNMENT;
+ uint8_t* mem = (uint8_t*)p_memory;
+ int ofs = *(mem-1);
+ mem = mem - ofs;
+ uint8_t* ptr = (uint8_t*)_realloc(mem, total);
+ ERR_FAIL_COND_V(ptr == NULL, NULL);
+ int new_ofs = (DEFAULT_ALIGNMENT - ((uintptr_t)ptr & (DEFAULT_ALIGNMENT - 1)));
+ if (new_ofs != ofs) {
+
+ //printf("realloc moving %i bytes\n", p_bytes);
+ movemem((ptr + new_ofs), (ptr + ofs), p_bytes);
+ ptr[new_ofs-1] = new_ofs;
+ };
+ return ptr + new_ofs;
+ #endif
+};
+
+void* MemoryPoolStaticMalloc::_realloc(void *p_memory,size_t p_bytes) {
+
+ if (p_memory==NULL) {
+
+ return alloc( p_bytes );
+ }
+
+ if (p_bytes<=0) {
+
+ this->free(p_memory);
+ ERR_FAIL_COND_V( p_bytes < 0 , NULL );
+ return NULL;
+ }
+
+ MutexLock lock(mutex);
+
+#ifdef DEBUG_MEMORY_ENABLED
+
+
+ RingPtr *ringptr = (RingPtr*)p_memory;
+ ringptr--; /* go back an element to find the tingptr */
+
+ bool single_element = (ringptr->next == ringptr) && (ringptr->prev == ringptr);
+ bool is_list = ( ringlist == ringptr );
+
+
+ RingPtr *new_ringptr=(RingPtr*)::realloc(ringptr, p_bytes+sizeof(RingPtr));
+
+ ERR_FAIL_COND_V( new_ringptr == 0, NULL ); /// reallocation failed
+
+ /* actualize mem used */
+ total_mem -= new_ringptr->size;
+ new_ringptr->size = p_bytes;
+ total_mem += new_ringptr->size;
+
+ if (total_mem > max_mem ) //update statistics
+ max_mem = total_mem;
+
+ if (new_ringptr == ringptr )
+ return ringptr + 1; // block didn't move, don't do anything
+
+ if (single_element) {
+
+ new_ringptr->next=new_ringptr;
+ new_ringptr->prev=new_ringptr;
+ } else {
+
+ new_ringptr->next->prev=new_ringptr;
+ new_ringptr->prev->next=new_ringptr;
+ }
+
+ if (is_list)
+ ringlist=new_ringptr;
+
+
+ return new_ringptr + 1;
+
+#else
+ return ::realloc( p_memory, p_bytes );
+#endif
+}
+
+void MemoryPoolStaticMalloc::free(void *p_ptr) {
+
+ ERR_FAIL_COND( !MemoryPoolStatic::get_singleton());
+
+ #if DFAULT_ALIGNMENT == 1
+
+ _free(p_ptr);
+ #else
+
+ uint8_t* mem = (uint8_t*)p_ptr;
+ int ofs = *(mem-1);
+ mem = mem - ofs;
+
+ _free(mem);
+ #endif
+};
+
+
+void MemoryPoolStaticMalloc::_free(void *p_ptr) {
+
+ MutexLock lock(mutex);
+
+#ifdef DEBUG_MEMORY_ENABLED
+
+ if (p_ptr==0) {
+ printf("**ERROR: STATIC ALLOC: Attempted free of NULL pointer.\n");
+ return;
+ };
+
+ RingPtr *ringptr = (RingPtr*)p_ptr;
+
+ ringptr--; /* go back an element to find the ringptr */
+
+
+#if 0
+ { // check for existing memory on free.
+ RingPtr *p = ringlist;
+
+ bool found=false;
+
+ if (ringlist) {
+ do {
+ if (p==ringptr) {
+ found=true;
+ break;
+ }
+
+ p=p->next;
+ } while (p!=ringlist);
+ }
+
+ if (!found) {
+ printf("**ERROR: STATIC ALLOC: Attempted free of unknown pointer at %p\n",(ringptr+1));
+ return;
+ }
+
+ }
+#endif
+ /* proceed to erase */
+
+ bool single_element = (ringptr->next == ringptr) && (ringptr->prev == ringptr);
+ bool is_list = ( ringlist == ringptr );
+
+ if (single_element) {
+ /* just get rid of it */
+ ringlist=0;
+
+ } else {
+ /* auto-remove from ringlist */
+ if (is_list)
+ ringlist=ringptr->next;
+
+ ringptr->prev->next = ringptr->next;
+ ringptr->next->prev = ringptr->prev;
+ }
+
+ total_mem -= ringptr->size;
+ total_pointers--;
+ // catch more errors
+ zeromem(ringptr,sizeof(RingPtr)+ringptr->size);
+ ::free(ringptr); //just free that pointer
+
+#else
+ ERR_FAIL_COND(p_ptr==0);
+
+ ::free(p_ptr);
+#endif
+}
+
+
+size_t MemoryPoolStaticMalloc::get_available_mem() const {
+
+ return 0xffffffff;
+}
+
+size_t MemoryPoolStaticMalloc::get_total_usage() {
+
+#ifdef DEBUG_MEMORY_ENABLED
+
+ return total_mem;
+#else
+ return 0;
+#endif
+
+}
+
+size_t MemoryPoolStaticMalloc::get_max_usage() {
+
+ return max_mem;
+}
+
+/* Most likely available only if memory debugger was compiled in */
+int MemoryPoolStaticMalloc::get_alloc_count() {
+
+ return 0;
+}
+void * MemoryPoolStaticMalloc::get_alloc_ptr(int p_alloc_idx) {
+
+ return 0;
+}
+const char* MemoryPoolStaticMalloc::get_alloc_description(int p_alloc_idx) {
+
+
+ return "";
+}
+size_t MemoryPoolStaticMalloc::get_alloc_size(int p_alloc_idx) {
+
+ return 0;
+}
+
+void MemoryPoolStaticMalloc::dump_mem_to_file(const char* p_file) {
+
+#ifdef DEBUG_MEMORY_ENABLED
+
+ ERR_FAIL_COND( !ringlist ); /** WTF BUG !? */
+ RingPtr *p = ringlist;
+ FILE *f = fopen(p_file,"wb");
+
+ do {
+ fprintf(f,"%p-%i-%s\n", p+1, (int)p->size, (p->descr?p->descr:"") );
+ p=p->next;
+ } while (p!=ringlist);
+
+ fclose(f);
+#endif
+
+}
+
+MemoryPoolStaticMalloc::MemoryPoolStaticMalloc() {
+
+#ifdef DEBUG_MEMORY_ENABLED
+ total_mem=0;
+ total_pointers=0;
+ ringlist=0;
+ max_mem=0;
+ max_pointers=0;
+
+
+#endif
+
+ mutex=NULL;
+#ifndef NO_THREADS
+
+ mutex=Mutex::create(); // at this point, this should work
+#endif
+
+}
+
+
+MemoryPoolStaticMalloc::~MemoryPoolStaticMalloc() {
+
+ Mutex *old_mutex=mutex;
+ mutex=NULL;
+ if (old_mutex)
+ memdelete(old_mutex);
+
+#ifdef DEBUG_MEMORY_ENABLED
+
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ if (total_mem > 0 ) {
+ printf("**ERROR: STATIC ALLOC: ** MEMORY LEAKS DETECTED **\n");
+ printf("**ERROR: STATIC ALLOC: %i bytes of memory in use at exit.\n",(int)total_mem);
+
+ if (1){
+ printf("**ERROR: STATIC ALLOC: Following is the list of leaked allocations: \n");
+
+ ERR_FAIL_COND( !ringlist ); /** WTF BUG !? */
+ RingPtr *p = ringlist;
+
+ do {
+ printf("\t%p - %i bytes - %s\n", (RingPtr*)(p+1), (int)p->size, (p->descr?p->descr:"") );
+ p=p->next;
+ } while (p!=ringlist);
+
+ printf("**ERROR: STATIC ALLOC: End of Report.\n");
+ };
+
+ printf("mem - max %i, pointers %i, leaks %i.\n",(int)max_mem,max_pointers,(int)total_mem);
+ } else {
+
+ printf("INFO: mem - max %i, pointers %i, no leaks.\n",(int)max_mem,max_pointers);
+ }
+ }
+
+#endif
+}
+
+