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