diff --git a/configure.ac b/configure.ac index ab6a0618ce..3ca13161d0 100644 --- a/configure.ac +++ b/configure.ac @@ -4086,6 +4086,13 @@ AC_DEFINE_IF([HAVE_NOTIFY_COCOA], [File monitoring with fsevent notification]) AM_CONDITIONAL([HAVE_NOTIFY_COCOA], [test "x${have_darwin}" = "xyes"]) +AC_CHECK_FUNC([kevent]) +have_notify_kevent="${ac_cv_func_kevent}" +AC_DEFINE_IF([HAVE_NOTIFY_KEVENT], + [test "x${have_notify_kevent}" = "xyes"], [1], + [File monitoring with kqueue/kevent mechanism]) +AM_CONDITIONAL([HAVE_NOTIFY_KEVENT], [test "x${have_notify_kevent}" = "xyes"]) + EFL_LIB_END([Eio]) dnl TODO: remove these ifdefs from code! diff --git a/src/Makefile_Eio.am b/src/Makefile_Eio.am index a41af55398..62882da978 100644 --- a/src/Makefile_Eio.am +++ b/src/Makefile_Eio.am @@ -43,6 +43,10 @@ lib_eio_libeio_la_SOURCES += lib/eio/eio_monitor_win32.c else if HAVE_NOTIFY_COCOA lib_eio_libeio_la_SOURCES += lib/eio/eio_monitor_cocoa.c +else +if HAVE_NOTIFY_KEVENT +lib_eio_libeio_la_SOURCES += lib/eio/eio_monitor_kevent.c +endif endif endif endif diff --git a/src/lib/eio/eio_monitor_kevent.c b/src/lib/eio/eio_monitor_kevent.c new file mode 100644 index 0000000000..753726b7fe --- /dev/null +++ b/src/lib/eio/eio_monitor_kevent.c @@ -0,0 +1,207 @@ +/* EIO - EFL data type library + * Copyright (C) 2011 Enlightenment Developers: + * Cedric Bail + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; + * if not, see . + */ + +#include "eio_private.h" +#include "Eio.h" + +#include +#include +#include + +/*============================================================================* + * Local * + *============================================================================*/ + +/** + * @cond LOCAL + */ + +#define KEVENT_NUM_EVENTS 5 + +struct _Eio_Monitor_Backend +{ + Eio_Monitor *parent; + + int fd; +}; + +static Ecore_Fd_Handler *_kqueue_fd = NULL; +static Eina_Hash *_kevent_monitors = NULL; + +static void +_eio_kevent_del(void *data) +{ + Eio_Monitor_Backend *emb = data; + + if (emb->fd) + close(emb->fd); + + free(emb); +} + +static Eina_Bool +_eio_kevent_handler(void *data EINA_UNUSED, Ecore_Fd_Handler *fdh) +{ + Eio_Monitor_Backend *backend; + struct kevent evs[KEVENT_NUM_EVENTS]; + int event_code = 0; + + int res = kevent(ecore_main_fd_handler_fd_get(fdh), 0, 0, evs, KEVENT_NUM_EVENTS, 0); + + for(int i=0; iparent, backend->parent->path, event_code); + } + if(evs[i].fflags & NOTE_WRITE || evs[i].fflags & NOTE_ATTRIB) + { + event_code = EIO_MONITOR_FILE_MODIFIED; + _eio_monitor_send(backend->parent, backend->parent->path, event_code); + } + } + + return ECORE_CALLBACK_RENEW; +} + +/** + * @endcond + */ + + +/*============================================================================* + * Global * + *============================================================================*/ + +/** + * @cond LOCAL + */ + +/** + * @endcond + */ + +void eio_monitor_backend_init(void) +{ + int fd; + + if (_kqueue_fd > 0) return; // already initialized + + fd = kqueue(); + if (fd < 0) return; + + _kqueue_fd = ecore_main_fd_handler_add(fd, ECORE_FD_READ, _eio_kevent_handler, NULL, NULL, NULL); + if (!_kqueue_fd) + { + close(fd); + return; + } + + _kevent_monitors = eina_hash_int32_new(_eio_kevent_del); +} + +void eio_monitor_backend_shutdown(void) +{ + int fd; + + if (!_kqueue_fd) return; + + eina_hash_free(_kevent_monitors); + + fd = ecore_main_fd_handler_fd_get(_kqueue_fd); + ecore_main_fd_handler_del(_kqueue_fd); + _kqueue_fd = NULL; + + if (fd < 0) + return; + + close(fd); +} + +void eio_monitor_backend_add(Eio_Monitor *monitor) +{ + struct kevent e; + struct stat st; + Eio_Monitor_Backend* backend; + int fd, res = 0; + + if (!_kqueue_fd) + { + eio_monitor_fallback_add(monitor); + return; + } + + backend = calloc(1, sizeof (Eio_Monitor_Backend)); + if (!backend) return; + + res = stat(monitor->path, &st); + if (res) goto error; + + if (S_ISDIR(st.st_mode)) // let poller handle directories + { + eio_monitor_fallback_add(monitor); + goto error; + } + + fd = open(monitor->path, O_RDONLY); + if (fd < 0) goto error; + + backend->fd = fd; + backend->parent = monitor; + monitor->backend = backend; + + eina_hash_direct_add(_kevent_monitors, &backend->fd, backend); + + EV_SET(&e, fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, + NOTE_DELETE | NOTE_WRITE | NOTE_ATTRIB, 0, NULL); + res = kevent(ecore_main_fd_handler_fd_get(_kqueue_fd), &e, 1, 0, 0, 0); + if (res) + { + eina_hash_del(_kevent_monitors, &backend->fd, backend); + eio_monitor_fallback_add(monitor); + } + + return; + +error: + free(backend); +} + +void eio_monitor_backend_del(Eio_Monitor *monitor) +{ + Eio_Monitor_Backend *backend; + + if (monitor->fallback) + { + eio_monitor_fallback_del(monitor); + return; + } + + backend = monitor->backend; + monitor->backend = NULL; + + eina_hash_del(_kevent_monitors, &backend->fd, backend); +} + + +/*============================================================================* + * API * + *============================================================================*/ diff --git a/src/lib/eio/eio_monitor_poll.c b/src/lib/eio/eio_monitor_poll.c index cb9daf9895..6b7b5a8b56 100644 --- a/src/lib/eio/eio_monitor_poll.c +++ b/src/lib/eio/eio_monitor_poll.c @@ -270,7 +270,8 @@ _eio_monitor_fallback_timer_cb(void *data) * @cond LOCAL */ -#if !defined HAVE_SYS_INOTIFY_H && !defined HAVE_NOTIFY_WIN32 && !defined HAVE_NOTIFY_COCOA +#if !defined HAVE_SYS_INOTIFY_H && !defined HAVE_NOTIFY_WIN32 && !defined HAVE_NOTIFY_COCOA \ + && !defined HAVE_NOTIFY_KEVENT void eio_monitor_backend_init(void) { }