diff --git a/inotify/adapters.py b/inotify/adapters.py index e8301da..9b6ac2e 100644 --- a/inotify/adapters.py +++ b/inotify/adapters.py @@ -57,8 +57,16 @@ def __init__(self, paths=[], block_duration_s=_DEFAULT_EPOLL_BLOCK_DURATION_S): self.__inotify_fd = inotify.calls.inotify_init() _LOGGER.debug("Inotify handle is (%d).", self.__inotify_fd) - self.__epoll = select.epoll() - self.__epoll.register(self.__inotify_fd, select.POLLIN) + + if hasattr(select, 'epoll'): + self.__epoll = select.epoll() + self.__epoll.register(self.__inotify_fd, select.POLLIN) + elif hasattr(select, 'kqueue'): + self.__kqueue = select.kqueue() + kevent = select.kevent(self.__inotify_fd, + filter=select.KQ_FILTER_READ, + flags=select.KQ_EV_ADD | select.KQ_EV_ENABLE) + self.__kqueue.control([kevent], 0, 0) self.__last_success_return = None @@ -204,29 +212,7 @@ def event_gen( while True: block_duration_s = self.__get_block_duration() - # Poll, but manage signal-related errors. - - try: - events = self.__epoll.poll(block_duration_s) - except IOError as e: - if e.errno != EINTR: - raise - - if timeout_s is not None: - time_since_event_s = time.time() - last_hit_s - if time_since_event_s > timeout_s: - break - - continue - - # Process events. - - for fd, event_type in events: - # (fd) looks to always match the inotify FD. - - names = self._get_event_names(event_type) - _LOGGER.debug("Events received from epoll: {}".format(names)) - + def process_fd(fd): for (header, type_names, path, filename) \ in self._handle_inotify_event(fd): last_hit_s = time.time() @@ -242,6 +228,52 @@ def event_gen( yield e + # Poll, but manage signal-related errors. + + if hasattr(select, 'epoll'): + try: + events = self.__epoll.poll(block_duration_s) + except IOError as e: + if e.errno != EINTR: + raise + + if timeout_s is not None: + time_since_event_s = time.time() - last_hit_s + if time_since_event_s > timeout_s: + break + + continue + + # Process events. + + for fd, event_type in events: + # (fd) looks to always match the inotify FD. + + names = self._get_event_names(event_type) + _LOGGER.debug("Events received from epoll: {}".format(names)) + + yield from process_fd(fd) + + + elif hasattr(select, 'kqueue'): + try: + kevents = self.__kqueue.control(None, 1, block_duration_s) + except IOError as e: + if e.errno != EINTR: + raise + + if timeout_s is not None: + time_since_event_s = time.time() - last_hit_s + if time_since_event_s > timeout_s: + break + + continue + + # Process kevents + for kevent in kevents: + if kevent.filter == select.KQ_FILTER_READ: + yield from process_fd(kevent.ident) + if timeout_s is not None: time_since_event_s = time.time() - last_hit_s if time_since_event_s > timeout_s: diff --git a/inotify/library.py b/inotify/library.py index bb718d3..aacf3ef 100644 --- a/inotify/library.py +++ b/inotify/library.py @@ -6,3 +6,8 @@ _FILEPATH = 'libc.so.6' instance = ctypes.cdll.LoadLibrary(_FILEPATH) +if not hasattr(instance, 'inotify_init'): + _FILEPATH = ctypes.util.find_library('inotify') + if _FILEPATH is None: + _FILEPATH = 'libinotify.so.0' + instance = ctypes.cdll.LoadLibrary(_FILEPATH)