gambas-source-code/main/share/gb_alloc_temp.h

494 lines
9.7 KiB
C
Raw Normal View History

/***************************************************************************
gb_alloc_temp.h
(c) 2000-2017 Benoît Minisini <g4mba5@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
***************************************************************************/
#define __GB_ALLOC_C
#include <config.h>
#ifdef HAVE_MALLOC_H
#include <malloc.h>
#endif
#include <stdlib.h>
#include "gb_common.h"
#include "gb_error.h"
#include "gb_alloc.h"
int MEMORY_count = 0;
//#define DEBUG_ME
//#define DO_NOT_PRINT_MEMORY
#if defined(DEBUG_ME) || DEBUG_MEMORY
size_t MEMORY_size = 0;
size_t MEMORY_pool_size = 0;
#endif
#if DEBUG_MEMORY
static int _id = 0;
ALLOC *_alloc = NULL;
#ifdef PROJECT_EXEC
extern char *DEBUG_get_current_position(void);
#endif
FILE *MEMORY_log;
#elif OPTIMIZE_MEMORY
#define SIZE_INC 16
#define SIZE_SHIFT 4
#define REAL_SIZE(_size) (((_size) + (SIZE_INC - 1)) & ~(SIZE_INC - 1))
#define POOL_SIZE 16
#define POOL_MAX 128
#define POOL_MAX_LEN (POOL_SIZE * SIZE_INC)
static size_t *_pool[POOL_SIZE] = { 0 };
static int _pool_count[POOL_SIZE] = { 0 };
/*static size_t *_first_alloc = 0;
static size_t *_max_alloc = 0;*/
#endif
int THROW_MEMORY()
{
THROW(E_MEMORY);
}
void MEMORY_init(void)
{
#if DEBUG_MEMORY
[DEVELOPMENT ENVIRONMENT] * BUG: The button that switches between form and class editor is not shown anymore when a module or a class is edited. [GB.GTK] * BUG: Font management was redesigned. It does not leak memory anymore, and now behaves like in gb.qt. * BUG: Tristate CheckBox controls now work as expected. * BUG: Destroy pending deleted controls before entering the event loop, to avoid some memory leaks if the event loop is immediately aborted. * BUG: Detach destroyed controls from their event listener, as in gb.qt. * BUG: Now menu shortcuts are active even if the menu bar is hidden. But the menu must be visible. To create an hidden active top-level menu, just set its Text property to NULL, but keep it visible. * NEW: Top-level menus with a void Text property are not shown anymore. * BUG: Showing and hiding top-level menu now work correctly. [GB.QT] * BUG: Font properties are correctly inherited between containers and children controls. * BUG: Showing a tray icon does not eat focus events anymore. * NEW: Top-level menus with a void Text property are not shown anymore. [GB.QT4] * BUG: Font properties are correctly inherited between containers and children controls. * BUG: Shortcut management was fixed. * BUG: Now menu shortcuts are active even if the menu bar is hidden. But the menu must be visible. To create an hidden active top-level menu, just set its Text property to NULL, but keep it visible. * NEW: Top-level menus with a void Text property are not shown anymore. * BUG: Showing and hiding top-level menu now work correctly. git-svn-id: svn://localhost/gambas/trunk@2034 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2009-06-22 13:16:34 +02:00
/*char path[256];
sprintf(path, "/tmp/gambas-memory-%d-%d.log", getuid(), getpid());
[DEVELOPMENT ENVIRONMENT] * BUG: The button that switches between form and class editor is not shown anymore when a module or a class is edited. [GB.GTK] * BUG: Font management was redesigned. It does not leak memory anymore, and now behaves like in gb.qt. * BUG: Tristate CheckBox controls now work as expected. * BUG: Destroy pending deleted controls before entering the event loop, to avoid some memory leaks if the event loop is immediately aborted. * BUG: Detach destroyed controls from their event listener, as in gb.qt. * BUG: Now menu shortcuts are active even if the menu bar is hidden. But the menu must be visible. To create an hidden active top-level menu, just set its Text property to NULL, but keep it visible. * NEW: Top-level menus with a void Text property are not shown anymore. * BUG: Showing and hiding top-level menu now work correctly. [GB.QT] * BUG: Font properties are correctly inherited between containers and children controls. * BUG: Showing a tray icon does not eat focus events anymore. * NEW: Top-level menus with a void Text property are not shown anymore. [GB.QT4] * BUG: Font properties are correctly inherited between containers and children controls. * BUG: Shortcut management was fixed. * BUG: Now menu shortcuts are active even if the menu bar is hidden. But the menu must be visible. To create an hidden active top-level menu, just set its Text property to NULL, but keep it visible. * NEW: Top-level menus with a void Text property are not shown anymore. * BUG: Showing and hiding top-level menu now work correctly. git-svn-id: svn://localhost/gambas/trunk@2034 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2009-06-22 13:16:34 +02:00
MEMORY_log = fopen(path, "w+");*/
MEMORY_log = stderr;
#endif
}
void MEMORY_clear_cache()
{
#if OPTIMIZE_MEMORY
int i;
void *ptr, *next;
size_t size = 0;
for (i = 0; i < POOL_SIZE; i++)
{
ptr = _pool[i];
while (ptr)
{
next = *((void **)ptr);
size += (i + 1) * SIZE_INC;
#ifdef DEBUG_ME
MEMORY_size -= (i + 1) * SIZE_INC;
#endif
free(ptr);
ptr = next;
}
_pool[i] = NULL;
_pool_count[i] = 0;
}
#ifdef DEBUG_ME
fprintf(stderr, "free %ld bytes [%ld / %p]\n", size, MEMORY_size, sbrk(0));
#endif
#endif
}
void MEMORY_exit(void)
{
MEMORY_clear_cache();
#if DEBUG_MEMORY
if (MEMORY_count)
{
fprintf(MEMORY_log, "\n*************************************************\n");
fprintf(MEMORY_log, "warning: %d allocation(s) non freed.\n", MEMORY_count);
while (_alloc)
{
fprintf(MEMORY_log, "<%d>\n", _alloc->id);
_alloc = _alloc->next;
}
}
fclose(MEMORY_log);
#else
if (MEMORY_count)
ERROR_warning("%d allocation(s) non freed.\n", MEMORY_count);
#endif
}
#if OPTIMIZE_MEMORY
#else
#if DEBUG_MEMORY
char *MEMORY_where_am_i(const char *file, int line, const char *func)
{
static char buffer[256];
snprintf(buffer, sizeof(buffer), "[%s] %s:%d", file, func, line);
return buffer;
}
#endif
#if DEBUG_MEMORY
void MEMORY_alloc(void *p_ptr, size_t size, const char *src)
{
ALLOC *alloc;
alloc = (ALLOC *)malloc(sizeof(ALLOC) + size);
if (!alloc)
THROW(E_MEMORY);
_id++;
alloc->id = _id;
alloc->prev = NULL;
alloc->next = _alloc;
alloc->size = size;
if (_alloc)
_alloc->prev = alloc;
_alloc = alloc;
*((void **)p_ptr) = (char *)alloc + sizeof(ALLOC);
MEMORY_count++;
MEMORY_size += size;
#ifndef DO_NOT_PRINT_MEMORY
#ifdef PROJECT_EXEC
fprintf(MEMORY_log, "%s: ", DEBUG_get_current_position());
#endif
fprintf(MEMORY_log, "<%d> %s: MEMORY_alloc(%d) -> %p\n", _id, src, (int)size, (char *)alloc + sizeof(ALLOC));
fflush(MEMORY_log);
/*if (_id == 2700)
BREAKPOINT();*/
#endif
}
#else
void MEMORY_alloc(void *p_ptr, size_t size)
{
void *alloc;
alloc = malloc(size);
if (!alloc)
THROW(E_MEMORY);
*((void **)p_ptr) = alloc;
MEMORY_count++;
}
#endif
#if DEBUG_MEMORY
void MEMORY_alloc_zero(void *p_ptr, size_t size, const char *src)
{
MEMORY_alloc(p_ptr, size, src);
memset(*((void **)p_ptr), 0, size);
}
#else
void MEMORY_alloc_zero(void *p_ptr, size_t size)
{
void *alloc;
alloc = calloc(size, 1);
if (!alloc)
THROW(E_MEMORY);
*((void **)p_ptr) = alloc;
MEMORY_count++;
}
#endif
#if DEBUG_MEMORY
void MEMORY_realloc(void *p_ptr, size_t size, const char *src)
{
ALLOC *alloc = (ALLOC *)(*((char **)p_ptr) - sizeof(ALLOC));
ALLOC *old = alloc;
if (size == 0)
{
MEMORY_free(p_ptr, src);
return;
}
alloc = realloc(alloc, sizeof(ALLOC) + size);
if (!alloc)
THROW(E_MEMORY);
MEMORY_size += size - alloc->size;
if (_alloc == old)
_alloc = alloc;
if (alloc->prev)
alloc->prev->next = alloc;
if (alloc->next)
alloc->next->prev = alloc;
#ifndef DO_NOT_PRINT_MEMORY
#ifdef PROJECT_EXEC
fprintf(MEMORY_log, "%s: ", DEBUG_get_current_position());
#endif
fprintf(MEMORY_log, "<%d> %s: MEMORY_realloc(%p, %d) -> %p\n", alloc->id, src, *((void **)p_ptr), (int)size, (char *)alloc + sizeof(ALLOC));
fflush(MEMORY_log);
#endif
*((void **)p_ptr) = (char *)alloc + sizeof(ALLOC);
}
#else
void MEMORY_realloc(void *p_ptr, size_t size)
{
void *alloc = *((void **)p_ptr);
if (size == 0)
{
MEMORY_free(p_ptr);
return;
}
alloc = realloc(alloc, size);
if (!alloc)
THROW(E_MEMORY);
*((void **)p_ptr) = alloc;
}
#endif
#if DEBUG_MEMORY
void MEMORY_free(void *p_ptr, const char *src)
{
ALLOC *alloc = (ALLOC *)(*((char **)p_ptr) - sizeof(ALLOC));
if (!(*((void **)p_ptr)))
return;
if (alloc->prev)
alloc->prev->next = alloc->next;
if (alloc->next)
alloc->next->prev = alloc->prev;
if (alloc == _alloc)
_alloc = alloc->next;
#ifndef DO_NOT_PRINT_MEMORY
#ifdef PROJECT_EXEC
fprintf(MEMORY_log, "%s: ", DEBUG_get_current_position());
#endif
fprintf(MEMORY_log, "<%d> %s: MEMORY_free(%p) / %p\n", alloc->id, src, *((void **)p_ptr), (char *)alloc + sizeof(ALLOC));
fflush(MEMORY_log);
#endif
MEMORY_size -= alloc->size;
//*((long *)alloc) = 0x31415926;
free(alloc);
*((void **)p_ptr) = NULL;
MEMORY_count--;
}
#else
void MEMORY_free(void *p_ptr)
{
void *alloc = *((void **)p_ptr);
******** Merged /branches/64bits r918:1003 into /trunk [CONFIGURATION] * NEW: 64 bits port. [EXAMPLES] * BUG: Fixed the AnalogWatch example. [WIKI CGI SCRIPT] * NEW: Some little cosmetic changes. [INTERPRETER] * NEW: The extern function implementation has been redesigned and is now based on libffi, so that it works on 64 bits system. Because of a flaw in the compiler design, projects that use the Pointer datatype must be recompiled to be used on a 64 bits system. This flaw will be fixed in Gambas 3. * OPT: Put some tables into read-only memory. About 1000 bytes are saved for each running interpreter, except the first one. * BUG: Does not crash anymore if a component cannot be loaded. * NEW: Spanish translation updated. * NEW: A new interpreter API for returning a pointer. [COMPILER] * BUG: Correctly compiles LONG constants inside code. [GB.DEBUG] * BUG: Compiles and links the gb.debug components with the thread libraries. [GB.DB.SQLITE3] * BUG: Getting the primary index of a table without primary index is safe now. [GB.GTK] * BUG: Modified the GLib priority of watched descriptors, as the main loop could enter in a loop in which user interface events were not managed. * BUG: Message boxes use application title without crashing now. [GB.OPENGL] * BUG: Disable dead code. [GB.QT.EXT] * BUG: TextEdit.TextWidth and TextEdit.TextHeight were not declared as read-only properties. [GB.XML.XSLT] * BUG: XSLT class is now declared as being not creatable. git-svn-id: svn://localhost/gambas/trunk@1006 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2008-01-17 22:39:26 +01:00
if (!alloc)
return;
free(alloc);
*((void **)p_ptr) = NULL;
MEMORY_count--;
}
#endif
[DEVELOPMENT ENVIRONMENT] * NEW: English and french tips were updated. A new tip was added. * NEW: Files that were opened at project close are automatically reopened   when the project is loaded again. * NEW: A warning message is displayed when the GNU translation tools are not installed. * BUG: The code editor method combo-box is correctly updated now. * BUG: Some fixes in the automatic completion. * BUG: Replace points by dash in the name of packages generated by the IDE packager. * NEW: Updated russian translation * NEW: Updated french translation [DATABASE MANAGER] * NEW: Updated russian translation [EXAMPLES] * BUG: Fixed the Gravity and the GameOfLife examples so that they do not   use public form controls anymore. [INTERPRETER] * OPT: Many optimizations in the string substitution routines, the internal datatype conversions, the INPUT and LINE INPUT instructions, the error messages generation, the object and string reference counting, and the memory allocation routines. * NEW: Opening a device file in direct mode (FOR READ/WRITE) is now automatically non blocking. * OPT: Lof() now only tries its different methods (ioctl and lseek) once. * BUG: Val() now ignores thousand separators characters at the end of the number. * NEW: A new flag for enabling the stack trace generation at each error. [GB.DEBUG] * BUG: The gb.debug component interface declaration was not 64-bits aware. [GB.EVAL] * BUG: The Highlight.Purge() method now correctly deals with non-ASCII characters. [GB.FORM] * BUG: TableView.Edit() does not raise a "read-only combo-box" error anymore. [GB.FORM.DIALOG] * BUG: Dialog buttons now are never cut. [GB.GTK] * BUG: Cached drawing areas are correctly redrawn now. * BUG: Loading big images now works correctly. There is apparently a bug in the GTK+ image loader, and I found a workaround. * BUG: Message boxes correctly display the text of their buttons now. [GB.QT] * BUG: The Open, and initial Move and Resize event of embedded forms are now always raised when you call the Show method or if you set the Visible property. Before, it was raised when the embedded form was actually shown. [GB.SETTINGS] * NEW: Settings are now stored in ~/.config/gambasX, where X is the gambas version number. * BUG: Strings are correctly quoted inside the settings file now. [GB.WEB] * NEW: Application.Protocol is a new property that allows to tell the   component that the protocol is not necessarily "http". git-svn-id: svn://localhost/gambas/trunk@1153 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2008-03-11 14:29:47 +01:00
#endif // OPTIMIZE_MEMORY
#if OPTIMIZE_MEMORY
//void DEBUG_print_current_backtrace(void);
//static bool _print_backtrace = FALSE;
void *my_malloc(size_t len)
{
size_t *ptr;
int size = REAL_SIZE((int)len + sizeof(size_t));
int pool = (size / SIZE_INC) - 1;
MEMORY_count++;
if (pool < POOL_SIZE)
{
if (_pool_count[pool])
{
ptr = _pool[pool];
#if defined(DEBUG_ME) && !defined(DO_NOT_PRINT_MEMORY)
MEMORY_pool_size -= size;
fprintf(stderr, "my_malloc: %d bytes from pool #%d -> %p (%p) [%ld / %ld]\n", size, pool, ptr + 1, sbrk(0), MEMORY_size - MEMORY_pool_size, MEMORY_size);
#endif
_pool[pool] = *((void **)ptr);
_pool_count[pool]--;
*ptr++ = size;
return ptr;
}
}
#ifdef DEBUG_ME
MEMORY_size += size;
#endif
ptr = malloc(size);
if (!ptr)
THROW_MEMORY();
#if defined(DEBUG_ME) && !defined(DO_NOT_PRINT_MEMORY)
fprintf(stderr, "my_malloc: %d bytes from malloc -> %p (%p) [%ld / %ld]\n", size, ptr + 1, sbrk(0), MEMORY_size - MEMORY_pool_size, MEMORY_size);
#endif
/*if (!_first_alloc)
_first_alloc = ptr;
if (ptr > _max_alloc && !_print_backtrace)
{
_max_alloc = ptr;
fprintf(stderr, "%ld\n", (char *)_max_alloc - (char *)_first_alloc + size);
_print_backtrace = TRUE;
DEBUG_print_current_backtrace();
_print_backtrace = FALSE;
}*/
*ptr++ = size;
return ptr;
}
void my_free(void *alloc)
{
size_t *ptr;
int size;
int pool;
if (!alloc)
return;
MEMORY_count--;
ptr = alloc;
ptr--;
size = (int)*ptr;
pool = (size / SIZE_INC) - 1;
//if (ptr < (_first_alloc + (_max_alloc - _first_alloc) / 2))
if (1)
{
if (pool < POOL_SIZE)
{
if (_pool_count[pool] < POOL_MAX)
{
#if defined(DEBUG_ME) && !defined(DO_NOT_PRINT_MEMORY)
MEMORY_pool_size += size;
fprintf(stderr, "my_free: %p (%p) -> %d bytes to pool #%d [%ld / %ld]\n", alloc, sbrk(0), size, pool, MEMORY_size - MEMORY_pool_size, MEMORY_size);
#endif
*((void **)ptr) = _pool[pool];
_pool[pool] = ptr;
_pool_count[pool]++;
return;
}
}
}
#ifdef DEBUG_ME
MEMORY_size -= size;
#ifndef DO_NOT_PRINT_MEMORY
fprintf(stderr, "my_free: %p (%p) -> %d bytes freed [%ld / %ld]\n", alloc, sbrk(0), size, MEMORY_size - MEMORY_pool_size, MEMORY_size);
#endif
#endif
free(ptr);
}
void *my_realloc(void *alloc, size_t new_len)
{
size_t *ptr;
int size;
int new_size;
if (!alloc)
return my_malloc(new_len);
ptr = alloc;
ptr--;
size = (int)*ptr;
new_size = REAL_SIZE(new_len + sizeof(size_t));
if (size == new_size)
return alloc;
#if defined(DEBUG_ME) && !defined(DO_NOT_PRINT_MEMORY)
fprintf(stderr, "my_realloc: %p (%p) -> %d ==> %d\n", alloc, sbrk(0), size, new_size);
#endif
if (new_len == 0)
{
my_free(alloc);
return NULL;
}
else if (size > POOL_MAX_LEN && new_size > POOL_MAX_LEN)
{
#ifdef DEBUG_ME
MEMORY_size += new_size - size;
#ifndef DO_NOT_PRINT_MEMORY
fprintf(stderr, "my_realloc: %p (%p) -> %d bytes reallocated to %d [%ld / %ld]\n", alloc, sbrk(0), size, new_size, MEMORY_size - MEMORY_pool_size, MEMORY_size);
#endif
#endif
ptr = realloc(ptr, new_size);
if (!ptr)
THROW_MEMORY();
*ptr++ = new_size;
return ptr;
}
else
{
size_t *nptr = my_malloc(new_len);
nptr--;
if (new_size < size)
memcpy(nptr, ptr, new_size);
else
memcpy(nptr, ptr, size);
my_free(alloc);
*nptr++ = new_size;
return nptr;
}
}
#endif