Home | History | Annotate | Download | only in message_loops
      1 // Copyright 2015 The Chromium OS 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 #ifndef LIBBRILLO_BRILLO_MESSAGE_LOOPS_BASE_MESSAGE_LOOP_H_
      6 #define LIBBRILLO_BRILLO_MESSAGE_LOOPS_BASE_MESSAGE_LOOP_H_
      7 
      8 // BaseMessageLoop is a brillo::MessageLoop implementation based on
      9 // base::MessageLoopForIO. This allows to mix new code using
     10 // brillo::MessageLoop and legacy code using base::MessageLoopForIO in the
     11 // same thread and share a single main loop. This disadvantage of using this
     12 // class is a less efficient implementation of CancelTask() for delayed tasks
     13 // since base::MessageLoopForIO doesn't provide a way to remove the event.
     14 
     15 #include <map>
     16 #include <memory>
     17 #include <string>
     18 
     19 #include <base/location.h>
     20 #include <base/memory/weak_ptr.h>
     21 #include <base/message_loop/message_loop.h>
     22 #include <base/time/time.h>
     23 #include <gtest/gtest_prod.h>
     24 
     25 #include <brillo/brillo_export.h>
     26 #include <brillo/message_loops/message_loop.h>
     27 
     28 namespace brillo {
     29 
     30 class BRILLO_EXPORT BaseMessageLoop : public MessageLoop {
     31  public:
     32   explicit BaseMessageLoop(base::MessageLoopForIO* base_loop);
     33   ~BaseMessageLoop() override;
     34 
     35   // MessageLoop overrides.
     36   TaskId PostDelayedTask(const tracked_objects::Location& from_here,
     37                          const base::Closure& task,
     38                          base::TimeDelta delay) override;
     39   using MessageLoop::PostDelayedTask;
     40   TaskId WatchFileDescriptor(const tracked_objects::Location& from_here,
     41                              int fd,
     42                              WatchMode mode,
     43                              bool persistent,
     44                              const base::Closure& task) override;
     45   using MessageLoop::WatchFileDescriptor;
     46   bool CancelTask(TaskId task_id) override;
     47   bool RunOnce(bool may_block) override;
     48   void Run() override;
     49   void BreakLoop() override;
     50 
     51   // Returns a callback that will quit the current message loop. If the message
     52   // loop is not running, an empty (null) callback is returned.
     53   base::Closure QuitClosure() const;
     54 
     55  private:
     56   FRIEND_TEST(BaseMessageLoopTest, ParseBinderMinor);
     57 
     58   static const int kInvalidMinor;
     59   static const int kUninitializedMinor;
     60 
     61   // Parses the contents of the file /proc/misc passed in |file_contents| and
     62   // returns the minor device number reported for binder. On error or if not
     63   // found, returns kInvalidMinor.
     64   static int ParseBinderMinor(const std::string& file_contents);
     65 
     66   // Called by base::MessageLoopForIO when is time to call the callback
     67   // scheduled with Post*Task() of id |task_id|, even if it was canceled.
     68   void OnRanPostedTask(MessageLoop::TaskId task_id);
     69 
     70   // Called from the message loop when the IOTask should run the scheduled
     71   // callback. This is a simple wrapper of IOTask::OnFileReadyPostedTask()
     72   // posted from the BaseMessageLoop so it is deleted when the BaseMessageLoop
     73   // goes out of scope since we can't cancel the callback otherwise.
     74   void OnFileReadyPostedTask(MessageLoop::TaskId task_id);
     75 
     76   // Return a new unused task_id.
     77   TaskId NextTaskId();
     78 
     79   // Returns binder minor device number.
     80   unsigned int GetBinderMinor();
     81 
     82   struct DelayedTask {
     83     tracked_objects::Location location;
     84 
     85     MessageLoop::TaskId task_id;
     86     base::Closure closure;
     87   };
     88 
     89   std::map<MessageLoop::TaskId, DelayedTask> delayed_tasks_;
     90 
     91   class IOTask : public base::MessageLoopForIO::Watcher {
     92    public:
     93     IOTask(const tracked_objects::Location& location,
     94            BaseMessageLoop* loop,
     95            MessageLoop::TaskId task_id,
     96            int fd,
     97            base::MessageLoopForIO::Mode base_mode,
     98            bool persistent,
     99            const base::Closure& task);
    100 
    101     const tracked_objects::Location& location() const { return location_; }
    102 
    103     // Used to start/stop watching the file descriptor while keeping the
    104     // IOTask entry available.
    105     bool StartWatching();
    106     void StopWatching();
    107 
    108     // Called from the message loop as a PostTask() when the file descriptor is
    109     // available, scheduled to run from OnFileReady().
    110     void OnFileReadyPostedTask();
    111 
    112     // Cancel the IOTask and returns whether it was actually canceled, with the
    113     // same semantics as MessageLoop::CancelTask().
    114     bool CancelTask();
    115 
    116     // Sets the closure to be run immediately whenever the file descriptor
    117     // becomes ready.
    118     void RunImmediately() { immediate_run_= true; }
    119 
    120    private:
    121     tracked_objects::Location location_;
    122     BaseMessageLoop* loop_;
    123 
    124     // These are the arguments passed in the constructor, basically forwarding
    125     // all the arguments passed to WatchFileDescriptor() plus the assigned
    126     // TaskId for this task.
    127     MessageLoop::TaskId task_id_;
    128     int fd_;
    129     base::MessageLoopForIO::Mode base_mode_;
    130     bool persistent_;
    131     base::Closure closure_;
    132 
    133     base::MessageLoopForIO::FileDescriptorWatcher fd_watcher_;
    134 
    135     // Tells whether there is a pending call to OnFileReadPostedTask().
    136     bool posted_task_pending_{false};
    137 
    138     // Whether the registered callback should be running immediately when the
    139     // file descriptor is ready, as opposed to posting a task to the main loop
    140     // to prevent starvation.
    141     bool immediate_run_{false};
    142 
    143     // base::MessageLoopForIO::Watcher overrides:
    144     void OnFileCanReadWithoutBlocking(int fd) override;
    145     void OnFileCanWriteWithoutBlocking(int fd) override;
    146 
    147     // Common implementation for both the read and write case.
    148     void OnFileReady();
    149 
    150     DISALLOW_COPY_AND_ASSIGN(IOTask);
    151   };
    152 
    153   std::map<MessageLoop::TaskId, IOTask> io_tasks_;
    154 
    155   // Flag to mark that we should run the message loop only one iteration.
    156   bool run_once_{false};
    157 
    158   // The last used TaskId. While base::MessageLoopForIO doesn't allow to cancel
    159   // delayed tasks, we handle that functionality by not running the callback
    160   // if it fires at a later point.
    161   MessageLoop::TaskId last_id_{kTaskIdNull};
    162 
    163   // The pointer to the libchrome base::MessageLoopForIO we are wrapping with
    164   // this interface.
    165   base::MessageLoopForIO* base_loop_;
    166 
    167   // The RunLoop instance used to run the main loop from Run().
    168   base::RunLoop* base_run_loop_{nullptr};
    169 
    170   // The binder minor device number. Binder is a "misc" char device with a
    171   // dynamically allocated minor number. When uninitialized, this value will
    172   // be negative, otherwise, it will hold the minor part of the binder device
    173   // number. This is populated by GetBinderMinor().
    174   int binder_minor_{kUninitializedMinor};
    175 
    176   // We use a WeakPtrFactory to schedule tasks with the base::MessageLoopForIO
    177   // since we can't cancel the callbacks we have scheduled there once this
    178   // instance is destroyed.
    179   base::WeakPtrFactory<BaseMessageLoop> weak_ptr_factory_;
    180   DISALLOW_COPY_AND_ASSIGN(BaseMessageLoop);
    181 };
    182 
    183 }  // namespace brillo
    184 
    185 #endif  // LIBBRILLO_BRILLO_MESSAGE_LOOPS_BASE_MESSAGE_LOOP_H_
    186