diff options
author | ridiculousfish <corydoras@ridiculousfish.com> | 2014-04-30 15:50:03 -0700 |
---|---|---|
committer | ridiculousfish <corydoras@ridiculousfish.com> | 2014-04-30 15:50:03 -0700 |
commit | 60c8012e9e8472330e6c77aa5755e4ec1ebb6a1a (patch) | |
tree | 53273e7c6210d319be4c1173e43d4f36fd121b98 /env_universal_common.cpp | |
parent | 08d6e515c73bc960c856667a5c69bd4c54eb04e5 (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.cpp | 86 |
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) +{ +} |