blob: 04579d1adcee6f5e6559fff33e2fcb99596308dc [file] [log] [blame]
fdorayf9f6c1e92016-09-15 13:23:241// 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"
François Doray1e392d22019-01-29 16:00:198#include "base/callback_helpers.h"
fdorayf9f6c1e92016-09-15 13:23:249#include "base/lazy_instance.h"
fdorayf9f6c1e92016-09-15 13:23:2410#include "base/memory/ptr_util.h"
Gabriel Charette810f3f432018-04-27 22:28:1411#include "base/message_loop/message_loop_current.h"
Gabriel Charette19d2ae62018-04-10 14:10:5812#include "base/message_loop/message_pump_for_io.h"
fdorayf9f6c1e92016-09-15 13:23:2413#include "base/sequenced_task_runner.h"
14#include "base/single_thread_task_runner.h"
François Doray1e392d22019-01-29 16:00:1915#include "base/synchronization/waitable_event.h"
fdorayf9f6c1e92016-09-15 13:23:2416#include "base/threading/sequenced_task_runner_handle.h"
17#include "base/threading/thread_checker.h"
18#include "base/threading/thread_local.h"
François Doray1e392d22019-01-29 16:00:1919#include "base/threading/thread_restrictions.h"
fdorayf9f6c1e92016-09-15 13:23:2420
21namespace base {
22
23namespace {
24
François Doray1e392d22019-01-29 16:00:1925// Per-thread FileDescriptorWatcher registration.
Alexander Timin6247f6a91a2018-10-27 15:40:1026LazyInstance<ThreadLocalPointer<FileDescriptorWatcher>>::Leaky tls_fd_watcher =
27 LAZY_INSTANCE_INITIALIZER;
fdorayf9f6c1e92016-09-15 13:23:2428
29} // namespace
30
fdorayf9f6c1e92016-09-15 13:23:2431class FileDescriptorWatcher::Controller::Watcher
Gabriel Charette19d2ae62018-04-10 14:10:5832 : public MessagePumpForIO::FdWatcher,
Gabriel Charette810f3f432018-04-27 22:28:1433 public MessageLoopCurrent::DestructionObserver {
fdorayf9f6c1e92016-09-15 13:23:2434 public:
Gabriel Charette19d2ae62018-04-10 14:10:5835 Watcher(WeakPtr<Controller> controller, MessagePumpForIO::Mode mode, int fd);
fdorayf9f6c1e92016-09-15 13:23:2436 ~Watcher() override;
37
38 void StartWatching();
39
40 private:
41 friend class FileDescriptorWatcher;
42
Gabriel Charette19d2ae62018-04-10 14:10:5843 // MessagePumpForIO::FdWatcher:
fdorayf9f6c1e92016-09-15 13:23:2444 void OnFileCanReadWithoutBlocking(int fd) override;
45 void OnFileCanWriteWithoutBlocking(int fd) override;
46
Gabriel Charette810f3f432018-04-27 22:28:1447 // MessageLoopCurrent::DestructionObserver:
fdorayf9f6c1e92016-09-15 13:23:2448 void WillDestroyCurrentMessageLoop() override;
49
François Doray1e392d22019-01-29 16:00:1950 // The MessagePumpForIO's watch handle (stops the watch when destroyed).
Gabriel Charette889b87c2018-05-11 22:23:3651 MessagePumpForIO::FdWatchController fd_watch_controller_;
fdorayf9f6c1e92016-09-15 13:23:2452
53 // Runs tasks on the sequence on which this was instantiated (i.e. the
54 // sequence on which the callback must run).
55 const scoped_refptr<SequencedTaskRunner> callback_task_runner_ =
56 SequencedTaskRunnerHandle::Get();
57
François Doray1e392d22019-01-29 16:00:1958 // The Controller that created this Watcher. This WeakPtr is bound to the
59 // |controller_| thread and can only be used by this Watcher to post back to
60 // |callback_task_runner_|.
fdorayf9f6c1e92016-09-15 13:23:2461 WeakPtr<Controller> controller_;
62
63 // Whether this Watcher is notified when |fd_| becomes readable or writable
64 // without blocking.
Gabriel Charette19d2ae62018-04-10 14:10:5865 const MessagePumpForIO::Mode mode_;
fdorayf9f6c1e92016-09-15 13:23:2466
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
François Doray1e392d22019-01-29 16:00:1971 // MessagePumpForIO thread.
fdorayf9f6c1e92016-09-15 13:23:2472 ThreadChecker thread_checker_;
73
74 // Whether this Watcher was registered as a DestructionObserver on the
François Doray1e392d22019-01-29 16:00:1975 // MessagePumpForIO thread.
fdorayf9f6c1e92016-09-15 13:23:2476 bool registered_as_destruction_observer_ = false;
77
78 DISALLOW_COPY_AND_ASSIGN(Watcher);
79};
80
81FileDescriptorWatcher::Controller::Watcher::Watcher(
82 WeakPtr<Controller> controller,
Gabriel Charette19d2ae62018-04-10 14:10:5883 MessagePumpForIO::Mode mode,
fdorayf9f6c1e92016-09-15 13:23:2484 int fd)
Gabriel Charette889b87c2018-05-11 22:23:3685 : fd_watch_controller_(FROM_HERE),
ssid5dd4fb32017-02-16 23:57:1786 controller_(controller),
87 mode_(mode),
88 fd_(fd) {
fdorayf9f6c1e92016-09-15 13:23:2489 DCHECK(callback_task_runner_);
90 thread_checker_.DetachFromThread();
91}
92
93FileDescriptorWatcher::Controller::Watcher::~Watcher() {
94 DCHECK(thread_checker_.CalledOnValidThread());
Gabriel Charette810f3f432018-04-27 22:28:1495 MessageLoopCurrentForIO::Get()->RemoveDestructionObserver(this);
fdorayf9f6c1e92016-09-15 13:23:2496}
97
98void FileDescriptorWatcher::Controller::Watcher::StartWatching() {
99 DCHECK(thread_checker_.CalledOnValidThread());
Alexander Timin6247f6a91a2018-10-27 15:40:10100 DCHECK(MessageLoopCurrentForIO::IsSet());
fdorayf9f6c1e92016-09-15 13:23:24101
François Doray1e392d22019-01-29 16:00:19102 const bool watch_success =
103 MessageLoopCurrentForIO::Get()->WatchFileDescriptor(
104 fd_, false, mode_, &fd_watch_controller_, this);
105 DCHECK(watch_success) << "Failed to watch fd=" << fd_;
fdorayf9f6c1e92016-09-15 13:23:24106
107 if (!registered_as_destruction_observer_) {
Gabriel Charette810f3f432018-04-27 22:28:14108 MessageLoopCurrentForIO::Get()->AddDestructionObserver(this);
fdorayf9f6c1e92016-09-15 13:23:24109 registered_as_destruction_observer_ = true;
110 }
111}
112
113void FileDescriptorWatcher::Controller::Watcher::OnFileCanReadWithoutBlocking(
114 int fd) {
115 DCHECK_EQ(fd_, fd);
Gabriel Charette19d2ae62018-04-10 14:10:58116 DCHECK_EQ(MessagePumpForIO::WATCH_READ, mode_);
fdorayf9f6c1e92016-09-15 13:23:24117 DCHECK(thread_checker_.CalledOnValidThread());
118
119 // Run the callback on the sequence on which the watch was initiated.
tzik92b7a422017-04-11 15:00:44120 callback_task_runner_->PostTask(
121 FROM_HERE, BindOnce(&Controller::RunCallback, controller_));
fdorayf9f6c1e92016-09-15 13:23:24122}
123
124void FileDescriptorWatcher::Controller::Watcher::OnFileCanWriteWithoutBlocking(
125 int fd) {
126 DCHECK_EQ(fd_, fd);
Gabriel Charette19d2ae62018-04-10 14:10:58127 DCHECK_EQ(MessagePumpForIO::WATCH_WRITE, mode_);
fdorayf9f6c1e92016-09-15 13:23:24128 DCHECK(thread_checker_.CalledOnValidThread());
129
130 // Run the callback on the sequence on which the watch was initiated.
tzik92b7a422017-04-11 15:00:44131 callback_task_runner_->PostTask(
132 FROM_HERE, BindOnce(&Controller::RunCallback, controller_));
fdorayf9f6c1e92016-09-15 13:23:24133}
134
135void FileDescriptorWatcher::Controller::Watcher::
136 WillDestroyCurrentMessageLoop() {
137 DCHECK(thread_checker_.CalledOnValidThread());
138
François Doray1e392d22019-01-29 16:00:19139 if (callback_task_runner_->RunsTasksInCurrentSequence()) {
140 // |controller_| can be accessed directly when Watcher runs on the same
141 // thread.
142 controller_->watcher_.reset();
143 } else {
144 // If the Watcher and the Controller live on different threads, delete
145 // |this| synchronously. Pending tasks bound to an unretained Watcher* will
146 // not run since this loop is dead. The associated Controller still
147 // technically owns this via unique_ptr but it never uses it directly and
148 // will ultimately send it to this thread for deletion (and that also won't
149 // run since the loop being dead).
150 delete this;
151 }
fdorayf9f6c1e92016-09-15 13:23:24152}
153
Gabriel Charette19d2ae62018-04-10 14:10:58154FileDescriptorWatcher::Controller::Controller(MessagePumpForIO::Mode mode,
fdorayf9f6c1e92016-09-15 13:23:24155 int fd,
kylecharb2695fc2019-04-24 14:51:20156 const RepeatingClosure& callback)
fdorayf9f6c1e92016-09-15 13:23:24157 : callback_(callback),
Alexander Timin6247f6a91a2018-10-27 15:40:10158 io_thread_task_runner_(
Jeremy Roman577d88492019-07-05 14:30:23159 tls_fd_watcher.Get().Get()->io_thread_task_runner()) {
fdorayf9f6c1e92016-09-15 13:23:24160 DCHECK(!callback_.is_null());
Alexander Timin6247f6a91a2018-10-27 15:40:10161 DCHECK(io_thread_task_runner_);
Jeremy Roman9532f252017-08-16 23:27:24162 watcher_ = std::make_unique<Watcher>(weak_factory_.GetWeakPtr(), mode, fd);
fdorayf9f6c1e92016-09-15 13:23:24163 StartWatching();
164}
165
François Doray1e392d22019-01-29 16:00:19166FileDescriptorWatcher::Controller::~Controller() {
167 DCHECK(sequence_checker_.CalledOnValidSequence());
168
169 if (io_thread_task_runner_->BelongsToCurrentThread()) {
170 // If the MessagePumpForIO and the Controller live on the same thread.
171 watcher_.reset();
172 } else {
173 // Synchronously wait until |watcher_| is deleted on the MessagePumpForIO
174 // thread. This ensures that the file descriptor is never accessed after
175 // this destructor returns.
176 //
Gabriel Charette30cdf0e52019-07-16 19:28:21177 // Use a ScopedClosureRunner to ensure that |done| is signaled even if the
François Doray1e392d22019-01-29 16:00:19178 // thread doesn't run any more tasks (if PostTask returns true, it means
179 // that the task was queued, but it doesn't mean that a RunLoop will run the
180 // task before the queue is deleted).
181 //
182 // We considered associating "generations" to file descriptors to avoid the
183 // synchronous wait. For example, if the IO thread gets a "cancel" for fd=6,
184 // generation=1 after getting a "start watching" for fd=6, generation=2, it
185 // can ignore the "Cancel". However, "generations" didn't solve this race:
186 //
187 // T1 (client) Start watching fd = 6 with WatchReadable()
188 // Stop watching fd = 6
189 // Close fd = 6
190 // Open a new file, fd = 6 gets reused.
191 // T2 (io) Watcher::StartWatching()
192 // Incorrectly starts watching fd = 6 which now refers to a
193 // different file than when WatchReadable() was called.
194 WaitableEvent done;
195 io_thread_task_runner_->PostTask(
196 FROM_HERE, BindOnce(
197 [](Watcher* watcher, ScopedClosureRunner closure) {
198 // Since |watcher| is a raw pointer, it isn't deleted
199 // if this callback is deleted before it gets to run.
200 delete watcher;
201 // |closure| runs at the end of this scope.
202 },
203 Unretained(watcher_.release()),
204 ScopedClosureRunner(BindOnce(&WaitableEvent::Signal,
205 Unretained(&done)))));
206 ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow;
207 done.Wait();
208 }
209
210 // Since WeakPtrs are invalidated by the destructor, any pending RunCallback()
211 // won't be invoked after this returns.
212}
213
fdorayf9f6c1e92016-09-15 13:23:24214void FileDescriptorWatcher::Controller::StartWatching() {
215 DCHECK(sequence_checker_.CalledOnValidSequence());
François Doray1e392d22019-01-29 16:00:19216 if (io_thread_task_runner_->BelongsToCurrentThread()) {
217 // If the MessagePumpForIO and the Controller live on the same thread.
218 watcher_->StartWatching();
219 } else {
220 // It is safe to use Unretained() below because |watcher_| can only be
221 // deleted by a delete task posted to |io_thread_task_runner_| by this
222 // Controller's destructor. Since this delete task hasn't been posted yet,
223 // it can't run before the task posted below.
224 io_thread_task_runner_->PostTask(
225 FROM_HERE,
226 BindOnce(&Watcher::StartWatching, Unretained(watcher_.get())));
227 }
fdorayf9f6c1e92016-09-15 13:23:24228}
229
230void FileDescriptorWatcher::Controller::RunCallback() {
231 DCHECK(sequence_checker_.CalledOnValidSequence());
232
233 WeakPtr<Controller> weak_this = weak_factory_.GetWeakPtr();
234
235 callback_.Run();
236
237 // If |this| wasn't deleted, re-enable the watch.
238 if (weak_this)
239 StartWatching();
240}
241
242FileDescriptorWatcher::FileDescriptorWatcher(
Alexander Timin6247f6a91a2018-10-27 15:40:10243 scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner)
244 : io_thread_task_runner_(std::move(io_thread_task_runner)) {
245 DCHECK(!tls_fd_watcher.Get().Get());
246 tls_fd_watcher.Get().Set(this);
fdorayf9f6c1e92016-09-15 13:23:24247}
248
249FileDescriptorWatcher::~FileDescriptorWatcher() {
Alexander Timin6247f6a91a2018-10-27 15:40:10250 tls_fd_watcher.Get().Set(nullptr);
fdorayf9f6c1e92016-09-15 13:23:24251}
252
253std::unique_ptr<FileDescriptorWatcher::Controller>
kylecharb2695fc2019-04-24 14:51:20254FileDescriptorWatcher::WatchReadable(int fd, const RepeatingClosure& callback) {
Gabriel Charette19d2ae62018-04-10 14:10:58255 return WrapUnique(new Controller(MessagePumpForIO::WATCH_READ, fd, callback));
fdorayf9f6c1e92016-09-15 13:23:24256}
257
258std::unique_ptr<FileDescriptorWatcher::Controller>
kylecharb2695fc2019-04-24 14:51:20259FileDescriptorWatcher::WatchWritable(int fd, const RepeatingClosure& callback) {
fdorayf9f6c1e92016-09-15 13:23:24260 return WrapUnique(
Gabriel Charette19d2ae62018-04-10 14:10:58261 new Controller(MessagePumpForIO::WATCH_WRITE, fd, callback));
fdorayf9f6c1e92016-09-15 13:23:24262}
263
Francois Dorayc1868292018-12-06 02:29:43264#if DCHECK_IS_ON()
265void FileDescriptorWatcher::AssertAllowed() {
266 DCHECK(tls_fd_watcher.Get().Get());
267}
268#endif
269
fdorayf9f6c1e92016-09-15 13:23:24270} // namespace base