aboutsummaryrefslogtreecommitdiffhomepage
path: root/env_universal_common.cpp
diff options
context:
space:
mode:
authorGravatar ridiculousfish <corydoras@ridiculousfish.com>2014-04-30 15:50:03 -0700
committerGravatar ridiculousfish <corydoras@ridiculousfish.com>2014-04-30 15:50:03 -0700
commit60c8012e9e8472330e6c77aa5755e4ec1ebb6a1a (patch)
tree53273e7c6210d319be4c1173e43d4f36fd121b98 /env_universal_common.cpp
parent08d6e515c73bc960c856667a5c69bd4c54eb04e5 (diff)
Implement notifyd-based notification strategy for universal variables
(OS X specific)
Diffstat (limited to 'env_universal_common.cpp')
-rw-r--r--env_universal_common.cpp86
1 files changed, 86 insertions, 0 deletions
diff --git a/env_universal_common.cpp b/env_universal_common.cpp
index 003a7616..cb555b2d 100644
--- a/env_universal_common.cpp
+++ b/env_universal_common.cpp
@@ -46,6 +46,11 @@
#include "env_universal_common.h"
#include "path.h"
+#if __APPLE__
+#define FISH_NOTIFYD_AVAILABLE 1
+#include <notify.h>
+#endif
+
/**
Non-wide version of the set command
*/
@@ -1497,12 +1502,87 @@ class universal_notifier_shmem_poller_t : public universal_notifier_t
return usec_per_sec / 3; //3 times a second
}
}
+};
+
+class universal_notifier_notifyd_t : public universal_notifier_t
+{
+ int notify_fd;
+ int token;
+ std::string name;
+
+ void setup_notifyd()
+ {
+#if FISH_NOTIFYD_AVAILABLE
+ // per notify(3), the user.uid.%d style is only accessible to processes with that uid
+ char local_name[256];
+ snprintf(local_name, sizeof local_name, "user.uid.%d.%ls.uvars", getuid(), program_name ? program_name : L"fish");
+ name.assign(local_name);
+
+ uint32_t status = notify_register_file_descriptor(name.c_str(), &this->notify_fd, 0, &this->token);
+ if (status != NOTIFY_STATUS_OK)
+ {
+ fprintf(stderr, "Warning: notify_register_file_descriptor() failed with status %u. Universal variable notifications may not be received.", status);
+ }
+ if (this->notify_fd >= 0)
+ {
+ // Mark us for non-blocking reads, with CLO_EXEC
+ int flags = fcntl(this->notify_fd, F_GETFL, 0);
+ fcntl(this->notify_fd, F_SETFL, flags | O_NONBLOCK | FD_CLOEXEC);
+ }
+#endif
+ }
+
+public:
+ universal_notifier_notifyd_t() : notify_fd(-1), token(0)
+ {
+ setup_notifyd();
+ }
+
+ ~universal_notifier_notifyd_t()
+ {
+ if (token != 0)
+ {
+ notify_cancel(token);
+ }
+ }
+
+ int notification_fd()
+ {
+ return notify_fd;
+ }
+ void 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);
+ unsigned char buff[64];
+ ssize_t amt_read;
+ do
+ {
+ amt_read = read(notify_fd, buff, sizeof buff);
+
+ } while (amt_read == sizeof buff);
+ }
+
+ void post_notification()
+ {
+#if FISH_NOTIFYD_AVAILABLE
+ uint32_t status = notify_post(name.c_str());
+ if (status != NOTIFY_STATUS_OK)
+ {
+ fprintf(stderr, "Warning: notify_post() failed with status %u. Universal variable notifications may not be sent.", status);
+ }
+#endif
+ }
};
universal_notifier_t::notifier_strategy_t universal_notifier_t::resolve_default_strategy()
{
+#if FISH_NOTIFYD_AVAILABLE
+ return strategy_notifyd;
+#else
return strategy_shmem_polling;
+#endif
}
universal_notifier_t &universal_notifier_t::default_notifier()
@@ -1522,6 +1602,9 @@ universal_notifier_t *universal_notifier_t::new_notifier_for_strategy(universal_
case strategy_shmem_polling:
return new universal_notifier_shmem_poller_t();
+ case strategy_notifyd:
+ return new universal_notifier_notifyd_t();
+
default:
fprintf(stderr, "Unsupported strategy %d\n", strat);
return NULL;
@@ -1561,3 +1644,6 @@ unsigned long universal_notifier_t::usec_delay_between_polls() const
return 0;
}
+void universal_notifier_t::drain_notification_fd(int fd)
+{
+}