efl/legacy/evas/src/lib/main.c

374 lines
8.9 KiB
C

#include "Evas.h"
#include "evas_common.h"
#include "evas_private.h"
int _evas_alloc_error = 0;
static int _evas_debug_init = 0;
static int _evas_debug_show = 0;
static int _evas_debug_abort = 0;
/**
* Return if any allocation errors have occured during the prior function
* @return The allocation error flag
*
* This function will return if any memory allocation errors occured during,
* and what kind they were. The return value will be one of
* EVAS_ALLOC_ERROR_NONE, EVAS_ALLOC_ERROR_FATAL or EVAS_ALLOC_ERROR_RECOVERED
* with each meaning something different.
*
* EVAS_ALLOC_ERROR_NONE means that no errors occured at all and the function
* worked as expected.
*
* EVAS_ALLOC_ERROR_FATAL means the function was completely unable to perform
* its job and will have exited as cleanly as possible. The programmer
* should consider this as a sign of very low memory and should try and safely
* recover from the prior functions failure (or try free up memory elsewhere
* and try again after more memory is freed).
*
* EVAS_ALLOC_ERROR_RECOVERED means that an allocation error occured, but was
* recovered from by evas finding memory of its own it has allocated and
* freeing what it sees as not really usefully allocated memory. What is freed
* may vary. Evas may reduce the resolution of images, free cached images or
* fonts, trhow out pre-rendered data, reduce the complexity of change lists
* etc. Evas and the program will function as per normal after this, but this
* is a sign of low memory, and it is suggested that the program try and
* identify memory it doesn't need, and free it.
*
* Example:
* @code
* extern Evas_Object *object;
* void callback (void *data, Evas *e, Evas_Object *obj, void *event_info);
*
* evas_object_event_callback_add(object, EVAS_CALLBACK_MOUSE_DOWN, callback, NULL);
* if (evas_alloc_error() == EVAS_ALLOC_ERROR_FATAL)
* {
* fprintf(stderr, "ERROR: Completely unable to attach callabck. Must\n");
* fprintf(stderr, " destroy object now as it cannot be used.\n");
* evas_object_del(object);
* object = NULL;
* fprintf(stderr, "WARNING: Memory is really low. Cleaning out RAM.\n");
* my_memory_cleanup();
* }
* if (evas_alloc_error() == EVAS_ALLOC_ERROR_RECOVERED)
* {
* fprintf(stderr, "WARNING: Memory is really low. Cleaning out RAM.\n");
* my_memory_cleanup();
* }
* @endcode
*/
int
evas_alloc_error(void)
{
return _evas_alloc_error;
}
/* free cached items only in ram for speed reasons. return 0 if cant free */
int
evas_mem_free(int mem_required)
{
return 0;
}
/* start reducing quality of images etc. return 0 if cant free anything */
int
evas_mem_degrade(int mem_required)
{
return 0;
}
void *
evas_mem_calloc(int size)
{
void *ptr;
ptr = calloc(1, size);
if (ptr) return ptr;
MERR_BAD();
while ((!ptr) && (evas_mem_free(size))) ptr = calloc(1, size);
if (ptr) return ptr;
while ((!ptr) && (evas_mem_degrade(size))) ptr = calloc(1, size);
if (ptr) return ptr;
MERR_FATAL();
return NULL;
}
void
evas_debug_error(void)
{
if (!_evas_debug_init)
{
if (getenv("EVAS_DEBUG_SHOW")) _evas_debug_show = 1;
if (getenv("EVAS_DEBUG_ABORT")) _evas_debug_abort = 1;
_evas_debug_init = 1;
}
if (_evas_debug_show)
fprintf(stderr,
"*** EVAS ERROR: Evas Magic Check Failed!!!\n");
}
void
evas_debug_input_null(void)
{
if (!_evas_debug_init)
{
if (getenv("EVAS_DEBUG_SHOW")) _evas_debug_show = 1;
if (getenv("EVAS_DEBUG_ABORT")) _evas_debug_abort = 1;
_evas_debug_init = 1;
}
if (_evas_debug_show)
fprintf(stderr,
" Input object pointer is NULL!\n");
if (_evas_debug_abort) abort();
}
void
evas_debug_magic_null(void)
{
if (!_evas_debug_init)
{
if (getenv("EVAS_DEBUG_SHOW")) _evas_debug_show = 1;
if (getenv("EVAS_DEBUG_ABORT")) _evas_debug_abort = 1;
_evas_debug_init = 1;
}
if (_evas_debug_show)
fprintf(stderr,
" Input object is zero'ed out (maybe a freed object or zero-filled RAM)!\n");
if (_evas_debug_abort) abort();
}
void
evas_debug_magic_wrong(DATA32 expected, DATA32 supplied)
{
if (!_evas_debug_init)
{
if (getenv("EVAS_DEBUG_SHOW")) _evas_debug_show = 1;
if (getenv("EVAS_DEBUG_ABORT")) _evas_debug_abort = 1;
_evas_debug_init = 1;
}
if (_evas_debug_show)
fprintf(stderr,
" Input object is wrong type\n"
" Expected: %08x - %s\n"
" Supplied: %08x - %s\n",
expected, evas_debug_magic_string_get(expected),
supplied, evas_debug_magic_string_get(supplied));
if (_evas_debug_abort) abort();
}
void
evas_debug_generic(const char *str)
{
if (!_evas_debug_init)
{
if (getenv("EVAS_DEBUG_SHOW")) _evas_debug_show = 1;
if (getenv("EVAS_DEBUG_ABORT")) _evas_debug_abort = 1;
_evas_debug_init = 1;
}
if (_evas_debug_show)
fprintf(stderr,
"*** EVAS ERROR:\n"
"%s", (char *)str);
if (_evas_debug_abort) abort();
}
char *
evas_debug_magic_string_get(DATA32 magic)
{
switch (magic)
{
case MAGIC_EVAS:
return "Evas";
break;
case MAGIC_OBJ:
return "Evas_Object";
break;
case MAGIC_OBJ_RECTANGLE:
return "Evas_Object (Rectangle)";
break;
case MAGIC_OBJ_LINE:
return "Evas_Object (Line)";
break;
case MAGIC_OBJ_GRADIENT:
return "Evas_Object (Gradient)";
break;
case MAGIC_OBJ_POLYGON:
return "Evas_Object (Polygon)";
break;
case MAGIC_OBJ_IMAGE:
return "Evas_Object (Image)";
break;
case MAGIC_OBJ_TEXT:
return "Evas_Object (Text)";
break;
case MAGIC_OBJ_SMART:
return "Evas_Object (Smart)";
break;
default:
return "<UNKNOWN>";
};
return "<UNKNOWN>";
}
typedef struct _Pool Pool;
struct _Pool
{
int usage;
void *base;
Pool *prev, *next;
};
Pool *
_evas_mp_pool_new(Evas_Mempool *pool)
{
Pool *p;
void **ptr;
int item_alloc, i;
item_alloc = ((pool->item_size + sizeof(void *) - 1) / sizeof(void *)) * sizeof(void *);
p = malloc(sizeof(Pool) + (pool->pool_size * item_alloc));
ptr = (void **)(((unsigned char *)p) + sizeof(Pool));
p->usage = 0;
p->base = ptr;
for (i = 0; i < pool->pool_size - 1; i++)
{
*ptr = (void **)(((unsigned char *)ptr) + item_alloc);
ptr = *ptr;
}
*ptr = NULL;
return p;
}
void
_evas_mp_pool_free(Pool *p)
{
free(p);
}
//#define NOPOOL
void *
evas_mempool_malloc(Evas_Mempool *pool, int size)
#ifdef NOPOOL
{
return malloc(size);
}
#else
{
Pool *p;
void *mem;
for (p = pool->first; p; p = p->next) // look 4 pool from 2nd bucket on
{
if (p->base) // base is not NULL - has a free slot
{
if (p->prev)
{
if (pool->last == p) pool->last = p->prev;
p->prev->next = p->next;
p->prev = NULL;
p->next = pool->first;
p->next->prev = p;
pool->first = p;
}
break;
}
}
if (!p) // we have reached the end of the list - no free pools
{
p = _evas_mp_pool_new(pool);
if (!p) return NULL;
p->prev = NULL;
p->next = pool->first;
if (p->next) p->next->prev = p;
if (!pool->last) pool->last = p;
pool->first = p;
}
mem = p->base; // this points to the next free block - so take it
p->base = *((void **)mem); // base now points to the next free block
if (!p->base) // move to end - it just filled up
{
if (p->next)
{
if (p->prev) p->prev->next = p->next;
else pool->first = p->next;
p->next->prev = p->prev;
((Pool *)pool->last)->next = p;
p->prev = pool->last;
p->next = NULL;
pool->last = p;
}
}
p->usage++;
pool->usage++;
return mem;
}
#endif
void
evas_mempool_free(Evas_Mempool *pool, void *ptr)
#ifdef NOPOOL
{
free(ptr);
}
#else
{
Pool *p;
void *pmem;
int item_alloc, psize;
item_alloc = ((pool->item_size + sizeof(void *) - 1) / sizeof(void *)) * sizeof(void *);
psize = item_alloc * pool->pool_size;
for (p = (Pool *)(pool->first); p; p = p->next) // look 4 pool
{
pmem = (void *)(((unsigned char *)p) + sizeof(Pool)); // pool mem base
if ((ptr >= pmem) && (ptr < (pmem + psize))) // is it in pool mem?
{
*((void **)ptr) = p->base; // freed node points to prev free node
p->base = ptr; // next free node is now the one we freed
p->usage--;
pool->usage--;
if (p->usage == 0) // free bucket
{
if (p->prev) p->prev->next = p->next;
if (p->next) p->next->prev = p->prev;
if (pool->last == p) pool->last = p->prev;
if (pool->first == p) pool->first = p->next;
_evas_mp_pool_free(p);
}
else
{
if (p->prev) // if not the first - move to front
{
p->prev->next = p->next;
if (p->next) p->next->prev = p->prev;
if (pool->last == p) pool->last = p->prev;
p->prev = NULL;
p->next = pool->first;
p->next->prev = p;
pool->first = p;
}
}
break;
}
}
}
#endif
void *
evas_mempool_calloc(Evas_Mempool *pool, int size)
{
void *mem;
mem = evas_mempool_malloc(pool, size);
memset(mem, 0, size);
return mem;
}