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