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