aboutsummaryrefslogtreecommitdiffhomepage
path: root/env_universal_common.cpp
diff options
context:
space:
mode:
authorGravatar ridiculousfish <corydoras@ridiculousfish.com>2014-05-01 16:44:37 -0700
committerGravatar ridiculousfish <corydoras@ridiculousfish.com>2014-05-01 16:44:37 -0700
commit186b0f62ebf34a446730d45a0a27a51be335df24 (patch)
tree4ef2adef01363264cc00ed923455b192a20589a1 /env_universal_common.cpp
parent60c8012e9e8472330e6c77aa5755e4ec1ebb6a1a (diff)
Early implementation of inotify-based universal variable notifier for
Linux
Diffstat (limited to 'env_universal_common.cpp')
-rw-r--r--env_universal_common.cpp98
1 files changed, 94 insertions, 4 deletions
diff --git a/env_universal_common.cpp b/env_universal_common.cpp
index cb555b2d..7d926efe 100644
--- a/env_universal_common.cpp
+++ b/env_universal_common.cpp
@@ -16,6 +16,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
+#include <arpa/inet.h>
#include <pwd.h>
#include <errno.h>
#include <sys/stat.h>
@@ -51,6 +52,11 @@
#include <notify.h>
#endif
+#if HAVE_INOTIFY_INIT || HAVE_INOTIFY_INIT1
+#define FISH_INOTIFY_AVAILABLE 1
+#include <sys/inotify.h>
+#endif
+
/**
Non-wide version of the set command
*/
@@ -1542,7 +1548,9 @@ public:
{
if (token != 0)
{
+#if FISH_NOTIFYD_AVAILABLE
notify_cancel(token);
+#endif
}
}
@@ -1551,17 +1559,19 @@ public:
return notify_fd;
}
- void drain_notification_fd(int fd)
+ bool drain_notification_fd(int fd)
{
/* notifyd notifications come in as 32 bit values. We don't care about the value. We set ourselves as non-blocking, so just read until we can't read any more. */
assert(fd == notify_fd);
+ bool read_something = false;
unsigned char buff[64];
ssize_t amt_read;
do
{
amt_read = read(notify_fd, buff, sizeof buff);
-
+ read_something = (read_something || amt_read > 0);
} while (amt_read == sizeof buff);
+ return read_something;
}
void post_notification()
@@ -1576,10 +1586,85 @@ public:
}
};
+class universal_notifier_inotify_t : public universal_notifier_t
+{
+ int watch_fd;
+ int watch_descriptor;
+
+ void setup_inotify(const wchar_t *test_path)
+ {
+#if FISH_INOTIFY_AVAILABLE
+
+ const wcstring path = test_path ? test_path : default_vars_path();
+
+ // Construct the watchfd
+#if HAVE_INOTIFY_INIT1
+ this->watch_fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
+#else
+ this->watch_fd = inotify_init();
+ if (this->watch_fd >= 0)
+ {
+ int flags = fcntl(this->watch_fd, F_GETFL, 0);
+ fcntl(this->watch_fd, F_SETFL, flags | O_NONBLOCK | FD_CLOEXEC);
+ }
+#endif
+ if (this->watch_fd < 0)
+ {
+ wperror(L"inotify_init");
+ }
+ else
+ {
+ std::string narrow_path = wcs2string(path);
+ this->watch_descriptor = inotify_add_watch(this->watch_fd, narrow_path.c_str(), IN_MODIFY | IN_EXCL_UNLINK);
+ if (this->watch_descriptor < 0)
+ {
+ wperror(L"inotify_add_watch");
+ }
+ }
+#endif
+ }
+
+public:
+
+ universal_notifier_inotify_t(const wchar_t *test_path) : watch_fd(-1), watch_descriptor(-1)
+ {
+ setup_inotify(test_path);
+ }
+
+ ~universal_notifier_inotify_t()
+ {
+ if (watch_fd >= 0)
+ {
+ close(watch_fd);
+ }
+ USE(watch_descriptor);
+ }
+
+ int notification_fd()
+ {
+ return watch_fd;
+ }
+
+ bool drain_notification_fd(int fd)
+ {
+ assert(fd == watch_fd);
+ bool result = false;
+
+#if FISH_INOTIFY_AVAILABLE
+ struct inotify_event evt = {};
+ ssize_t read_amt = read(watch_fd, &evt, sizeof evt);
+ result = (read_amt > 0);
+#endif
+ return result;
+ }
+};
+
universal_notifier_t::notifier_strategy_t universal_notifier_t::resolve_default_strategy()
{
#if FISH_NOTIFYD_AVAILABLE
return strategy_notifyd;
+#elif FISH_INOTIFY_AVAILABLE
+ return strategy_inotify;
#else
return strategy_shmem_polling;
#endif
@@ -1591,7 +1676,7 @@ universal_notifier_t &universal_notifier_t::default_notifier()
return *result;
}
-universal_notifier_t *universal_notifier_t::new_notifier_for_strategy(universal_notifier_t::notifier_strategy_t strat)
+universal_notifier_t *universal_notifier_t::new_notifier_for_strategy(universal_notifier_t::notifier_strategy_t strat, const wchar_t *test_path)
{
if (strat == strategy_default)
{
@@ -1605,6 +1690,10 @@ universal_notifier_t *universal_notifier_t::new_notifier_for_strategy(universal_
case strategy_notifyd:
return new universal_notifier_notifyd_t();
+ case strategy_inotify:
+ return new universal_notifier_inotify_t(test_path);
+
+
default:
fprintf(stderr, "Unsupported strategy %d\n", strat);
return NULL;
@@ -1644,6 +1733,7 @@ unsigned long universal_notifier_t::usec_delay_between_polls() const
return 0;
}
-void universal_notifier_t::drain_notification_fd(int fd)
+bool universal_notifier_t::drain_notification_fd(int fd)
{
+ return false;
}