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 |