blob: 94f746f79f7a2660e98a095c059fa188ce237c70 [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 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"
15#include "base/threading/sequenced_task_runner_handle.h"
16#include "base/threading/thread_checker.h"
17#include "base/threading/thread_local.h"
18
19namespace base {
20
21namespace {
22
23// MessageLoopForIO used to watch file descriptors for which callbacks are
24// registered from a given thread.
Alexander Timin6247f6a91a2018-10-27 15:40:1025LazyInstance<ThreadLocalPointer<FileDescriptorWatcher>>::Leaky tls_fd_watcher =
26 LAZY_INSTANCE_INITIALIZER;
fdorayf9f6c1e92016-09-15 13:23:2427
28} // namespace
29
30FileDescriptorWatcher::Controller::~Controller() {
31 DCHECK(sequence_checker_.CalledOnValidSequence());
fdoray20e80002016-10-01 15:37:2932
Alexander Timin6247f6a91a2018-10-27 15:40:1033 // Delete |watcher_| on the IO thread task runner.
fdoray20e80002016-10-01 15:37:2934 //
35 // If the MessageLoopForIO is deleted before Watcher::StartWatching() runs,
36 // |watcher_| is leaked. If the MessageLoopForIO is deleted after
37 // Watcher::StartWatching() runs but before the DeleteSoon task runs,
38 // |watcher_| is deleted from Watcher::WillDestroyCurrentMessageLoop().
Alexander Timin6247f6a91a2018-10-27 15:40:1039 io_thread_task_runner_->DeleteSoon(FROM_HERE, watcher_.release());
fdoray20e80002016-10-01 15:37:2940
fdorayf9f6c1e92016-09-15 13:23:2441 // Since WeakPtrs are invalidated by the destructor, RunCallback() won't be
42 // invoked after this returns.
43}
44
45class FileDescriptorWatcher::Controller::Watcher
Gabriel Charette19d2ae62018-04-10 14:10:5846 : public MessagePumpForIO::FdWatcher,
Gabriel Charette810f3f432018-04-27 22:28:1447 public MessageLoopCurrent::DestructionObserver {
fdorayf9f6c1e92016-09-15 13:23:2448 public:
Gabriel Charette19d2ae62018-04-10 14:10:5849 Watcher(WeakPtr<Controller> controller, MessagePumpForIO::Mode mode, int fd);
fdorayf9f6c1e92016-09-15 13:23:2450 ~Watcher() override;
51
52 void StartWatching();
53
54 private:
55 friend class FileDescriptorWatcher;
56
Gabriel Charette19d2ae62018-04-10 14:10:5857 // MessagePumpForIO::FdWatcher:
fdorayf9f6c1e92016-09-15 13:23:2458 void OnFileCanReadWithoutBlocking(int fd) override;
59 void OnFileCanWriteWithoutBlocking(int fd) override;
60
Gabriel Charette810f3f432018-04-27 22:28:1461 // MessageLoopCurrent::DestructionObserver:
fdorayf9f6c1e92016-09-15 13:23:2462 void WillDestroyCurrentMessageLoop() override;
63
Gabriel Charette889b87c2018-05-11 22:23:3664 // The MessageLoopForIO's watch handle (stops the watch when destroyed).
65 MessagePumpForIO::FdWatchController fd_watch_controller_;
fdorayf9f6c1e92016-09-15 13:23:2466
67 // Runs tasks on the sequence on which this was instantiated (i.e. the
68 // sequence on which the callback must run).
69 const scoped_refptr<SequencedTaskRunner> callback_task_runner_ =
70 SequencedTaskRunnerHandle::Get();
71
72 // The Controller that created this Watcher.
73 WeakPtr<Controller> controller_;
74
75 // Whether this Watcher is notified when |fd_| becomes readable or writable
76 // without blocking.
Gabriel Charette19d2ae62018-04-10 14:10:5877 const MessagePumpForIO::Mode mode_;
fdorayf9f6c1e92016-09-15 13:23:2478
79 // The watched file descriptor.
80 const int fd_;
81
82 // Except for the constructor, every method of this class must run on the same
83 // MessageLoopForIO thread.
84 ThreadChecker thread_checker_;
85
86 // Whether this Watcher was registered as a DestructionObserver on the
87 // MessageLoopForIO thread.
88 bool registered_as_destruction_observer_ = false;
89
90 DISALLOW_COPY_AND_ASSIGN(Watcher);
91};
92
93FileDescriptorWatcher::Controller::Watcher::Watcher(
94 WeakPtr<Controller> controller,
Gabriel Charette19d2ae62018-04-10 14:10:5895 MessagePumpForIO::Mode mode,
fdorayf9f6c1e92016-09-15 13:23:2496 int fd)
Gabriel Charette889b87c2018-05-11 22:23:3697 : fd_watch_controller_(FROM_HERE),
ssid5dd4fb32017-02-16 23:57:1798 controller_(controller),
99 mode_(mode),
100 fd_(fd) {
fdorayf9f6c1e92016-09-15 13:23:24101 DCHECK(callback_task_runner_);
102 thread_checker_.DetachFromThread();
103}
104
105FileDescriptorWatcher::Controller::Watcher::~Watcher() {
106 DCHECK(thread_checker_.CalledOnValidThread());
Gabriel Charette810f3f432018-04-27 22:28:14107 MessageLoopCurrentForIO::Get()->RemoveDestructionObserver(this);
fdorayf9f6c1e92016-09-15 13:23:24108}
109
110void FileDescriptorWatcher::Controller::Watcher::StartWatching() {
111 DCHECK(thread_checker_.CalledOnValidThread());
Alexander Timin6247f6a91a2018-10-27 15:40:10112 DCHECK(MessageLoopCurrentForIO::IsSet());
fdorayf9f6c1e92016-09-15 13:23:24113
Gabriel Charette810f3f432018-04-27 22:28:14114 if (!MessageLoopCurrentForIO::Get()->WatchFileDescriptor(
Gabriel Charette889b87c2018-05-11 22:23:36115 fd_, false, mode_, &fd_watch_controller_, this)) {
Wez1be89cc2017-07-12 06:44:49116 // TODO(wez): Ideally we would [D]CHECK here, or propagate the failure back
117 // to the caller, but there is no guarantee that they haven't already
118 // closed |fd_| on another thread, so the best we can do is Debug-log.
119 DLOG(ERROR) << "Failed to watch fd=" << fd_;
120 }
fdorayf9f6c1e92016-09-15 13:23:24121
122 if (!registered_as_destruction_observer_) {
Gabriel Charette810f3f432018-04-27 22:28:14123 MessageLoopCurrentForIO::Get()->AddDestructionObserver(this);
fdorayf9f6c1e92016-09-15 13:23:24124 registered_as_destruction_observer_ = true;
125 }
126}
127
128void FileDescriptorWatcher::Controller::Watcher::OnFileCanReadWithoutBlocking(
129 int fd) {
130 DCHECK_EQ(fd_, fd);
Gabriel Charette19d2ae62018-04-10 14:10:58131 DCHECK_EQ(MessagePumpForIO::WATCH_READ, mode_);
fdorayf9f6c1e92016-09-15 13:23:24132 DCHECK(thread_checker_.CalledOnValidThread());
133
134 // Run the callback on the sequence on which the watch was initiated.
tzik92b7a422017-04-11 15:00:44135 callback_task_runner_->PostTask(
136 FROM_HERE, BindOnce(&Controller::RunCallback, controller_));
fdorayf9f6c1e92016-09-15 13:23:24137}
138
139void FileDescriptorWatcher::Controller::Watcher::OnFileCanWriteWithoutBlocking(
140 int fd) {
141 DCHECK_EQ(fd_, fd);
Gabriel Charette19d2ae62018-04-10 14:10:58142 DCHECK_EQ(MessagePumpForIO::WATCH_WRITE, mode_);
fdorayf9f6c1e92016-09-15 13:23:24143 DCHECK(thread_checker_.CalledOnValidThread());
144
145 // Run the callback on the sequence on which the watch was initiated.
tzik92b7a422017-04-11 15:00:44146 callback_task_runner_->PostTask(
147 FROM_HERE, BindOnce(&Controller::RunCallback, controller_));
fdorayf9f6c1e92016-09-15 13:23:24148}
149
150void FileDescriptorWatcher::Controller::Watcher::
151 WillDestroyCurrentMessageLoop() {
152 DCHECK(thread_checker_.CalledOnValidThread());
153
154 // A Watcher is owned by a Controller. When the Controller is deleted, it
155 // transfers ownership of the Watcher to a delete task posted to the
156 // MessageLoopForIO. If the MessageLoopForIO is deleted before the delete task
157 // runs, the following line takes care of deleting the Watcher.
158 delete this;
159}
160
Gabriel Charette19d2ae62018-04-10 14:10:58161FileDescriptorWatcher::Controller::Controller(MessagePumpForIO::Mode mode,
fdorayf9f6c1e92016-09-15 13:23:24162 int fd,
163 const Closure& callback)
164 : callback_(callback),
Alexander Timin6247f6a91a2018-10-27 15:40:10165 io_thread_task_runner_(
166 tls_fd_watcher.Get().Get()->io_thread_task_runner()),
fdorayf9f6c1e92016-09-15 13:23:24167 weak_factory_(this) {
168 DCHECK(!callback_.is_null());
Alexander Timin6247f6a91a2018-10-27 15:40:10169 DCHECK(io_thread_task_runner_);
Jeremy Roman9532f252017-08-16 23:27:24170 watcher_ = std::make_unique<Watcher>(weak_factory_.GetWeakPtr(), mode, fd);
fdorayf9f6c1e92016-09-15 13:23:24171 StartWatching();
172}
173
174void FileDescriptorWatcher::Controller::StartWatching() {
175 DCHECK(sequence_checker_.CalledOnValidSequence());
176 // It is safe to use Unretained() below because |watcher_| can only be deleted
Alexander Timin6247f6a91a2018-10-27 15:40:10177 // by a delete task posted to |io_thread_task_runner_| by this
fdorayf9f6c1e92016-09-15 13:23:24178 // Controller's destructor. Since this delete task hasn't been posted yet, it
179 // can't run before the task posted below.
Alexander Timin6247f6a91a2018-10-27 15:40:10180 io_thread_task_runner_->PostTask(
tzik92b7a422017-04-11 15:00:44181 FROM_HERE, BindOnce(&Watcher::StartWatching, Unretained(watcher_.get())));
fdorayf9f6c1e92016-09-15 13:23:24182}
183
184void FileDescriptorWatcher::Controller::RunCallback() {
185 DCHECK(sequence_checker_.CalledOnValidSequence());
186
187 WeakPtr<Controller> weak_this = weak_factory_.GetWeakPtr();
188
189 callback_.Run();
190
191 // If |this| wasn't deleted, re-enable the watch.
192 if (weak_this)
193 StartWatching();
194}
195
196FileDescriptorWatcher::FileDescriptorWatcher(
Alexander Timin6247f6a91a2018-10-27 15:40:10197 scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner)
198 : io_thread_task_runner_(std::move(io_thread_task_runner)) {
199 DCHECK(!tls_fd_watcher.Get().Get());
200 tls_fd_watcher.Get().Set(this);
fdorayf9f6c1e92016-09-15 13:23:24201}
202
203FileDescriptorWatcher::~FileDescriptorWatcher() {
Alexander Timin6247f6a91a2018-10-27 15:40:10204 tls_fd_watcher.Get().Set(nullptr);
fdorayf9f6c1e92016-09-15 13:23:24205}
206
207std::unique_ptr<FileDescriptorWatcher::Controller>
208FileDescriptorWatcher::WatchReadable(int fd, const Closure& callback) {
Gabriel Charette19d2ae62018-04-10 14:10:58209 return WrapUnique(new Controller(MessagePumpForIO::WATCH_READ, fd, callback));
fdorayf9f6c1e92016-09-15 13:23:24210}
211
212std::unique_ptr<FileDescriptorWatcher::Controller>
213FileDescriptorWatcher::WatchWritable(int fd, const Closure& callback) {
214 return WrapUnique(
Gabriel Charette19d2ae62018-04-10 14:10:58215 new Controller(MessagePumpForIO::WATCH_WRITE, fd, callback));
fdorayf9f6c1e92016-09-15 13:23:24216}
217
218} // namespace base