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