efl/src/lib/ecore/ecore.c

1054 lines
25 KiB
C

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <locale.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#ifdef HAVE_LANGINFO_H
# include <langinfo.h>
#endif
#if defined(HAVE_SYS_MMAN_H) || defined(HAVE_EVIL)
# include <sys/mman.h>
#endif
#ifdef HAVE_SYSTEMD
# include <systemd/sd-daemon.h>
#endif
#ifdef HAVE_EVIL
# include <Evil.h>
#endif
#include <Eina.h>
#include "Ecore.h"
#include "ecore_private.h"
#if HAVE_MALLINFO
#include <malloc.h>
static Ecore_Version _version = { VMAJ, VMIN, VMIC, VREV };
EAPI Ecore_Version *ecore_version = &_version;
#define KEEP_MAX(Global, Local) \
if (Global < (Local)) \
Global = Local;
static Eina_Bool _ecore_memory_statistic(void *data);
static int _ecore_memory_max_total = 0;
static int _ecore_memory_max_free = 0;
static pid_t _ecore_memory_pid = 0;
#endif
Eo *_ecore_parent = NULL;
static const char *_ecore_magic_string_get(Ecore_Magic m);
static int _ecore_init_count = 0;
int _ecore_log_dom = -1;
int _ecore_fps_debug = 0;
typedef struct _Ecore_Safe_Call Ecore_Safe_Call;
struct _Ecore_Safe_Call
{
union {
Ecore_Cb async;
Ecore_Data_Cb sync;
} cb;
void *data;
Eina_Lock m;
Eina_Condition c;
int current_id;
Eina_Bool sync : 1;
Eina_Bool suspend : 1;
};
#ifdef HAVE_SYSTEMD
static Eina_Bool _systemd_watchdog_cb(void *data);
#endif
static void _ecore_main_loop_thread_safe_call(Ecore_Safe_Call *order);
static void _thread_safe_cleanup(void *data);
static void _thread_callback(void *data,
void *buffer,
unsigned int nbyte);
static Eina_List *_thread_cb = NULL;
static Ecore_Pipe *_thread_call = NULL;
static Eina_Lock _thread_safety;
static const int wakeup = 42;
static int _thread_loop = 0;
static Eina_Lock _thread_mutex;
static Eina_Condition _thread_cond;
static Eina_Lock _thread_feedback_mutex;
static Eina_Condition _thread_feedback_cond;
static Eina_Lock _thread_id_lock;
static int _thread_id = -1;
static int _thread_id_max = 0;
static int _thread_id_update = 0;
static Eina_Bool _ecore_low_memory = EINA_FALSE;
static Eina_Bool _ecore_low_battery = EINA_FALSE;
#ifdef HAVE_SYSTEMD
static Ecore_Timer *_systemd_watchdog = NULL;
#endif
Eina_Lock _ecore_main_loop_lock;
int _ecore_main_lock_count;
/** OpenBSD does not define CODESET
* FIXME ??
*/
#ifndef CODESET
# define CODESET "INVALID"
#endif
static Eina_Prefix *_ecore_pfx = NULL;
static Eina_Array *module_list = NULL;
static void
ecore_system_modules_load(void)
{
char buf[PATH_MAX] = "";
char *path;
if (getenv("EFL_RUN_IN_TREE"))
{
struct stat st;
snprintf(buf, sizeof(buf), "%s/src/modules/ecore/system",
PACKAGE_BUILD_DIR);
if (stat(buf, &st) == 0)
{
const char *built_modules[] = {
#ifdef HAVE_SYSTEMD
"systemd",
#endif
NULL
};
const char **itr;
for (itr = built_modules; *itr != NULL; itr++)
{
snprintf(buf, sizeof(buf),
"%s/src/modules/ecore/system/%s/.libs",
PACKAGE_BUILD_DIR, *itr);
module_list = eina_module_list_get(module_list, buf,
EINA_FALSE, NULL, NULL);
}
if (module_list)
eina_module_list_load(module_list);
return;
}
}
path = eina_module_environment_path_get("ECORE_MODULES_DIR",
"/ecore/system");
if (path)
{
module_list = eina_module_arch_list_get(module_list, path, MODULE_ARCH);
free(path);
}
path = eina_module_environment_path_get("HOME", "/.ecore/system");
if (path)
{
module_list = eina_module_arch_list_get(module_list, path, MODULE_ARCH);
free(path);
}
snprintf(buf, sizeof(buf), "%s/ecore/system",
eina_prefix_lib_get(_ecore_pfx));
module_list = eina_module_arch_list_get(module_list, buf, MODULE_ARCH);
eina_module_list_load(module_list);
}
static void
ecore_system_modules_unload(void)
{
if (module_list)
{
eina_module_list_free(module_list);
eina_array_free(module_list);
module_list = NULL;
}
}
/**
* @addtogroup Ecore_Init_Group
*
* @{
*/
/**
* Set up connections, signal handlers, sockets etc.
* @return 1 or greater on success, 0 otherwise
*
* This function sets up all singal handlers and the basic event loop. If it
* succeeds, 1 will be returned, otherwise 0 will be returned.
*
* @code
* #include <Ecore.h>
*
* int main(int argc, char **argv)
* {
* if (!ecore_init())
* {
* printf("ERROR: Cannot init Ecore!\n");
* return -1;
* }
* ecore_main_loop_begin();
* ecore_shutdown();
* }
* @endcode
*/
EAPI int
ecore_init(void)
{
if (++_ecore_init_count != 1)
return _ecore_init_count;
setlocale(LC_CTYPE, "");
/*
if (strcmp(nl_langinfo(CODESET), "UTF-8"))
{
WRN("Not a utf8 locale!");
}
*/
#ifdef HAVE_EVIL
if (!evil_init())
return --_ecore_init_count;
#endif
if (!eina_init())
goto shutdown_evil;
_ecore_log_dom = eina_log_domain_register("ecore", ECORE_DEFAULT_LOG_COLOR);
if (_ecore_log_dom < 0)
{
EINA_LOG_ERR("Ecore was unable to create a log domain.");
goto shutdown_log_dom;
}
_ecore_pfx = eina_prefix_new(NULL, ecore_init,
"ECORE", "ecore", "checkme",
PACKAGE_BIN_DIR, PACKAGE_LIB_DIR,
PACKAGE_DATA_DIR, PACKAGE_DATA_DIR);
if (!_ecore_pfx)
{
ERR("Could not get ecore installation prefix");
goto shutdown_log_dom;
}
eo_init();
if (getenv("ECORE_FPS_DEBUG")) _ecore_fps_debug = 1;
if (_ecore_fps_debug) _ecore_fps_debug_init();
if (!ecore_mempool_init()) goto shutdown_mempool;
_ecore_main_loop_init();
_ecore_signal_init();
#ifndef HAVE_EXOTIC
_ecore_exe_init();
#endif
_ecore_thread_init();
_ecore_glib_init();
_ecore_job_init();
_ecore_time_init();
_ecore_coroutine_init();
eina_lock_new(&_thread_mutex);
eina_condition_new(&_thread_cond, &_thread_mutex);
eina_lock_new(&_thread_feedback_mutex);
eina_condition_new(&_thread_feedback_cond, &_thread_feedback_mutex);
_thread_call = _ecore_pipe_add(_thread_callback, NULL);
eina_lock_new(&_thread_safety);
eina_lock_new(&_thread_id_lock);
eina_lock_new(&_ecore_main_loop_lock);
#if HAVE_MALLINFO
if (getenv("ECORE_MEM_STAT"))
{
_ecore_memory_pid = getpid();
ecore_animator_add(_ecore_memory_statistic, NULL);
}
#endif
#if defined(GLIB_INTEGRATION_ALWAYS)
if (_ecore_glib_always_integrate) ecore_main_loop_glib_integrate();
#endif
_ecore_parent = eo_add(ECORE_PARENT_CLASS, NULL);
#ifdef HAVE_SYSTEMD
if (getenv("WATCHDOG_USEC"))
{
double sec;
sec = ((double) atoi(getenv("WATCHDOG_USEC"))) / 1000 / 1000;
_systemd_watchdog = ecore_timer_add(sec / 2, _systemd_watchdog_cb, NULL);
unsetenv("WATCHDOG_USEC");
INF("Setup systemd watchdog to : %f", sec);
_systemd_watchdog_cb(NULL);
}
#endif
eina_log_timing(_ecore_log_dom,
EINA_LOG_STATE_STOP,
EINA_LOG_STATE_INIT);
ecore_system_modules_load();
return _ecore_init_count;
shutdown_mempool:
ecore_mempool_shutdown();
eo_shutdown();
shutdown_log_dom:
eina_shutdown();
shutdown_evil:
#ifdef HAVE_EVIL
evil_shutdown();
#endif
return --_ecore_init_count;
}
/**
* Shut down connections, signal handlers sockets etc.
*
* @return 0 if ecore shuts down, greater than 0 otherwise.
* This function shuts down all things set up in ecore_init() and cleans up all
* event queues, handlers, filters, timers, idlers, idle enterers/exiters
* etc. set up after ecore_init() was called.
*
* Do not call this function from any callback that may be called from the main
* loop, as the main loop will then fall over and not function properly.
*/
EAPI int
ecore_shutdown(void)
{
Ecore_Pipe *p;
/*
* take a lock here because _ecore_event_shutdown() does callbacks
*/
_ecore_lock();
if (_ecore_init_count <= 0)
{
ERR("Init count not greater than 0 in shutdown.");
_ecore_unlock();
return 0;
}
if (--_ecore_init_count != 0)
goto unlock;
ecore_system_modules_unload();
eina_log_timing(_ecore_log_dom,
EINA_LOG_STATE_START,
EINA_LOG_STATE_SHUTDOWN);
#ifdef HAVE_SYSTEMD
if (_systemd_watchdog)
{
ecore_timer_del(_systemd_watchdog);
_systemd_watchdog = NULL;
}
#endif
if (_ecore_fps_debug) _ecore_fps_debug_shutdown();
_ecore_coroutine_shutdown();
_ecore_poller_shutdown();
_ecore_animator_shutdown();
_ecore_glib_shutdown();
_ecore_job_shutdown();
_ecore_thread_shutdown();
/* this looks horrible - a hack for now, but something to note. as
* we delete the _thread_call pipe a thread COULD be doing
* ecore_pipe_write() or what not to it at the same time - we
* must ensure all possible users of this _thread_call are finished
* and exited before we delete it here */
/*
* ok - this causes other valgrind complaints regarding glib aquiring
* locks internally. so fix bug a or bug b. let's leave the original
* bug in then and leave this as a note for now
*/
/*
* It should be fine now as we do wait for thread to shutdown before
* we try to destroy the pipe.
*/
p = _thread_call;
_thread_call = NULL;
_ecore_pipe_wait(p, 1, 0.1);
_ecore_pipe_del(p);
eina_lock_free(&_thread_safety);
eina_condition_free(&_thread_cond);
eina_lock_free(&_thread_mutex);
eina_condition_free(&_thread_feedback_cond);
eina_lock_free(&_thread_feedback_mutex);
eina_lock_free(&_thread_id_lock);
#ifndef HAVE_EXOTIC
_ecore_exe_shutdown();
#endif
_ecore_idle_enterer_shutdown();
_ecore_idle_exiter_shutdown();
_ecore_idler_shutdown();
_ecore_timer_shutdown();
_ecore_event_shutdown();
_ecore_main_shutdown();
_ecore_signal_shutdown();
_ecore_main_loop_shutdown();
#if HAVE_MALLINFO
if (getenv("ECORE_MEM_STAT"))
{
_ecore_memory_statistic(NULL);
ERR("[%i] Memory MAX total: %i, free: %i",
_ecore_memory_pid,
_ecore_memory_max_total,
_ecore_memory_max_free);
}
#endif
ecore_mempool_shutdown();
eina_log_domain_unregister(_ecore_log_dom);
_ecore_log_dom = -1;
eina_prefix_free(_ecore_pfx);
_ecore_pfx = NULL;
eina_shutdown();
#ifdef HAVE_EVIL
evil_shutdown();
#endif
eo_unref(_ecore_parent);
eo_shutdown();
unlock:
_ecore_unlock();
return _ecore_init_count;
}
struct _Ecore_Fork_Cb
{
Ecore_Cb func;
void *data;
Eina_Bool delete_me : 1;
};
typedef struct _Ecore_Fork_Cb Ecore_Fork_Cb;
static int fork_cbs_walking = 0;
static Eina_List *fork_cbs = NULL;
EAPI Eina_Bool
ecore_fork_reset_callback_add(Ecore_Cb func, const void *data)
{
Ecore_Fork_Cb *fcb;
fcb = calloc(1, sizeof(Ecore_Fork_Cb));
if (!fcb) return EINA_FALSE;
fcb->func = func;
fcb->data = (void *)data;
fork_cbs = eina_list_append(fork_cbs, fcb);
return EINA_TRUE;
}
EAPI Eina_Bool
ecore_fork_reset_callback_del(Ecore_Cb func, const void *data)
{
Eina_List *l;
Ecore_Fork_Cb *fcb;
EINA_LIST_FOREACH(fork_cbs, l, fcb)
{
if ((fcb->func == func) && (fcb->data == data))
{
if (!fork_cbs_walking)
{
fork_cbs = eina_list_remove_list(fork_cbs, l);
free(fcb);
}
else
fcb->delete_me = EINA_TRUE;
return EINA_TRUE;
}
}
return EINA_FALSE;
}
EAPI void
ecore_fork_reset(void)
{
Eina_List *l, *ln;
Ecore_Fork_Cb *fcb;
eina_lock_take(&_thread_safety);
ecore_pipe_del(_thread_call);
_thread_call = ecore_pipe_add(_thread_callback, NULL);
/* If there was something in the pipe, trigger a wakeup again */
if (_thread_cb) ecore_pipe_write(_thread_call, &wakeup, sizeof (int));
eina_lock_release(&_thread_safety);
// should this be done withing the eina lock stuff?
fork_cbs_walking++;
EINA_LIST_FOREACH(fork_cbs, l, fcb)
{
fcb->func(fcb->data);
}
fork_cbs_walking--;
EINA_LIST_FOREACH_SAFE(fork_cbs, l, ln, fcb)
{
if (fcb->delete_me)
{
fork_cbs = eina_list_remove_list(fork_cbs, l);
free(fcb);
}
}
#ifdef HAVE_SYSTEMD
unsetenv("NOTIFY_SOCKET");
#endif
}
/**
* @}
*/
EAPI void
ecore_main_loop_thread_safe_call_async(Ecore_Cb callback,
void *data)
{
Ecore_Safe_Call *order;
if (!callback) return;
if (eina_main_loop_is())
{
callback(data);
return;
}
order = malloc(sizeof (Ecore_Safe_Call));
if (!order) return;
order->cb.async = callback;
order->data = data;
order->sync = EINA_FALSE;
order->suspend = EINA_FALSE;
_ecore_main_loop_thread_safe_call(order);
}
EAPI void *
ecore_main_loop_thread_safe_call_sync(Ecore_Data_Cb callback,
void *data)
{
Ecore_Safe_Call *order;
void *ret;
if (!callback) return NULL;
if (eina_main_loop_is())
{
return callback(data);
}
order = malloc(sizeof (Ecore_Safe_Call));
if (!order) return NULL;
order->cb.sync = callback;
order->data = data;
eina_lock_new(&order->m);
eina_condition_new(&order->c, &order->m);
order->sync = EINA_TRUE;
order->suspend = EINA_FALSE;
_ecore_main_loop_thread_safe_call(order);
eina_lock_take(&order->m);
eina_condition_wait(&order->c);
eina_lock_release(&order->m);
ret = order->data;
order->sync = EINA_FALSE;
order->cb.async = _thread_safe_cleanup;
order->data = order;
_ecore_main_loop_thread_safe_call(order);
return ret;
}
EAPI int
ecore_thread_main_loop_begin(void)
{
Ecore_Safe_Call *order;
if (eina_main_loop_is())
{
return ++_thread_loop;
}
order = malloc(sizeof (Ecore_Safe_Call));
if (!order) return -1;
eina_lock_take(&_thread_id_lock);
order->current_id = ++_thread_id_max;
if (order->current_id < 0)
{
_thread_id_max = 0;
order->current_id = ++_thread_id_max;
}
eina_lock_release(&_thread_id_lock);
eina_lock_new(&order->m);
eina_condition_new(&order->c, &order->m);
order->suspend = EINA_TRUE;
_ecore_main_loop_thread_safe_call(order);
eina_lock_take(&order->m);
while (order->current_id != _thread_id)
eina_condition_wait(&order->c);
eina_lock_release(&order->m);
eina_main_loop_define();
_thread_loop = 1;
return _thread_loop;
}
EAPI int
ecore_thread_main_loop_end(void)
{
int current_id;
if (_thread_loop == 0)
{
ERR("the main loop is not locked ! No matching call to ecore_thread_main_loop_begin().");
return -1;
}
/* until we unlock the main loop, this thread has the main loop id */
if (!eina_main_loop_is())
{
ERR("Not in a locked thread !");
return -1;
}
_thread_loop--;
if (_thread_loop > 0)
return _thread_loop;
current_id = _thread_id;
eina_lock_take(&_thread_mutex);
_thread_id_update = _thread_id;
eina_condition_broadcast(&_thread_cond);
eina_lock_release(&_thread_mutex);
eina_lock_take(&_thread_feedback_mutex);
while (current_id == _thread_id && _thread_id != -1)
eina_condition_wait(&_thread_feedback_cond);
eina_lock_release(&_thread_feedback_mutex);
return 0;
}
EAPI void
ecore_print_warning(const char *function EINA_UNUSED,
const char *sparam EINA_UNUSED)
{
WRN("***** Developer Warning ***** :\n"
"\tThis program is calling:\n\n"
"\t%s();\n\n"
"\tWith the parameter:\n\n"
"\t%s\n\n"
"\tbeing NULL. Please fix your program.", function, sparam);
if (getenv("ECORE_ERROR_ABORT")) abort();
}
EAPI void
_ecore_magic_fail(const void *d,
Ecore_Magic m,
Ecore_Magic req_m,
const char *fname EINA_UNUSED)
{
ERR("\n"
"*** ECORE ERROR: Ecore Magic Check Failed!!!\n"
"*** IN FUNCTION: %s()", fname);
if (!d)
ERR(" Input handle pointer is NULL!");
else if (m == ECORE_MAGIC_NONE)
ERR(" Input handle has already been freed!");
else if (m != req_m)
ERR(" Input handle is wrong type\n"
" Expected: %08x - %s\n"
" Supplied: %08x - %s",
(unsigned int)req_m, _ecore_magic_string_get(req_m),
(unsigned int)m, _ecore_magic_string_get(m));
ERR("*** NAUGHTY PROGRAMMER!!!\n"
"*** SPANK SPANK SPANK!!!\n"
"*** Now go fix your code. Tut tut tut!");
if (getenv("ECORE_ERROR_ABORT")) abort();
}
static const char *
_ecore_magic_string_get(Ecore_Magic m)
{
switch (m)
{
case ECORE_MAGIC_NONE:
return "None (Freed Object)";
break;
case ECORE_MAGIC_EXE:
return "Ecore_Exe (Executable)";
break;
case ECORE_MAGIC_TIMER:
return "Ecore_Timer (Timer)";
break;
case ECORE_MAGIC_IDLER:
return "Ecore_Idler (Idler)";
break;
case ECORE_MAGIC_IDLE_ENTERER:
return "Ecore_Idle_Enterer (Idler Enterer)";
break;
case ECORE_MAGIC_IDLE_EXITER:
return "Ecore_Idle_Exiter (Idler Exiter)";
break;
case ECORE_MAGIC_FD_HANDLER:
return "Ecore_Fd_Handler (Fd Handler)";
break;
case ECORE_MAGIC_WIN32_HANDLER:
return "Ecore_Win32_Handler (Win32 Handler)";
break;
case ECORE_MAGIC_EVENT_HANDLER:
return "Ecore_Event_Handler (Event Handler)";
break;
case ECORE_MAGIC_EVENT:
return "Ecore_Event (Event)";
break;
default:
return "<UNKNOWN>";
}
}
/* fps debug calls - for debugging how much time your app actually spends */
/* "running" (and the inverse being time spent running)... this does not */
/* account for other apps and multitasking... */
static int _ecore_fps_debug_init_count = 0;
static int _ecore_fps_debug_fd = -1;
unsigned int *_ecore_fps_runtime_mmap = NULL;
void
_ecore_fps_debug_init(void)
{
char buf[PATH_MAX];
const char *tmp;
int pid;
_ecore_fps_debug_init_count++;
if (_ecore_fps_debug_init_count > 1) return;
#ifndef HAVE_EVIL
tmp = "/tmp";
#else
tmp = evil_tmpdir_get ();
#endif /* HAVE_EVIL */
pid = (int)getpid();
snprintf(buf, sizeof(buf), "%s/.ecore_fps_debug-%i", tmp, pid);
_ecore_fps_debug_fd = open(buf, O_CREAT | O_TRUNC | O_RDWR, 0644);
if (_ecore_fps_debug_fd < 0)
{
unlink(buf);
_ecore_fps_debug_fd = open(buf, O_CREAT | O_TRUNC | O_RDWR, 0644);
}
if (_ecore_fps_debug_fd >= 0)
{
unsigned int zero = 0;
char *buf2 = (char *)&zero;
ssize_t todo = sizeof(unsigned int);
while (todo > 0)
{
ssize_t r = write(_ecore_fps_debug_fd, buf2, todo);
if (r > 0)
{
todo -= r;
buf2 += r;
}
else if ((r < 0) && (errno == EINTR))
continue;
else
{
ERR("could not write to file '%s' fd %d: %s",
tmp, _ecore_fps_debug_fd, strerror(errno));
close(_ecore_fps_debug_fd);
_ecore_fps_debug_fd = -1;
return;
}
}
_ecore_fps_runtime_mmap = mmap(NULL, sizeof(unsigned int),
PROT_READ | PROT_WRITE,
MAP_SHARED,
_ecore_fps_debug_fd, 0);
if (_ecore_fps_runtime_mmap == MAP_FAILED)
_ecore_fps_runtime_mmap = NULL;
}
}
void
_ecore_fps_debug_shutdown(void)
{
_ecore_fps_debug_init_count--;
if (_ecore_fps_debug_init_count > 0) return;
if (_ecore_fps_debug_fd >= 0)
{
char buf[4096];
const char *tmp;
int pid;
#ifndef HAVE_EVIL
tmp = "/tmp";
#else
tmp = (char *)evil_tmpdir_get ();
#endif /* HAVE_EVIL */
pid = (int)getpid();
snprintf(buf, sizeof(buf), "%s/.ecore_fps_debug-%i", tmp, pid);
unlink(buf);
if (_ecore_fps_runtime_mmap)
{
munmap(_ecore_fps_runtime_mmap, sizeof(int));
_ecore_fps_runtime_mmap = NULL;
}
close(_ecore_fps_debug_fd);
_ecore_fps_debug_fd = -1;
}
}
void
_ecore_fps_debug_runtime_add(double t)
{
if ((_ecore_fps_debug_fd >= 0) &&
(_ecore_fps_runtime_mmap))
{
unsigned int tm;
tm = (unsigned int)(t * 1000000.0);
/* i know its not 100% theoretically guaranteed, but i'd say a write */
/* of an int could be considered atomic for all practical purposes */
/* oh and since this is cumulative, 1 second = 1,000,000 ticks, so */
/* this can run for about 4294 seconds becore looping. if you are */
/* doing performance testing in one run for over an hour... well */
/* time to restart or handle a loop condition :) */
*(_ecore_fps_runtime_mmap) += tm;
}
}
#ifdef HAVE_SYSTEMD
static Eina_Bool
_systemd_watchdog_cb(EINA_UNUSED void *data)
{
sd_notify(0, "WATCHDOG=1");
return ECORE_CALLBACK_RENEW;
}
#endif
#if HAVE_MALLINFO
static Eina_Bool
_ecore_memory_statistic(EINA_UNUSED void *data)
{
struct mallinfo mi;
static int uordblks = 0;
static int fordblks = 0;
Eina_Bool changed = EINA_FALSE;
mi = mallinfo();
#define HAS_CHANGED(Global, Local) \
if (Global != Local) \
{ \
Global = Local; \
changed = EINA_TRUE; \
}
HAS_CHANGED(uordblks, mi.uordblks);
HAS_CHANGED(fordblks, mi.fordblks);
if (changed)
ERR("[%i] Memory total: %i, free: %i",
_ecore_memory_pid,
mi.uordblks,
mi.fordblks);
KEEP_MAX(_ecore_memory_max_total, mi.uordblks);
KEEP_MAX(_ecore_memory_max_free, mi.fordblks);
return ECORE_CALLBACK_RENEW;
}
#endif
static void
_ecore_main_loop_thread_safe_call(Ecore_Safe_Call *order)
{
Eina_Bool count;
eina_lock_take(&_thread_safety);
count = _thread_cb ? 0 : 1;
_thread_cb = eina_list_append(_thread_cb, order);
if (count) ecore_pipe_write(_thread_call, &wakeup, sizeof (int));
eina_lock_release(&_thread_safety);
}
static void
_thread_safe_cleanup(void *data)
{
Ecore_Safe_Call *call = data;
eina_condition_free(&call->c);
eina_lock_free(&call->m);
}
void
_ecore_main_call_flush(void)
{
Ecore_Safe_Call *call;
Eina_List *callback;
eina_lock_take(&_thread_safety);
callback = _thread_cb;
_thread_cb = NULL;
eina_lock_release(&_thread_safety);
EINA_LIST_FREE(callback, call)
{
if (call->suspend)
{
eina_lock_take(&_thread_mutex);
eina_lock_take(&call->m);
_thread_id = call->current_id;
eina_condition_broadcast(&call->c);
eina_lock_release(&call->m);
while (_thread_id_update != _thread_id)
eina_condition_wait(&_thread_cond);
eina_lock_release(&_thread_mutex);
eina_main_loop_define();
eina_lock_take(&_thread_feedback_mutex);
_thread_id = -1;
eina_condition_broadcast(&_thread_feedback_cond);
eina_lock_release(&_thread_feedback_mutex);
_thread_safe_cleanup(call);
free(call);
}
else if (call->sync)
{
call->data = call->cb.sync(call->data);
eina_condition_broadcast(&call->c);
}
else
{
call->cb.async(call->data);
free(call);
}
}
}
static void
_thread_callback(void *data EINA_UNUSED,
void *buffer EINA_UNUSED,
unsigned int nbyte EINA_UNUSED)
{
_ecore_main_call_flush();
}
EAPI Eina_Bool
ecore_low_memory_get(void)
{
return _ecore_low_memory;
}
EAPI void
ecore_low_memory_set(Eina_Bool status)
{
status = !!status;
if (_ecore_low_memory == status) return;
_ecore_low_memory = status;
ecore_event_add(ECORE_EVENT_LOW_MEMORY, NULL, NULL, NULL);
}
EAPI Eina_Bool
ecore_low_battery_get(void)
{
return _ecore_low_battery;
}
EAPI void
ecore_low_battery_set(Eina_Bool status)
{
status = !!status;
if (_ecore_low_battery == status) return;
_ecore_low_battery = status;
ecore_event_add(ECORE_EVENT_LOW_BATTERY, NULL, NULL, NULL);
}
static const Eo_Class_Description parent_class_desc = {
EO_VERSION,
"ecore_parent",
EO_CLASS_TYPE_REGULAR,
EO_CLASS_DESCRIPTION_OPS(NULL, NULL, 0),
NULL,
0,
NULL,
NULL
};
EO_DEFINE_CLASS(ecore_parent_class_get, &parent_class_desc, EO_BASE_CLASS, NULL);