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