Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "base/files/file_descriptor_watcher_posix.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/lazy_instance.h" | |
| 9 #include "base/logging.h" | |
| 10 #include "base/memory/ptr_util.h" | |
| 11 #include "base/sequenced_task_runner.h" | |
| 12 #include "base/single_thread_task_runner.h" | |
| 13 #include "base/threading/sequenced_task_runner_handle.h" | |
| 14 #include "base/threading/thread_checker.h" | |
| 15 #include "base/threading/thread_local.h" | |
| 16 | |
| 17 namespace base { | |
| 18 | |
| 19 namespace { | |
| 20 | |
| 21 // MessageLoopForIO used to watch file descriptors for which callbacks are | |
| 22 // registered from a given thread. | |
| 23 LazyInstance<ThreadLocalPointer<MessageLoopForIO>>::Leaky | |
| 24 tls_message_loop_for_io = LAZY_INSTANCE_INITIALIZER; | |
| 25 | |
| 26 } // namespace | |
| 27 | |
| 28 FileDescriptorWatcher::Controller::~Controller() { | |
| 29 DCHECK(sequence_checker_.CalledOnValidSequence()); | |
| 30 message_loop_for_io_task_runner_->DeleteSoon(FROM_HERE, watcher_.release()); | |
| 31 // Since WeakPtrs are invalidated by the destructor, RunCallback() won't be | |
| 32 // invoked after this returns. | |
| 33 } | |
| 34 | |
| 35 class FileDescriptorWatcher::Controller::Watcher | |
| 36 : public MessageLoopForIO::Watcher, | |
| 37 public MessageLoop::DestructionObserver { | |
| 38 public: | |
| 39 Watcher(WeakPtr<Controller> controller, MessageLoopForIO::Mode mode, int fd); | |
| 40 ~Watcher() override; | |
| 41 | |
| 42 private: | |
| 43 friend class FileDescriptorWatcher; | |
| 44 | |
| 45 // MessageLoopForIO::Watcher: | |
| 46 void OnFileCanReadWithoutBlocking(int fd) override; | |
| 47 void OnFileCanWriteWithoutBlocking(int fd) override; | |
| 48 | |
| 49 // MessageLoop::DestructionObserver: | |
| 50 void WillDestroyCurrentMessageLoop() override; | |
| 51 | |
| 52 // Used to instruct the MessageLoopForIO to stop watching the file descriptor. | |
| 53 MessageLoopForIO::FileDescriptorWatcher file_descriptor_watcher_; | |
| 54 | |
| 55 // Runs tasks on the sequence on which this was instantiated (i.e. the | |
| 56 // sequence on which the callback must run). | |
| 57 const scoped_refptr<SequencedTaskRunner> callback_task_runner_ = | |
| 58 SequencedTaskRunnerHandle::Get(); | |
| 59 | |
| 60 // The Controller that created this Watcher. | |
| 61 WeakPtr<Controller> controller_; | |
| 62 | |
| 63 // Whether this Watcher is notified when |fd_| becomes readable or writable | |
| 64 // without blocking. | |
| 65 const MessageLoopForIO::Mode mode_; | |
| 66 | |
| 67 // The watched file descriptor. | |
| 68 const int fd_; | |
| 69 | |
| 70 // Except for the constructor, every method of this class must run on the same | |
| 71 // MessageLoopForIO thread. | |
| 72 ThreadChecker thread_checker_; | |
| 73 | |
| 74 DISALLOW_COPY_AND_ASSIGN(Watcher); | |
| 75 }; | |
| 76 | |
| 77 FileDescriptorWatcher::Controller::Watcher::Watcher( | |
| 78 WeakPtr<Controller> controller, | |
| 79 MessageLoopForIO::Mode mode, | |
| 80 int fd) | |
| 81 : controller_(controller), mode_(mode), fd_(fd) { | |
| 82 DCHECK(callback_task_runner_); | |
| 83 thread_checker_.DetachFromThread(); | |
| 84 } | |
| 85 | |
| 86 FileDescriptorWatcher::Controller::Watcher::~Watcher() { | |
| 87 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 88 MessageLoopForIO::current()->RemoveDestructionObserver(this); | |
| 89 } | |
| 90 | |
| 91 void FileDescriptorWatcher::Controller::Watcher::OnFileCanReadWithoutBlocking( | |
| 92 int fd) { | |
| 93 DCHECK_EQ(fd_, fd); | |
| 94 DCHECK_EQ(MessageLoopForIO::WATCH_READ, mode_); | |
| 95 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 96 | |
| 97 // Run the callback on the sequence on which the watch was initiated. | |
| 98 callback_task_runner_->PostTask(FROM_HERE, | |
| 99 Bind(&Controller::RunCallback, controller_)); | |
| 100 } | |
| 101 | |
| 102 void FileDescriptorWatcher::Controller::Watcher::OnFileCanWriteWithoutBlocking( | |
| 103 int fd) { | |
| 104 DCHECK_EQ(fd_, fd); | |
| 105 DCHECK_EQ(MessageLoopForIO::WATCH_WRITE, mode_); | |
| 106 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 107 | |
| 108 // Run the callback on the sequence on which the watch was initiated. | |
| 109 callback_task_runner_->PostTask(FROM_HERE, | |
| 110 Bind(&Controller::RunCallback, controller_)); | |
| 111 } | |
| 112 | |
| 113 void FileDescriptorWatcher::Controller::Watcher:: | |
| 114 WillDestroyCurrentMessageLoop() { | |
| 115 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 116 | |
| 117 // A Watcher is owned by a Controller. When the Controller is deleted, it | |
| 118 // transfers ownership of the Watcher to a delete task posted to the | |
| 119 // MessageLoopForIO. If the MessageLoopForIO is deleted before the delete task | |
| 120 // runs, the following line takes care of deleting the Watcher. | |
| 121 delete this; | |
| 122 } | |
| 123 | |
| 124 FileDescriptorWatcher::Controller::Controller(MessageLoopForIO::Mode mode, | |
| 125 int fd, | |
| 126 const Closure& callback) | |
| 127 : callback_(callback), | |
| 128 message_loop_for_io_task_runner_( | |
| 129 tls_message_loop_for_io.Get().Get()->task_runner()), | |
| 130 weak_factory_(this) { | |
| 131 DCHECK(!callback_.is_null()); | |
| 132 DCHECK(message_loop_for_io_task_runner_); | |
| 133 watcher_ = MakeUnique<Watcher>(weak_factory_.GetWeakPtr(), mode, fd); | |
| 134 StartWatching(true); | |
| 135 } | |
| 136 | |
| 137 void FileDescriptorWatcher::Controller::StartWatching( | |
| 138 bool called_from_constructor) { | |
| 139 DCHECK(sequence_checker_.CalledOnValidSequence()); | |
| 140 message_loop_for_io_task_runner_->PostTask( | |
| 141 FROM_HERE, | |
| 142 Bind( | |
| 143 [](Watcher* watcher, bool called_from_constructor) { | |
| 144 // |watcher| is guaranteed to be alive when this task | |
| 145 // runs because it can only be deleted by a task posted | |
| 146 // to the MessageLoopForIO by the Controller's | |
| 147 // destructor. | |
| 148 MessageLoopForIO::current()->WatchFileDescriptor( | |
| 149 watcher->fd_, false, watcher->mode_, | |
| 150 &watcher->file_descriptor_watcher_, watcher); | |
| 151 | |
| 152 if (called_from_constructor) { | |
| 153 // MessageLoopForIO::AddDestructionObserver() has to be called on | |
| 154 // the MessageLoopForIO thread (can't be called in the constructor | |
| 155 // of Controller). | |
| 156 MessageLoopForIO::current()->AddDestructionObserver(watcher); | |
| 157 } | |
| 158 }, | |
| 159 Unretained(watcher_.get()), called_from_constructor)); | |
|
dcheng
2016/09/15 08:23:02
Nit: let's just make this an actual method on Watc
fdoray
2016/09/15 12:10:15
Done.
fdoray
2016/09/15 12:11:11
Done. Note that Unretained() is still required bec
| |
| 160 } | |
| 161 | |
| 162 void FileDescriptorWatcher::Controller::RunCallback() { | |
| 163 DCHECK(sequence_checker_.CalledOnValidSequence()); | |
| 164 | |
| 165 WeakPtr<Controller> weak_this = weak_factory_.GetWeakPtr(); | |
| 166 | |
| 167 callback_.Run(); | |
| 168 | |
| 169 // If |this| wasn't deleted, re-enable the watch. | |
| 170 if (weak_this) | |
| 171 StartWatching(false); | |
| 172 } | |
| 173 | |
| 174 FileDescriptorWatcher::FileDescriptorWatcher( | |
| 175 MessageLoopForIO* message_loop_for_io) { | |
| 176 DCHECK(message_loop_for_io); | |
| 177 DCHECK(!tls_message_loop_for_io.Get().Get()); | |
| 178 tls_message_loop_for_io.Get().Set(message_loop_for_io); | |
| 179 } | |
| 180 | |
| 181 FileDescriptorWatcher::~FileDescriptorWatcher() { | |
| 182 tls_message_loop_for_io.Get().Set(nullptr); | |
| 183 } | |
| 184 | |
| 185 std::unique_ptr<FileDescriptorWatcher::Controller> | |
| 186 FileDescriptorWatcher::WatchReadable(int fd, const Closure& callback) { | |
| 187 return WrapUnique(new Controller(MessageLoopForIO::WATCH_READ, fd, callback)); | |
| 188 } | |
| 189 | |
| 190 std::unique_ptr<FileDescriptorWatcher::Controller> | |
| 191 FileDescriptorWatcher::WatchWritable(int fd, const Closure& callback) { | |
| 192 return WrapUnique( | |
| 193 new Controller(MessageLoopForIO::WATCH_WRITE, fd, callback)); | |
| 194 } | |
| 195 | |
| 196 } // namespace base | |
| OLD | NEW |