| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/dns/notify_watcher_mac.h" |
| |
| #include <notify.h> |
| |
| #include "base/logging.h" |
| #include "base/mac/mac_util.h" |
| #include "base/message_loop/message_loop_current.h" |
| #include "base/posix/eintr_wrapper.h" |
| #include "starboard/types.h" |
| |
| namespace net { |
| |
| namespace { |
| |
| // Registers a dummy file descriptor to workaround a bug in libnotify |
| // in macOS 10.12 |
| // See https://bugs.chromium.org/p/chromium/issues/detail?id=783148. |
| class NotifyFileDescriptorsGlobalsHolder { |
| public: |
| NotifyFileDescriptorsGlobalsHolder() { |
| int notify_fd = -1; |
| int notify_token = -1; |
| notify_register_file_descriptor("notify_file_descriptor_holder", ¬ify_fd, |
| 0, ¬ify_token); |
| } |
| }; |
| |
| void HoldNotifyFileDescriptorsGlobals() { |
| if (base::mac::IsAtMostOS10_12()) { |
| static NotifyFileDescriptorsGlobalsHolder holder; |
| } |
| } |
| } // namespace |
| |
| NotifyWatcherMac::NotifyWatcherMac() |
| : notify_fd_(-1), notify_token_(-1), watcher_(FROM_HERE) { |
| HoldNotifyFileDescriptorsGlobals(); |
| } |
| |
| NotifyWatcherMac::~NotifyWatcherMac() { |
| Cancel(); |
| } |
| |
| bool NotifyWatcherMac::Watch(const char* key, const CallbackType& callback) { |
| DCHECK(key); |
| DCHECK(!callback.is_null()); |
| Cancel(); |
| uint32_t status = notify_register_file_descriptor( |
| key, ¬ify_fd_, 0, ¬ify_token_); |
| if (status != NOTIFY_STATUS_OK) |
| return false; |
| DCHECK_GE(notify_fd_, 0); |
| if (!base::MessageLoopCurrentForIO::Get()->WatchFileDescriptor( |
| notify_fd_, true, base::MessagePumpForIO::WATCH_READ, &watcher_, |
| this)) { |
| Cancel(); |
| return false; |
| } |
| callback_ = callback; |
| return true; |
| } |
| |
| void NotifyWatcherMac::Cancel() { |
| if (notify_fd_ >= 0) { |
| notify_cancel(notify_token_); // Also closes |notify_fd_|. |
| notify_fd_ = -1; |
| callback_.Reset(); |
| watcher_.StopWatchingFileDescriptor(); |
| } |
| } |
| |
| void NotifyWatcherMac::OnFileCanReadWithoutBlocking(int fd) { |
| int token; |
| int status = HANDLE_EINTR(read(notify_fd_, &token, sizeof(token))); |
| if (status != sizeof(token)) { |
| Cancel(); |
| callback_.Run(false); |
| return; |
| } |
| // Ignoring |token| value to avoid possible endianness mismatch: |
| // http://openradar.appspot.com/8821081 |
| callback_.Run(true); |
| } |
| |
| } // namespace net |