blob: 8e29d1975273d962cc6f136823545ce5005a04b4 [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"
8#include "base/lazy_instance.h"
9#include "base/logging.h"
10#include "base/memory/ptr_util.h"
Gabriel Charette19d2ae62018-04-10 14:10:5811#include "base/message_loop/message_pump_for_io.h"
fdorayf9f6c1e92016-09-15 13:23:2412#include "base/sequenced_task_runner.h"
13#include "base/single_thread_task_runner.h"
14#include "base/threading/sequenced_task_runner_handle.h"
15#include "base/threading/thread_checker.h"
16#include "base/threading/thread_local.h"
17
18namespace base {
19
20namespace {
21
22// MessageLoopForIO used to watch file descriptors for which callbacks are
23// registered from a given thread.
24LazyInstance<ThreadLocalPointer<MessageLoopForIO>>::Leaky
25 tls_message_loop_for_io = LAZY_INSTANCE_INITIALIZER;
26
27} // namespace
28
29FileDescriptorWatcher::Controller::~Controller() {
30 DCHECK(sequence_checker_.CalledOnValidSequence());
fdoray20e80002016-10-01 15:37:2931
32 // Delete |watcher_| on the MessageLoopForIO.
33 //
34 // If the MessageLoopForIO is deleted before Watcher::StartWatching() runs,
35 // |watcher_| is leaked. If the MessageLoopForIO is deleted after
36 // Watcher::StartWatching() runs but before the DeleteSoon task runs,
37 // |watcher_| is deleted from Watcher::WillDestroyCurrentMessageLoop().
fdorayf9f6c1e92016-09-15 13:23:2438 message_loop_for_io_task_runner_->DeleteSoon(FROM_HERE, watcher_.release());
fdoray20e80002016-10-01 15:37:2939
fdorayf9f6c1e92016-09-15 13:23:2440 // Since WeakPtrs are invalidated by the destructor, RunCallback() won't be
41 // invoked after this returns.
42}
43
44class FileDescriptorWatcher::Controller::Watcher
Gabriel Charette19d2ae62018-04-10 14:10:5845 : public MessagePumpForIO::FdWatcher,
fdorayf9f6c1e92016-09-15 13:23:2446 public MessageLoop::DestructionObserver {
47 public:
Gabriel Charette19d2ae62018-04-10 14:10:5848 Watcher(WeakPtr<Controller> controller, MessagePumpForIO::Mode mode, int fd);
fdorayf9f6c1e92016-09-15 13:23:2449 ~Watcher() override;
50
51 void StartWatching();
52
53 private:
54 friend class FileDescriptorWatcher;
55
Gabriel Charette19d2ae62018-04-10 14:10:5856 // MessagePumpForIO::FdWatcher:
fdorayf9f6c1e92016-09-15 13:23:2457 void OnFileCanReadWithoutBlocking(int fd) override;
58 void OnFileCanWriteWithoutBlocking(int fd) override;
59
60 // MessageLoop::DestructionObserver:
61 void WillDestroyCurrentMessageLoop() override;
62
63 // Used to instruct the MessageLoopForIO to stop watching the file descriptor.
Gabriel Charette19d2ae62018-04-10 14:10:5864 MessagePumpForIO::FdWatchController file_descriptor_watcher_;
fdorayf9f6c1e92016-09-15 13:23:2465
66 // Runs tasks on the sequence on which this was instantiated (i.e. the
67 // sequence on which the callback must run).
68 const scoped_refptr<SequencedTaskRunner> callback_task_runner_ =
69 SequencedTaskRunnerHandle::Get();
70
71 // The Controller that created this Watcher.
72 WeakPtr<Controller> controller_;
73
74 // Whether this Watcher is notified when |fd_| becomes readable or writable
75 // without blocking.
Gabriel Charette19d2ae62018-04-10 14:10:5876 const MessagePumpForIO::Mode mode_;
fdorayf9f6c1e92016-09-15 13:23:2477
78 // The watched file descriptor.
79 const int fd_;
80
81 // Except for the constructor, every method of this class must run on the same
82 // MessageLoopForIO thread.
83 ThreadChecker thread_checker_;
84
85 // Whether this Watcher was registered as a DestructionObserver on the
86 // MessageLoopForIO thread.
87 bool registered_as_destruction_observer_ = false;
88
89 DISALLOW_COPY_AND_ASSIGN(Watcher);
90};
91
92FileDescriptorWatcher::Controller::Watcher::Watcher(
93 WeakPtr<Controller> controller,
Gabriel Charette19d2ae62018-04-10 14:10:5894 MessagePumpForIO::Mode mode,
fdorayf9f6c1e92016-09-15 13:23:2495 int fd)
ssid5dd4fb32017-02-16 23:57:1796 : file_descriptor_watcher_(FROM_HERE),
97 controller_(controller),
98 mode_(mode),
99 fd_(fd) {
fdorayf9f6c1e92016-09-15 13:23:24100 DCHECK(callback_task_runner_);
101 thread_checker_.DetachFromThread();
102}
103
104FileDescriptorWatcher::Controller::Watcher::~Watcher() {
105 DCHECK(thread_checker_.CalledOnValidThread());
106 MessageLoopForIO::current()->RemoveDestructionObserver(this);
107}
108
109void FileDescriptorWatcher::Controller::Watcher::StartWatching() {
110 DCHECK(thread_checker_.CalledOnValidThread());
111
Wez1be89cc2017-07-12 06:44:49112 if (!MessageLoopForIO::current()->WatchFileDescriptor(
113 fd_, false, mode_, &file_descriptor_watcher_, this)) {
114 // TODO(wez): Ideally we would [D]CHECK here, or propagate the failure back
115 // to the caller, but there is no guarantee that they haven't already
116 // closed |fd_| on another thread, so the best we can do is Debug-log.
117 DLOG(ERROR) << "Failed to watch fd=" << fd_;
118 }
fdorayf9f6c1e92016-09-15 13:23:24119
120 if (!registered_as_destruction_observer_) {
121 MessageLoopForIO::current()->AddDestructionObserver(this);
122 registered_as_destruction_observer_ = true;
123 }
124}
125
126void FileDescriptorWatcher::Controller::Watcher::OnFileCanReadWithoutBlocking(
127 int fd) {
128 DCHECK_EQ(fd_, fd);
Gabriel Charette19d2ae62018-04-10 14:10:58129 DCHECK_EQ(MessagePumpForIO::WATCH_READ, mode_);
fdorayf9f6c1e92016-09-15 13:23:24130 DCHECK(thread_checker_.CalledOnValidThread());
131
132 // Run the callback on the sequence on which the watch was initiated.
tzik92b7a422017-04-11 15:00:44133 callback_task_runner_->PostTask(
134 FROM_HERE, BindOnce(&Controller::RunCallback, controller_));
fdorayf9f6c1e92016-09-15 13:23:24135}
136
137void FileDescriptorWatcher::Controller::Watcher::OnFileCanWriteWithoutBlocking(
138 int fd) {
139 DCHECK_EQ(fd_, fd);
Gabriel Charette19d2ae62018-04-10 14:10:58140 DCHECK_EQ(MessagePumpForIO::WATCH_WRITE, mode_);
fdorayf9f6c1e92016-09-15 13:23:24141 DCHECK(thread_checker_.CalledOnValidThread());
142
143 // Run the callback on the sequence on which the watch was initiated.
tzik92b7a422017-04-11 15:00:44144 callback_task_runner_->PostTask(
145 FROM_HERE, BindOnce(&Controller::RunCallback, controller_));
fdorayf9f6c1e92016-09-15 13:23:24146}
147
148void FileDescriptorWatcher::Controller::Watcher::
149 WillDestroyCurrentMessageLoop() {
150 DCHECK(thread_checker_.CalledOnValidThread());
151
152 // A Watcher is owned by a Controller. When the Controller is deleted, it
153 // transfers ownership of the Watcher to a delete task posted to the
154 // MessageLoopForIO. If the MessageLoopForIO is deleted before the delete task
155 // runs, the following line takes care of deleting the Watcher.
156 delete this;
157}
158
Gabriel Charette19d2ae62018-04-10 14:10:58159FileDescriptorWatcher::Controller::Controller(MessagePumpForIO::Mode mode,
fdorayf9f6c1e92016-09-15 13:23:24160 int fd,
161 const Closure& callback)
162 : callback_(callback),
163 message_loop_for_io_task_runner_(
164 tls_message_loop_for_io.Get().Get()->task_runner()),
165 weak_factory_(this) {
166 DCHECK(!callback_.is_null());
167 DCHECK(message_loop_for_io_task_runner_);
Jeremy Roman9532f252017-08-16 23:27:24168 watcher_ = std::make_unique<Watcher>(weak_factory_.GetWeakPtr(), mode, fd);
fdorayf9f6c1e92016-09-15 13:23:24169 StartWatching();
170}
171
172void FileDescriptorWatcher::Controller::StartWatching() {
173 DCHECK(sequence_checker_.CalledOnValidSequence());
174 // It is safe to use Unretained() below because |watcher_| can only be deleted
175 // by a delete task posted to |message_loop_for_io_task_runner_| by this
176 // Controller's destructor. Since this delete task hasn't been posted yet, it
177 // can't run before the task posted below.
178 message_loop_for_io_task_runner_->PostTask(
tzik92b7a422017-04-11 15:00:44179 FROM_HERE, BindOnce(&Watcher::StartWatching, Unretained(watcher_.get())));
fdorayf9f6c1e92016-09-15 13:23:24180}
181
182void FileDescriptorWatcher::Controller::RunCallback() {
183 DCHECK(sequence_checker_.CalledOnValidSequence());
184
185 WeakPtr<Controller> weak_this = weak_factory_.GetWeakPtr();
186
187 callback_.Run();
188
189 // If |this| wasn't deleted, re-enable the watch.
190 if (weak_this)
191 StartWatching();
192}
193
194FileDescriptorWatcher::FileDescriptorWatcher(
195 MessageLoopForIO* message_loop_for_io) {
196 DCHECK(message_loop_for_io);
197 DCHECK(!tls_message_loop_for_io.Get().Get());
198 tls_message_loop_for_io.Get().Set(message_loop_for_io);
199}
200
201FileDescriptorWatcher::~FileDescriptorWatcher() {
202 tls_message_loop_for_io.Get().Set(nullptr);
203}
204
205std::unique_ptr<FileDescriptorWatcher::Controller>
206FileDescriptorWatcher::WatchReadable(int fd, const Closure& callback) {
Gabriel Charette19d2ae62018-04-10 14:10:58207 return WrapUnique(new Controller(MessagePumpForIO::WATCH_READ, fd, callback));
fdorayf9f6c1e92016-09-15 13:23:24208}
209
210std::unique_ptr<FileDescriptorWatcher::Controller>
211FileDescriptorWatcher::WatchWritable(int fd, const Closure& callback) {
212 return WrapUnique(
Gabriel Charette19d2ae62018-04-10 14:10:58213 new Controller(MessagePumpForIO::WATCH_WRITE, fd, callback));
fdorayf9f6c1e92016-09-15 13:23:24214}
215
216} // namespace base