ecore: Use timerfd with g_main_loop

glib only allows millisecond resolution in g_main_loop.
To avoid this limitation, use timerfd to wake up the main loop.

Signed-off-by: Mike McCormack <mj.mccormack@samsung.com>

SVN revision: 61079
This commit is contained in:
Mike McCormack 2011-07-06 10:54:11 +00:00 committed by Mike McCormack
parent f1b0e8d075
commit 0ddf5b9cab
2 changed files with 98 additions and 4 deletions

View File

@ -946,6 +946,9 @@ if test "x${want_epoll}" = "xyes" ; then
AC_CHECK_HEADERS([sys/epoll.h])
fi
# timerfd_create
AC_CHECK_HEADERS([sys/timerfd.h])
AC_CHECK_FUNCS(timerfd_create)
# thread support

View File

@ -63,10 +63,16 @@
# include <sys/epoll.h>
#endif
#ifdef HAVE_SYS_TIMERFD_H
#include <sys/timerfd.h>
#endif
#ifdef USE_G_MAIN_LOOP
# include <glib.h>
#endif
#define NS_PER_SEC (1000.0 * 1000.0 * 1000.0)
struct _Ecore_Fd_Handler
{
EINA_INLIST;
@ -157,6 +163,9 @@ static double t1 = 0.0;
static double t2 = 0.0;
#endif
#ifdef HAVE_TIMERFD_CREATE
static int timer_fd = -1;
#endif
#ifdef HAVE_EPOLL
static int epoll_fd = -1;
static pid_t epoll_pid;
@ -166,6 +175,9 @@ static pid_t epoll_pid;
#ifdef HAVE_EPOLL
static GPollFD ecore_epoll_fd;
#endif
#ifdef HAVE_TIMERFD_CREATE
static GPollFD ecore_timer_fd;
#endif
static GSource *ecore_glib_source;
static guint ecore_glib_source_id;
static GMainLoop* ecore_main_loop;
@ -462,8 +474,37 @@ _ecore_main_gsource_prepare(GSource *source __UNUSED__, gint *next_time)
{
if (_ecore_timers_exists())
{
int r = -1;
double t = _ecore_timer_next_get();
*next_time = ceil(t * 1000.0);
#ifdef HAVE_TIMERFD_CREATE
if (timer_fd >= 0)
{
struct itimerspec ts;
ts.it_interval.tv_sec = 0;
ts.it_interval.tv_nsec = 0;
ts.it_value.tv_sec = t;
ts.it_value.tv_nsec = fmod(t*NS_PER_SEC, NS_PER_SEC);
/* timerfd cannot sleep for 0 time */
if (ts.it_value.tv_sec && ts.it_value.tv_nsec)
{
r = timerfd_settime(timer_fd, 0, &ts, NULL);
if (r < 0)
{
ERR("timer set returned %d (errno=%d)", r, errno);
close(timer_fd);
timer_fd = -1;
}
else
INF("sleeping for %ld s %06ldus",
ts.it_value.tv_sec,
ts.it_value.tv_nsec/1000);
}
}
#endif
if (r == -1)
*next_time = ceil(t * 1000.0);
}
else
*next_time = -1;
@ -492,11 +533,27 @@ _ecore_main_gsource_check(GSource *source __UNUSED__)
/* check if old timers expired */
if (ecore_idling && !_ecore_idler_exist())
{
if (_ecore_timers_exists())
#ifdef HAVE_TIMERFD_CREATE
if (timer_fd >= 0)
{
double next_time = _ecore_timer_next_get();
ret = _ecore_timers_exists() && (0.0 >= next_time);
uint64_t count = 0;
int r = read(timer_fd, &count, sizeof count);
if (r == -1 && errno == EAGAIN)
INF("timer not ready");
else if (r == sizeof count)
{
INF("woke %d times", (int)count);
ret = TRUE;
}
else
{
/* unexpected things happened... fail back to old way */
ERR("timer read returned %d (errno=%d)", r, errno);
close(timer_fd);
timer_fd = -1;
}
}
#endif
}
else
ret = TRUE;
@ -505,11 +562,20 @@ _ecore_main_gsource_check(GSource *source __UNUSED__)
ecore_fds_ready = (_ecore_main_fdh_poll_mark_active() > 0);
_ecore_main_fd_handlers_cleanup();
/* check timers after updating loop time */
_ecore_time_loop_time = ecore_time_get();
if (!ret && _ecore_timers_exists())
{
double next_time = _ecore_timer_next_get();
ret = _ecore_timers_exists() && (0.0 >= next_time);
}
_ecore_timer_enable_new();
in_main_loop--;
if (!(ret || ecore_fds_ready))
INF("nothing was ready");
return ret || ecore_fds_ready;
}
@ -609,18 +675,35 @@ _ecore_main_loop_init(void)
#endif
/* setup for the g_main_loop only integration */
#ifdef USE_G_MAIN_LOOP
ecore_glib_source = g_source_new(&ecore_gsource_funcs, sizeof (GSource));
if (!ecore_glib_source)
CRIT("Failed to create glib source for epoll!");
else
{
/* epoll multiplexes fds into the g_main_loop */
#ifdef HAVE_EPOLL
ecore_epoll_fd.fd = epoll_fd;
ecore_epoll_fd.events = G_IO_IN;
ecore_epoll_fd.revents = 0;
g_source_add_poll(ecore_glib_source, &ecore_epoll_fd);
#endif
/* timerfd gives us better than millisecond accuracy in g_main_loop */
#ifdef HAVE_TIMERFD_CREATE
timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
if (timer_fd < 0)
ERR("failed to create timer fd!");
else
{
ecore_timer_fd.fd = timer_fd;
ecore_timer_fd.events = G_IO_IN;
ecore_timer_fd.revents = 0;
g_source_add_poll(ecore_glib_source, &ecore_timer_fd);
}
#endif
ecore_glib_source_id = g_source_attach(ecore_glib_source, NULL);
if (ecore_glib_source_id <= 0)
CRIT("Failed to attach glib source to default context");
@ -648,6 +731,14 @@ _ecore_main_loop_shutdown(void)
epoll_pid = 0;
#endif
#ifdef HAVE_TIMERFD_CREATE
if (timer_fd >= 0)
{
close(timer_fd);
timer_fd = -1;
}
#endif
}
/**