• 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 #include <brillo/message_loops/base_message_loop.h>
6 
7 #include <fcntl.h>
8 #include <sys/stat.h>
9 #include <sys/sysmacros.h>
10 #include <sys/types.h>
11 #include <unistd.h>
12 
13 #ifndef __APPLE__
14 #include <sys/sysmacros.h>
15 #endif
16 
17 #ifndef __ANDROID_HOST__
18 // Used for MISC_MAJOR. Only required for the target and not always available
19 // for the host.
20 #include <linux/major.h>
21 #endif
22 
23 #include <utility>
24 #include <vector>
25 
26 #include <base/bind.h>
27 #include <base/bind_helpers.h>
28 #include <base/files/file_path.h>
29 #include <base/files/file_util.h>
30 #include <base/run_loop.h>
31 #include <base/strings/string_number_conversions.h>
32 #include <base/strings/string_split.h>
33 #include <base/threading/thread_task_runner_handle.h>
34 
35 #include <brillo/location_logging.h>
36 #include <brillo/strings/string_utils.h>
37 
38 namespace {
39 
40 const char kMiscMinorPath[] = "/proc/misc";
41 const char kBinderDriverName[] = "binder";
42 
43 }  // namespace
44 
45 namespace brillo {
46 
47 const int BaseMessageLoop::kInvalidMinor = -1;
48 const int BaseMessageLoop::kUninitializedMinor = -2;
49 
BaseMessageLoop()50 BaseMessageLoop::BaseMessageLoop() {
51   CHECK(!base::ThreadTaskRunnerHandle::IsSet())
52       << "You can't create a base::MessageLoopForIO when another "
53          "base::MessageLoop is already created for this thread.";
54   owned_base_loop_.reset(new base::MessageLoopForIO());
55   base_loop_ = owned_base_loop_.get();
56   watcher_ = std::make_unique<base::FileDescriptorWatcher>(base_loop_);
57 }
58 
BaseMessageLoop(base::MessageLoopForIO * base_loop)59 BaseMessageLoop::BaseMessageLoop(base::MessageLoopForIO* base_loop)
60     : base_loop_(base_loop),
61       watcher_(std::make_unique<base::FileDescriptorWatcher>(base_loop_)) {}
62 
~BaseMessageLoop()63 BaseMessageLoop::~BaseMessageLoop() {
64   // Note all pending canceled delayed tasks when destroying the message loop.
65   size_t lazily_deleted_tasks = 0;
66   for (const auto& delayed_task : delayed_tasks_) {
67     if (delayed_task.second.closure.is_null()) {
68       lazily_deleted_tasks++;
69     } else {
70       DVLOG_LOC(delayed_task.second.location, 1)
71           << "Removing delayed task_id " << delayed_task.first
72           << " leaked on BaseMessageLoop, scheduled from this location.";
73     }
74   }
75   if (lazily_deleted_tasks) {
76     LOG(INFO) << "Leaking " << lazily_deleted_tasks << " canceled tasks.";
77   }
78 }
79 
PostDelayedTask(const base::Location & from_here,base::OnceClosure task,base::TimeDelta delay)80 MessageLoop::TaskId BaseMessageLoop::PostDelayedTask(
81     const base::Location& from_here,
82     base::OnceClosure task,
83     base::TimeDelta delay) {
84   TaskId task_id =  NextTaskId();
85   bool base_scheduled = base_loop_->task_runner()->PostDelayedTask(
86       from_here,
87       base::BindOnce(&BaseMessageLoop::OnRanPostedTask,
88                      weak_ptr_factory_.GetWeakPtr(), task_id),
89       delay);
90   DVLOG_LOC(from_here, 1) << "Scheduling delayed task_id " << task_id
91                           << " to run in " << delay << ".";
92   if (!base_scheduled)
93     return MessageLoop::kTaskIdNull;
94 
95   delayed_tasks_.emplace(task_id,
96                          DelayedTask{from_here, task_id, std::move(task)});
97   return task_id;
98 }
99 
CancelTask(TaskId task_id)100 bool BaseMessageLoop::CancelTask(TaskId task_id) {
101   if (task_id == kTaskIdNull)
102     return false;
103   auto delayed_task_it = delayed_tasks_.find(task_id);
104   if (delayed_task_it == delayed_tasks_.end())
105     return false;
106 
107   // A DelayedTask was found for this task_id at this point.
108 
109   // Check if the callback was already canceled but we have the entry in
110   // delayed_tasks_ since it didn't fire yet in the message loop.
111   if (delayed_task_it->second.closure.is_null())
112     return false;
113 
114   DVLOG_LOC(delayed_task_it->second.location, 1)
115       << "Removing task_id " << task_id << " scheduled from this location.";
116   // We reset to closure to a null OnceClosure to release all the resources
117   // used by this closure at this point, but we don't remove the task_id from
118   // delayed_tasks_ since we can't tell base::MessageLoopForIO to not run it.
119   delayed_task_it->second.closure.Reset();
120 
121   return true;
122 }
123 
RunOnce(bool may_block)124 bool BaseMessageLoop::RunOnce(bool may_block) {
125   run_once_ = true;
126   base::RunLoop run_loop;  // Uses the base::MessageLoopForIO implicitly.
127   base_run_loop_ = &run_loop;
128   if (!may_block)
129     run_loop.RunUntilIdle();
130   else
131     run_loop.Run();
132   base_run_loop_ = nullptr;
133   // If the flag was reset to false, it means a closure was run.
134   if (!run_once_)
135     return true;
136 
137   run_once_ = false;
138   return false;
139 }
140 
Run()141 void BaseMessageLoop::Run() {
142   base::RunLoop run_loop;  // Uses the base::MessageLoopForIO implicitly.
143   base_run_loop_ = &run_loop;
144   run_loop.Run();
145   base_run_loop_ = nullptr;
146 }
147 
BreakLoop()148 void BaseMessageLoop::BreakLoop() {
149   if (base_run_loop_ == nullptr) {
150     DVLOG(1) << "Message loop not running, ignoring BreakLoop().";
151     return;  // Message loop not running, nothing to do.
152   }
153   base_run_loop_->Quit();
154 }
155 
QuitClosure() const156 base::RepeatingClosure BaseMessageLoop::QuitClosure() const {
157   if (base_run_loop_ == nullptr)
158     return base::DoNothing();
159   return base_run_loop_->QuitClosure();
160 }
161 
NextTaskId()162 MessageLoop::TaskId BaseMessageLoop::NextTaskId() {
163   TaskId res;
164   do {
165     res = ++last_id_;
166     // We would run out of memory before we run out of task ids.
167   } while (!res ||
168            delayed_tasks_.find(res) != delayed_tasks_.end());
169   return res;
170 }
171 
OnRanPostedTask(MessageLoop::TaskId task_id)172 void BaseMessageLoop::OnRanPostedTask(MessageLoop::TaskId task_id) {
173   auto task_it = delayed_tasks_.find(task_id);
174   DCHECK(task_it != delayed_tasks_.end());
175   if (!task_it->second.closure.is_null()) {
176     DVLOG_LOC(task_it->second.location, 1)
177         << "Running delayed task_id " << task_id
178         << " scheduled from this location.";
179     // Mark the task as canceled while we are running it so CancelTask returns
180     // false.
181     std::move(task_it->second.closure).Run();
182 
183     // If the |run_once_| flag is set, it is because we are instructed to run
184     // only once callback.
185     if (run_once_) {
186       run_once_ = false;
187       BreakLoop();
188     }
189   }
190   delayed_tasks_.erase(task_it);
191 }
192 
ParseBinderMinor(const std::string & file_contents)193 int BaseMessageLoop::ParseBinderMinor(
194     const std::string& file_contents) {
195   int result = kInvalidMinor;
196   // Split along '\n', then along the ' '. Note that base::SplitString trims all
197   // white spaces at the beginning and end after splitting.
198   std::vector<std::string> lines =
199       base::SplitString(file_contents, "\n", base::TRIM_WHITESPACE,
200                         base::SPLIT_WANT_ALL);
201   for (const std::string& line : lines) {
202     if (line.empty())
203       continue;
204     std::string number;
205     std::string name;
206     if (!string_utils::SplitAtFirst(line, " ", &number, &name, false))
207       continue;
208 
209     if (name == kBinderDriverName && base::StringToInt(number, &result))
210       break;
211   }
212   return result;
213 }
214 
GetBinderMinor()215 unsigned int BaseMessageLoop::GetBinderMinor() {
216   if (binder_minor_ != kUninitializedMinor)
217     return binder_minor_;
218 
219   std::string proc_misc;
220   if (!base::ReadFileToString(base::FilePath(kMiscMinorPath), &proc_misc))
221     return binder_minor_;
222   binder_minor_ = ParseBinderMinor(proc_misc);
223   return binder_minor_;
224 }
225 
226 }  // namespace brillo
227