From ca39ff976e576dd917becf989f28fdf149c9f1d0 Mon Sep 17 00:00:00 2001 From: Gustavo Sverzut Barbieri Date: Fri, 9 Aug 2013 00:02:04 -0300 Subject: [PATCH] ecore: detect and emit event on system time changed. If we have timerfd then we can set a timer with special features (ABSTIME | CANCELON) to be notified if its offset to monotonic time change, effectively this will alert us if user called settimeofday() or similar method to change system time. This code was inspired by Enlightenment's clock module. --- src/lib/ecore/ecore_main.c | 72 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/src/lib/ecore/ecore_main.c b/src/lib/ecore/ecore_main.c index 0500052a73..3a6210d71b 100644 --- a/src/lib/ecore/ecore_main.c +++ b/src/lib/ecore/ecore_main.c @@ -127,6 +127,13 @@ epoll_ctl(int epfd EINA_UNUSED, # endif #endif /* HAVE_SYS_TIMERFD_H */ +#ifndef TFD_TIMER_ABSTIME +# define TFD_TIMER_ABSTIME (1 << 0) +#endif +#ifndef TFD_TIMER_CANCELON_SET +# define TFD_TIMER_CANCELON_SET (1 << 1) +#endif + #ifndef HAVE_TIMERFD_CREATE static inline int timerfd_create(int clockid EINA_UNUSED, @@ -763,6 +770,67 @@ static GSourceFuncs ecore_gsource_funcs = #endif +#ifdef HAVE_SYS_TIMERFD_H +static int realtime_fd = -1; + +static void detect_time_changes_start(void); +static Eina_Bool +_realtime_update(void *data EINA_UNUSED, Ecore_Fd_Handler *fdh EINA_UNUSED) +{ + char buf[64]; + + if (read(realtime_fd, buf, sizeof(buf)) >= 0) return EINA_TRUE; + + DBG("system clock changed"); + ecore_event_add(ECORE_EVENT_SYSTEM_TIMEDATE_CHANGED, NULL, NULL, NULL); + + close(realtime_fd); + realtime_fd = -1; + detect_time_changes_start(); + return EINA_FALSE; +} +#endif + +static void +detect_time_changes_start(void) +{ +#ifdef HAVE_SYS_TIMERFD_H + struct itimerspec its; + + if (realtime_fd >= 0) return; + + realtime_fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK | TFD_CLOEXEC); + if (realtime_fd < 0) return; + + memset(&its, 0, sizeof(its)); + if (timerfd_settime(realtime_fd, + TFD_TIMER_ABSTIME | TFD_TIMER_CANCELON_SET, + &its, NULL) < 0) + { + WRN("Couldn't arm timerfd to detect clock changes: %s", + strerror(errno)); + close(realtime_fd); + realtime_fd = -1; + return; + } + + ecore_main_fd_handler_add(realtime_fd, ECORE_FD_READ, + _realtime_update, NULL, NULL, NULL); +#endif +} + +static void +detect_time_changes_stop(void) +{ +#ifdef HAVE_SYS_TIMERFD_H + if (realtime_fd > 0) + { + close(realtime_fd); + realtime_fd = -1; + } +#endif +} + void _ecore_main_loop_init(void) { @@ -818,6 +886,8 @@ _ecore_main_loop_init(void) CRIT("Failed to attach glib source to default context"); } #endif + + detect_time_changes_start(); } void @@ -831,6 +901,8 @@ _ecore_main_loop_shutdown(void) } #endif + detect_time_changes_stop(); + if (epoll_fd >= 0) { close(epoll_fd);