Home | History | Annotate | Download | only in files
      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 
     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 
     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 
    103 FileDescriptorWatcher::Controller::Watcher::~Watcher() {
    104   DCHECK(thread_checker_.CalledOnValidThread());
    105   MessageLoopForIO::current()->RemoveDestructionObserver(this);
    106 }
    107 
    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 
    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 
    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::
    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 
    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 
    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 
    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 
    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 
    195 FileDescriptorWatcher::~FileDescriptorWatcher() {
    196   tls_message_loop_for_io.Get().Set(nullptr);
    197 }
    198 
    199 std::unique_ptr<FileDescriptorWatcher::Controller>
    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>
    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