+2014-08-01 Dmitry Antipov <dmantipov@yandex.ru>
+
+ * atimer.c (toplevel) [HAVE_TIMERFD]: Include errno.h.
+ (timerfd_callback): Ignore weird events with no data. Add tight
+ assertions and comments.
+ (init_atimer) [HAVE_TIMERFD]: Add environment variable to optionally
+ disable timerfd-based timer. Use TFD_NONBLOCK for timer descriptor.
+
2014-08-01 Paul Eggert <eggert@cs.ucla.edu>
* frame.c (x_set_frame_parameters): Fix typo in previous patch.
#include <unistd.h>
#ifdef HAVE_TIMERFD
+#include <errno.h>
# include <sys/timerfd.h>
#endif
void
timerfd_callback (int fd, void *arg)
{
- char buf[8];
ptrdiff_t nbytes;
+ uint64_t expirations;
eassert (fd == timerfd);
- nbytes = emacs_read (fd, buf, sizeof (buf));
- /* Just discard an expiration count for now. */
- eassert (nbytes == sizeof (buf));
- do_pending_atimers ();
+ nbytes = emacs_read (fd, &expirations, sizeof (expirations));
+
+ if (nbytes == sizeof (expirations))
+ {
+ /* Timer should expire just once. */
+ eassert (expirations == 1);
+ do_pending_atimers ();
+ }
+ else if (nbytes < 0)
+ /* For some not yet known reason, we may get weird event and no
+ data on timer descriptor. This can break Gnus at least, see:
+ http://lists.gnu.org/archive/html/emacs-devel/2014-07/msg00503.html. */
+ eassert (errno == EAGAIN);
+ else
+ /* I don't know what else can happen with this descriptor. */
+ emacs_abort ();
}
#endif /* HAVE_TIMERFD */
{
#ifdef HAVE_ITIMERSPEC
# ifdef HAVE_TIMERFD
- timerfd = timerfd_create (CLOCK_REALTIME, TFD_CLOEXEC);
+ /* Until this feature is considered stable, you can ask to not use it. */
+ timerfd = (egetenv ("EMACS_IGNORE_TIMERFD") ? -1 :
+ timerfd_create (CLOCK_REALTIME, TFD_NONBLOCK | TFD_CLOEXEC));
# endif
if (timerfd < 0)
{