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 31 // Delete |watcher_| on the MessageLoopForIO. 32 // 33 // If the MessageLoopForIO is deleted before Watcher::StartWatching() runs, 34 // |watcher_| is leaked. If the MessageLoopForIO is deleted after 35 // Watcher::StartWatching() runs but before the DeleteSoon task runs, 36 // |watcher_| is deleted from Watcher::WillDestroyCurrentMessageLoop(). 37 message_loop_for_io_task_runner_->DeleteSoon(FROM_HERE, watcher_.release()); 38 39 // Since WeakPtrs are invalidated by the destructor, RunCallback() won't be 40 // invoked after this returns. 41 } 42 43 class FileDescriptorWatcher::Controller::Watcher 44 : public MessageLoopForIO::Watcher, 45 public MessageLoop::DestructionObserver { 46 public: 47 Watcher(WeakPtr<Controller> controller, MessageLoopForIO::Mode mode, int fd); 48 ~Watcher() override; 49 50 void StartWatching(); 51 52 private: 53 friend class FileDescriptorWatcher; 54 55 // MessageLoopForIO::Watcher: 56 void OnFileCanReadWithoutBlocking(int fd) override; 57 void OnFileCanWriteWithoutBlocking(int fd) override; 58 59 // MessageLoop::DestructionObserver: 60 void WillDestroyCurrentMessageLoop() override; 61 62 // Used to instruct the MessageLoopForIO to stop watching the file descriptor. 63 MessageLoopForIO::FileDescriptorWatcher file_descriptor_watcher_; 64 65 // Runs tasks on the sequence on which this was instantiated (i.e. the 66 // sequence on which the callback must run). 67 const scoped_refptr<SequencedTaskRunner> callback_task_runner_ = 68 SequencedTaskRunnerHandle::Get(); 69 70 // The Controller that created this Watcher. 71 WeakPtr<Controller> controller_; 72 73 // Whether this Watcher is notified when |fd_| becomes readable or writable 74 // without blocking. 75 const MessageLoopForIO::Mode mode_; 76 77 // The watched file descriptor. 78 const int fd_; 79 80 // Except for the constructor, every method of this class must run on the same 81 // MessageLoopForIO thread. 82 ThreadChecker thread_checker_; 83 84 // Whether this Watcher was registered as a DestructionObserver on the 85 // MessageLoopForIO thread. 86 bool registered_as_destruction_observer_ = false; 87 88 DISALLOW_COPY_AND_ASSIGN(Watcher); 89 }; 90 91 FileDescriptorWatcher::Controller::Watcher::Watcher( 92 WeakPtr<Controller> controller, 93 MessageLoopForIO::Mode mode, 94 int fd) 95 : file_descriptor_watcher_(FROM_HERE), 96 controller_(controller), 97 mode_(mode), 98 fd_(fd) { 99 DCHECK(callback_task_runner_); 100 thread_checker_.DetachFromThread(); 101 } 102 103 FileDescriptorWatcher::Controller::Watcher::~Watcher() { 104 DCHECK(thread_checker_.CalledOnValidThread()); 105 MessageLoopForIO::current()->RemoveDestructionObserver(this); 106 } 107 108 void FileDescriptorWatcher::Controller::Watcher::StartWatching() { 109 DCHECK(thread_checker_.CalledOnValidThread()); 110 111 MessageLoopForIO::current()->WatchFileDescriptor( 112 fd_, false, mode_, &file_descriptor_watcher_, this); 113 114 if (!registered_as_destruction_observer_) { 115 MessageLoopForIO::current()->AddDestructionObserver(this); 116 registered_as_destruction_observer_ = true; 117 } 118 } 119 120 void FileDescriptorWatcher::Controller::Watcher::OnFileCanReadWithoutBlocking( 121 int fd) { 122 DCHECK_EQ(fd_, fd); 123 DCHECK_EQ(MessageLoopForIO::WATCH_READ, mode_); 124 DCHECK(thread_checker_.CalledOnValidThread()); 125 126 // Run the callback on the sequence on which the watch was initiated. 127 callback_task_runner_->PostTask(FROM_HERE, 128 Bind(&Controller::RunCallback, controller_)); 129 } 130 131 void FileDescriptorWatcher::Controller::Watcher::OnFileCanWriteWithoutBlocking( 132 int fd) { 133 DCHECK_EQ(fd_, fd); 134 DCHECK_EQ(MessageLoopForIO::WATCH_WRITE, mode_); 135 DCHECK(thread_checker_.CalledOnValidThread()); 136 137 // Run the callback on the sequence on which the watch was initiated. 138 callback_task_runner_->PostTask(FROM_HERE, 139 Bind(&Controller::RunCallback, controller_)); 140 } 141 142 void FileDescriptorWatcher::Controller::Watcher:: 143 WillDestroyCurrentMessageLoop() { 144 DCHECK(thread_checker_.CalledOnValidThread()); 145 146 // A Watcher is owned by a Controller. When the Controller is deleted, it 147 // transfers ownership of the Watcher to a delete task posted to the 148 // MessageLoopForIO. If the MessageLoopForIO is deleted before the delete task 149 // runs, the following line takes care of deleting the Watcher. 150 delete this; 151 } 152 153 FileDescriptorWatcher::Controller::Controller(MessageLoopForIO::Mode mode, 154 int fd, 155 const Closure& callback) 156 : callback_(callback), 157 message_loop_for_io_task_runner_( 158 tls_message_loop_for_io.Get().Get()->task_runner()), 159 weak_factory_(this) { 160 DCHECK(!callback_.is_null()); 161 DCHECK(message_loop_for_io_task_runner_); 162 watcher_ = MakeUnique<Watcher>(weak_factory_.GetWeakPtr(), mode, fd); 163 StartWatching(); 164 } 165 166 void FileDescriptorWatcher::Controller::StartWatching() { 167 DCHECK(sequence_checker_.CalledOnValidSequence()); 168 // It is safe to use Unretained() below because |watcher_| can only be deleted 169 // by a delete task posted to |message_loop_for_io_task_runner_| by this 170 // Controller's destructor. Since this delete task hasn't been posted yet, it 171 // can't run before the task posted below. 172 message_loop_for_io_task_runner_->PostTask( 173 FROM_HERE, Bind(&Watcher::StartWatching, Unretained(watcher_.get()))); 174 } 175 176 void FileDescriptorWatcher::Controller::RunCallback() { 177 DCHECK(sequence_checker_.CalledOnValidSequence()); 178 179 WeakPtr<Controller> weak_this = weak_factory_.GetWeakPtr(); 180 181 callback_.Run(); 182 183 // If |this| wasn't deleted, re-enable the watch. 184 if (weak_this) 185 StartWatching(); 186 } 187 188 FileDescriptorWatcher::FileDescriptorWatcher( 189 MessageLoopForIO* message_loop_for_io) { 190 DCHECK(message_loop_for_io); 191 DCHECK(!tls_message_loop_for_io.Get().Get()); 192 tls_message_loop_for_io.Get().Set(message_loop_for_io); 193 } 194 195 FileDescriptorWatcher::~FileDescriptorWatcher() { 196 tls_message_loop_for_io.Get().Set(nullptr); 197 } 198 199 std::unique_ptr<FileDescriptorWatcher::Controller> 200 FileDescriptorWatcher::WatchReadable(int fd, const Closure& callback) { 201 return WrapUnique(new Controller(MessageLoopForIO::WATCH_READ, fd, callback)); 202 } 203 204 std::unique_ptr<FileDescriptorWatcher::Controller> 205 FileDescriptorWatcher::WatchWritable(int fd, const Closure& callback) { 206 return WrapUnique( 207 new Controller(MessageLoopForIO::WATCH_WRITE, fd, callback)); 208 } 209 210 } // namespace base 211