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 
location()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.
RunImmediately()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