diff --git a/NEWS b/NEWS index 88c6b10a..58ec39d8 100644 --- a/NEWS +++ b/NEWS @@ -3,7 +3,11 @@ NEWS New in master: - * Issue 230: Improve responsiveness on macos: add support for kFSEventStreamCreateFlagNoDefer. + * Refactor code to replace usages of deprecated function + FSEventStreamScheduleWithRunLoop with FSEventStreamSetDispatchQueue. + + * Issue 230: Improve responsiveness on macos: add support for + kFSEventStreamCreateFlagNoDefer. * Issue 249: Man page still mentions fswatch-run. diff --git a/configure.ac b/configure.ac index e79b7f92..acfdf725 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ # -*- Autoconf -*- # -# Copyright (C) 2014-2021 Enrico M. Crisostomo +# Copyright (C) 2014-2022 Enrico M. Crisostomo # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software @@ -16,12 +16,12 @@ # # Process this file with autoconf to produce a configure script. # -dnl Copyright (C) 2014-2021 Enrico M. Crisostomo +dnl Copyright (C) 2014-2022 Enrico M. Crisostomo AC_PREREQ([2.69]) m4_include([m4/fswatch_version.m4]) m4_include([m4/libfswatch_version.m4]) AC_INIT([fswatch], LIBFSWATCH_VERSION, [enrico.m.crisostomo@gmail.com], [], [https://github.com/emcrisostomo/fswatch]) -AC_COPYRIGHT([2013-2021 (C) Enrico M. Crisostomo]) +AC_COPYRIGHT([2013-2022 (C) Enrico M. Crisostomo]) AC_REVISION([$Revision: LIBFSWATCH_REVISION$]) AC_CONFIG_SRCDIR([fswatch/src/fswatch.cpp]) AC_CONFIG_AUX_DIR([config]) @@ -129,13 +129,13 @@ AS_VAR_SET_IF([IS_DARWIN], [ AX_COMPARE_VERSION([${DARWIN_VER}], [ge], [11.0], [AC_DEFINE([HAVE_MACOS_GE_10_7], [1], ["macOS is at least the specified version"])]) AX_COMPARE_VERSION([${DARWIN_VER}], [ge], [13.0], [AC_DEFINE([HAVE_MACOS_GE_10_9], [1], ["macOS is at least the specified version"])]) AX_COMPARE_VERSION([${DARWIN_VER}], [ge], [14.0], [AC_DEFINE([HAVE_MACOS_GE_10_10], [1], ["macOS is at least the specified version"])]) + # Check for macOS FSEvents. FSEvents added file events in a later release, so + # this check must be performed separately. + AC_CHECK_HEADERS([CoreServices/CoreServices.h]) + AS_VAR_IF([ac_cv_header_CoreServices_CoreServices_h], ["yes"], [AX_FSEVENTS_HAVE_FILE_EVENTS]) ]) -# Check for macOS FSEvents. FSEvents added file events in a later release, so -# this check must be performed separately. -AC_CHECK_HEADERS([CoreServices/CoreServices.h]) -AS_VAR_IF([ac_cv_header_CoreServices_CoreServices_h], ["yes"], [AX_FSEVENTS_HAVE_FILE_EVENTS]) -AM_CONDITIONAL([USE_FSEVENTS], [test "x${ax_cv_fsevents_have_file_events}" = "xyes"]) +AM_CONDITIONAL([USE_FSEVENTS], [test "x${ax_cv_fsevents_have_fseventstreamsetdispatchqueue}" = "xyes"]) # Check for kqueue: if the sys/event.h header is present, perform a check for # the kqueue and kevent functions. diff --git a/fswatch/src/fswatch.cpp b/fswatch/src/fswatch.cpp index 4a6471b4..8fcdb981 100644 --- a/fswatch/src/fswatch.cpp +++ b/fswatch/src/fswatch.cpp @@ -35,7 +35,7 @@ #include "libfswatch/c/libfswatch.h" #include "libfswatch/c/libfswatch_log.h" #include "libfswatch/c++/libfswatch_exception.hpp" -#ifdef HAVE_FSEVENTS_FILE_EVENTS +#ifdef HAVE_FSEVENTS_FSEVENTSTREAMSETDISPATCHQUEUE #include "libfswatch/c++/fsevents_monitor.hpp" #endif @@ -172,7 +172,7 @@ static void usage(std::ostream& stream) stream << " -i, --include=REGEX " << _("Include paths matching REGEX.\n"); stream << " -I, --insensitive " << _("Use case insensitive regular expressions.\n"); stream << " -l, --latency=DOUBLE " << _("Set the latency.\n"); - #if defined(HAVE_FSEVENTS_FILE_EVENTS) + #if defined(HAVE_FSEVENTS_FSEVENTSTREAMSETDISPATCHQUEUE) stream << " --no-defer " << _("Set the no defer flag in the monitor.\n"); #endif stream << " -L, --follow-links " << _("Follow symbolic links.\n"); @@ -494,7 +494,7 @@ static void start_monitor(int argc, char **argv, int optind) active_monitor->set_properties(monitor_properties); active_monitor->set_allow_overflow(allow_overflow); active_monitor->set_latency(lvalue); - #if defined(HAVE_FSEVENTS_FILE_EVENTS) + #if defined(HAVE_FSEVENTS_FSEVENTSTREAMSETDISPATCHQUEUE) if (noDeferFlag) active_monitor->set_property(std::string(fsw::fsevents_monitor::DARWIN_EVENTSTREAM_NO_DEFER), "true"); #endif @@ -537,7 +537,7 @@ static void parse_opts(int argc, char **argv) {"include", required_argument, nullptr, 'i'}, {"insensitive", no_argument, nullptr, 'I'}, {"latency", required_argument, nullptr, 'l'}, - #ifdef HAVE_FSEVENTS_FILE_EVENTS + #ifdef HAVE_FSEVENTS_FSEVENTSTREAMSETDISPATCHQUEUE {"no-defer", no_argument, nullptr, OPT_NO_DEFER}, #endif {"list-monitors", no_argument, nullptr, 'M'}, diff --git a/libfswatch/src/libfswatch/c++/fsevents_monitor.cpp b/libfswatch/src/libfswatch/c++/fsevents_monitor.cpp index 89b3506e..1b0b07a2 100644 --- a/libfswatch/src/libfswatch/c++/fsevents_monitor.cpp +++ b/libfswatch/src/libfswatch/c++/fsevents_monitor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2021 Enrico M. Crisostomo + * Copyright (c) 2014-2022 Enrico M. Crisostomo * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software @@ -17,6 +17,7 @@ #include #include // isatty() #include // fileno() +#include #include "fsevents_monitor.hpp" #include "libfswatch/gettext_defs.h" #include "libfswatch_exception.hpp" @@ -120,14 +121,9 @@ namespace fsw if (!stream) throw libfsw_exception(_("Event stream could not be created.")); - // Fire the event loop - run_loop = CFRunLoopGetCurrent(); - - // Loop Initialization - FSW_ELOG(_("Scheduling stream with run loop...\n")); - FSEventStreamScheduleWithRunLoop(stream, - run_loop, - kCFRunLoopDefaultMode); + // Creating dispatch queue + fsevents_queue = dispatch_queue_create("fswatch_event_queue", NULL); + FSEventStreamSetDispatchQueue(stream, fsevents_queue); FSW_ELOG(_("Starting event stream...\n")); FSEventStreamStart(stream); @@ -136,9 +132,16 @@ namespace fsw run_loop_lock.unlock(); #endif - // Loop - FSW_ELOG(_("Starting run loop...\n")); - CFRunLoopRun(); + for(;;) + { +#ifdef HAVE_CXX_MUTEX + run_loop_lock.lock(); + if (should_stop) break; + run_loop_lock.unlock(); +#endif + + std::this_thread::sleep_for(std::chrono::milliseconds((long long) (latency * 1000))); + } // Deinitialization part FSW_ELOG(_("Stopping event stream...\n")); @@ -150,22 +153,10 @@ namespace fsw FSW_ELOG(_("Releasing event stream...\n")); FSEventStreamRelease(stream); + dispatch_release(fsevents_queue); stream = nullptr; } - /* - * on_stop() is designed to be invoked with a lock on the run_mutex. - */ - void fsevents_monitor::on_stop() - { - if (!run_loop) throw libfsw_exception(_("run loop is null")); - - FSW_ELOG(_("Stopping run loop...\n")); - CFRunLoopStop(run_loop); - - run_loop = nullptr; - } - static vector decode_flags(FSEventStreamEventFlags flag) { vector evt_flags; diff --git a/libfswatch/src/libfswatch/c++/fsevents_monitor.hpp b/libfswatch/src/libfswatch/c++/fsevents_monitor.hpp index f4ca81ab..63c94f5e 100644 --- a/libfswatch/src/libfswatch/c++/fsevents_monitor.hpp +++ b/libfswatch/src/libfswatch/c++/fsevents_monitor.hpp @@ -80,11 +80,6 @@ namespace fsw */ void run() override; - /** - * @brief Execute an implementation-specific stop handler. - */ - void on_stop() override; - private: static void fsevents_callback(ConstFSEventStreamRef streamRef, void *clientCallBackInfo, @@ -94,7 +89,7 @@ namespace fsw const FSEventStreamEventId eventIds[]); FSEventStreamRef stream = nullptr; - CFRunLoopRef run_loop = nullptr; + dispatch_queue_t fsevents_queue = nullptr; bool no_defer(); void create_stream(CFArrayRef pathsToWatch); }; diff --git a/libfswatch/src/libfswatch/c++/monitor_factory.cpp b/libfswatch/src/libfswatch/c++/monitor_factory.cpp index 505abcdb..56d5e965 100644 --- a/libfswatch/src/libfswatch/c++/monitor_factory.cpp +++ b/libfswatch/src/libfswatch/c++/monitor_factory.cpp @@ -18,7 +18,7 @@ #include "libfswatch/gettext_defs.h" #include "monitor_factory.hpp" #include "libfswatch_exception.hpp" -#if defined(HAVE_FSEVENTS_FILE_EVENTS) +#if defined(HAVE_FSEVENTS_FSEVENTSTREAMSETDISPATCHQUEUE) #include "fsevents_monitor.hpp" #endif #if defined(HAVE_SYS_EVENT_H) @@ -43,7 +43,7 @@ namespace fsw { fsw_monitor_type type; -#if defined(HAVE_FSEVENTS_FILE_EVENTS) +#if defined(HAVE_FSEVENTS_FSEVENTSTREAMSETDISPATCHQUEUE) type = fsw_monitor_type::fsevents_monitor_type; #elif defined(HAVE_SYS_EVENT_H) type = fsw_monitor_type::kqueue_monitor_type; @@ -73,7 +73,7 @@ namespace fsw case system_default_monitor_type: return create_default_monitor(paths, callback, context); -#if defined(HAVE_FSEVENTS_FILE_EVENTS) +#if defined(HAVE_FSEVENTS_FSEVENTSTREAMSETDISPATCHQUEUE) case fsevents_monitor_type: return new fsevents_monitor(paths, callback, context); #endif @@ -105,7 +105,7 @@ namespace fsw #define fsw_quote(x) #x static std::map creator_by_string_set; -#if defined(HAVE_FSEVENTS_FILE_EVENTS) +#if defined(HAVE_FSEVENTS_FSEVENTSTREAMSETDISPATCHQUEUE) creator_by_string_set[fsw_quote(fsevents_monitor)] = fsw_monitor_type::fsevents_monitor_type; #endif #if defined(HAVE_SYS_EVENT_H)