OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/message_loop/message_loop.h" | 5 #include "base/message_loop/message_loop.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/compiler_specific.h" | 10 #include "base/compiler_specific.h" |
11 #include "base/debug/alias.h" | 11 #include "base/debug/alias.h" |
12 #include "base/debug/trace_event.h" | 12 #include "base/debug/trace_event.h" |
13 #include "base/lazy_instance.h" | 13 #include "base/lazy_instance.h" |
14 #include "base/logging.h" | 14 #include "base/logging.h" |
15 #include "base/memory/scoped_ptr.h" | 15 #include "base/memory/scoped_ptr.h" |
16 #include "base/message_loop/message_loop_proxy_impl.h" | |
17 #include "base/message_loop/message_pump_default.h" | 16 #include "base/message_loop/message_pump_default.h" |
18 #include "base/metrics/histogram.h" | 17 #include "base/metrics/histogram.h" |
19 #include "base/metrics/statistics_recorder.h" | 18 #include "base/metrics/statistics_recorder.h" |
20 #include "base/run_loop.h" | 19 #include "base/run_loop.h" |
21 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" | 20 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" |
22 #include "base/thread_task_runner_handle.h" | 21 #include "base/thread_task_runner_handle.h" |
23 #include "base/threading/thread_local.h" | 22 #include "base/threading/thread_local.h" |
24 #include "base/time/time.h" | 23 #include "base/time/time.h" |
25 #include "base/tracked_objects.h" | 24 #include "base/tracked_objects.h" |
26 | 25 |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
82 VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent) | 81 VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent) |
83 VALUE_TO_NUMBER_AND_NAME(kTimerEvent) | 82 VALUE_TO_NUMBER_AND_NAME(kTimerEvent) |
84 | 83 |
85 {-1, NULL} // The list must be null terminated, per API to histogram. | 84 {-1, NULL} // The list must be null terminated, per API to histogram. |
86 }; | 85 }; |
87 | 86 |
88 bool enable_histogrammer_ = false; | 87 bool enable_histogrammer_ = false; |
89 | 88 |
90 MessageLoop::MessagePumpFactory* message_pump_for_ui_factory_ = NULL; | 89 MessageLoop::MessagePumpFactory* message_pump_for_ui_factory_ = NULL; |
91 | 90 |
92 // Create a process-wide unique ID to represent this task in trace events. This | |
93 // will be mangled with a Process ID hash to reduce the likelyhood of colliding | |
94 // with MessageLoop pointers on other processes. | |
95 uint64 GetTaskTraceID(const PendingTask& task, MessageLoop* loop) { | |
96 return (static_cast<uint64>(task.sequence_num) << 32) | | |
97 static_cast<uint64>(reinterpret_cast<intptr_t>(loop)); | |
98 } | |
99 | |
100 } // namespace | 91 } // namespace |
101 | 92 |
102 //------------------------------------------------------------------------------ | 93 //------------------------------------------------------------------------------ |
103 | 94 |
104 #if defined(OS_WIN) | 95 #if defined(OS_WIN) |
105 | 96 |
106 // Upon a SEH exception in this thread, it restores the original unhandled | 97 // Upon a SEH exception in this thread, it restores the original unhandled |
107 // exception filter. | 98 // exception filter. |
108 static int SEHFilter(LPTOP_LEVEL_EXCEPTION_FILTER old_filter) { | 99 static int SEHFilter(LPTOP_LEVEL_EXCEPTION_FILTER old_filter) { |
109 ::SetUnhandledExceptionFilter(old_filter); | 100 ::SetUnhandledExceptionFilter(old_filter); |
(...skipping 19 matching lines...) Expand all Loading... |
129 MessageLoop::TaskObserver::~TaskObserver() { | 120 MessageLoop::TaskObserver::~TaskObserver() { |
130 } | 121 } |
131 | 122 |
132 MessageLoop::DestructionObserver::~DestructionObserver() { | 123 MessageLoop::DestructionObserver::~DestructionObserver() { |
133 } | 124 } |
134 | 125 |
135 //------------------------------------------------------------------------------ | 126 //------------------------------------------------------------------------------ |
136 | 127 |
137 MessageLoop::MessageLoop(Type type) | 128 MessageLoop::MessageLoop(Type type) |
138 : type_(type), | 129 : type_(type), |
| 130 exception_restoration_(false), |
139 nestable_tasks_allowed_(true), | 131 nestable_tasks_allowed_(true), |
140 exception_restoration_(false), | |
141 message_histogram_(NULL), | |
142 run_loop_(NULL), | |
143 #if defined(OS_WIN) | 132 #if defined(OS_WIN) |
144 os_modal_loop_(false), | 133 os_modal_loop_(false), |
145 #endif // OS_WIN | 134 #endif // OS_WIN |
146 next_sequence_num_(0) { | 135 message_histogram_(NULL), |
| 136 run_loop_(NULL) { |
147 DCHECK(!current()) << "should only have one message loop per thread"; | 137 DCHECK(!current()) << "should only have one message loop per thread"; |
148 lazy_tls_ptr.Pointer()->Set(this); | 138 lazy_tls_ptr.Pointer()->Set(this); |
149 | 139 |
150 message_loop_proxy_ = new MessageLoopProxyImpl(); | 140 incoming_task_queue_ = new internal::IncomingTaskQueue(); |
| 141 message_loop_proxy_ = |
| 142 new internal::MessageLoopProxyImpl(incoming_task_queue_); |
151 thread_task_runner_handle_.reset( | 143 thread_task_runner_handle_.reset( |
152 new ThreadTaskRunnerHandle(message_loop_proxy_)); | 144 new ThreadTaskRunnerHandle(message_loop_proxy_)); |
153 | 145 |
154 // TODO(rvargas): Get rid of the OS guards. | 146 // TODO(rvargas): Get rid of the OS guards. |
155 #if defined(OS_WIN) | 147 #if defined(OS_WIN) |
156 #define MESSAGE_PUMP_UI new MessagePumpForUI() | 148 #define MESSAGE_PUMP_UI new MessagePumpForUI() |
157 #define MESSAGE_PUMP_IO new MessagePumpForIO() | 149 #define MESSAGE_PUMP_IO new MessagePumpForIO() |
158 #elif defined(OS_IOS) | 150 #elif defined(OS_IOS) |
159 #define MESSAGE_PUMP_UI MessagePumpMac::Create() | 151 #define MESSAGE_PUMP_UI MessagePumpMac::Create() |
160 #define MESSAGE_PUMP_IO new MessagePumpIOSForIO() | 152 #define MESSAGE_PUMP_IO new MessagePumpIOSForIO() |
161 #elif defined(OS_MACOSX) | 153 #elif defined(OS_MACOSX) |
162 #define MESSAGE_PUMP_UI MessagePumpMac::Create() | 154 #define MESSAGE_PUMP_UI MessagePumpMac::Create() |
163 #define MESSAGE_PUMP_IO new MessagePumpLibevent() | 155 #define MESSAGE_PUMP_IO new MessagePumpLibevent() |
164 #elif defined(OS_NACL) | 156 #elif defined(OS_NACL) |
165 // Currently NaCl doesn't have a UI MessageLoop. | 157 // Currently NaCl doesn't have a UI MessageLoop. |
166 // TODO(abarth): Figure out if we need this. | 158 // TODO(abarth): Figure out if we need this. |
167 #define MESSAGE_PUMP_UI NULL | 159 #define MESSAGE_PUMP_UI NULL |
168 // ipc_channel_nacl.cc uses a worker thread to do socket reads currently, and | 160 // ipc_channel_nacl.cc uses a worker thread to do socket reads currently, and |
169 // doesn't require extra support for watching file descriptors. | 161 // doesn't require extra support for watching file descriptors. |
170 #define MESSAGE_PUMP_IO new MessagePumpDefault(); | 162 #define MESSAGE_PUMP_IO new MessagePumpDefault() |
171 #elif defined(OS_POSIX) // POSIX but not MACOSX. | 163 #elif defined(OS_POSIX) // POSIX but not MACOSX. |
172 #define MESSAGE_PUMP_UI new MessagePumpForUI() | 164 #define MESSAGE_PUMP_UI new MessagePumpForUI() |
173 #define MESSAGE_PUMP_IO new MessagePumpLibevent() | 165 #define MESSAGE_PUMP_IO new MessagePumpLibevent() |
174 #else | 166 #else |
175 #error Not implemented | 167 #error Not implemented |
176 #endif | 168 #endif |
177 | 169 |
178 if (type_ == TYPE_UI) { | 170 if (type_ == TYPE_UI) { |
179 if (message_pump_for_ui_factory_) | 171 if (message_pump_for_ui_factory_) |
180 pump_ = message_pump_for_ui_factory_(); | 172 pump_.reset(message_pump_for_ui_factory_()); |
181 else | 173 else |
182 pump_ = MESSAGE_PUMP_UI; | 174 pump_.reset(MESSAGE_PUMP_UI); |
183 } else if (type_ == TYPE_IO) { | 175 } else if (type_ == TYPE_IO) { |
184 pump_ = MESSAGE_PUMP_IO; | 176 pump_.reset(MESSAGE_PUMP_IO); |
185 } else { | 177 } else { |
186 DCHECK_EQ(TYPE_DEFAULT, type_); | 178 DCHECK_EQ(TYPE_DEFAULT, type_); |
187 pump_ = new MessagePumpDefault(); | 179 pump_.reset(new MessagePumpDefault()); |
188 } | 180 } |
189 } | 181 } |
190 | 182 |
191 MessageLoop::~MessageLoop() { | 183 MessageLoop::~MessageLoop() { |
192 DCHECK_EQ(this, current()); | 184 DCHECK_EQ(this, current()); |
193 | 185 |
194 DCHECK(!run_loop_); | 186 DCHECK(!run_loop_); |
195 | 187 |
196 // Clean up any unprocessed tasks, but take care: deleting a task could | 188 // Clean up any unprocessed tasks, but take care: deleting a task could |
197 // result in the addition of more tasks (e.g., via DeleteSoon). We set a | 189 // result in the addition of more tasks (e.g., via DeleteSoon). We set a |
(...skipping 11 matching lines...) Expand all Loading... |
209 break; | 201 break; |
210 } | 202 } |
211 DCHECK(!did_work); | 203 DCHECK(!did_work); |
212 | 204 |
213 // Let interested parties have one last shot at accessing this. | 205 // Let interested parties have one last shot at accessing this. |
214 FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_, | 206 FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_, |
215 WillDestroyCurrentMessageLoop()); | 207 WillDestroyCurrentMessageLoop()); |
216 | 208 |
217 thread_task_runner_handle_.reset(); | 209 thread_task_runner_handle_.reset(); |
218 | 210 |
219 // Tell the message_loop_proxy that we are dying. | 211 // Tell the incoming queue that we are dying. |
220 static_cast<MessageLoopProxyImpl*>(message_loop_proxy_.get())-> | 212 incoming_task_queue_->WillDestroyCurrentMessageLoop(); |
221 WillDestroyCurrentMessageLoop(); | 213 incoming_task_queue_ = NULL; |
222 message_loop_proxy_ = NULL; | 214 message_loop_proxy_ = NULL; |
223 | 215 |
224 // OK, now make it so that no one can find us. | 216 // OK, now make it so that no one can find us. |
225 lazy_tls_ptr.Pointer()->Set(NULL); | 217 lazy_tls_ptr.Pointer()->Set(NULL); |
226 | |
227 #if defined(OS_WIN) | |
228 // If we left the high-resolution timer activated, deactivate it now. | |
229 // Doing this is not-critical, it is mainly to make sure we track | |
230 // the high resolution timer activations properly in our unit tests. | |
231 if (!high_resolution_timer_expiration_.is_null()) { | |
232 Time::ActivateHighResolutionTimer(false); | |
233 high_resolution_timer_expiration_ = TimeTicks(); | |
234 } | |
235 #endif | |
236 } | 218 } |
237 | 219 |
238 // static | 220 // static |
239 MessageLoop* MessageLoop::current() { | 221 MessageLoop* MessageLoop::current() { |
240 // TODO(darin): sadly, we cannot enable this yet since people call us even | 222 // TODO(darin): sadly, we cannot enable this yet since people call us even |
241 // when they have no intention of using us. | 223 // when they have no intention of using us. |
242 // DCHECK(loop) << "Ouch, did you forget to initialize me?"; | 224 // DCHECK(loop) << "Ouch, did you forget to initialize me?"; |
243 return lazy_tls_ptr.Pointer()->Get(); | 225 return lazy_tls_ptr.Pointer()->Get(); |
244 } | 226 } |
245 | 227 |
(...skipping 20 matching lines...) Expand all Loading... |
266 void MessageLoop::RemoveDestructionObserver( | 248 void MessageLoop::RemoveDestructionObserver( |
267 DestructionObserver* destruction_observer) { | 249 DestructionObserver* destruction_observer) { |
268 DCHECK_EQ(this, current()); | 250 DCHECK_EQ(this, current()); |
269 destruction_observers_.RemoveObserver(destruction_observer); | 251 destruction_observers_.RemoveObserver(destruction_observer); |
270 } | 252 } |
271 | 253 |
272 void MessageLoop::PostTask( | 254 void MessageLoop::PostTask( |
273 const tracked_objects::Location& from_here, | 255 const tracked_objects::Location& from_here, |
274 const Closure& task) { | 256 const Closure& task) { |
275 DCHECK(!task.is_null()) << from_here.ToString(); | 257 DCHECK(!task.is_null()) << from_here.ToString(); |
276 PendingTask pending_task( | 258 incoming_task_queue_->AddToIncomingQueue(from_here, task, TimeDelta(), true); |
277 from_here, task, CalculateDelayedRuntime(TimeDelta()), true); | |
278 AddToIncomingQueue(&pending_task, false); | |
279 } | 259 } |
280 | 260 |
281 bool MessageLoop::TryPostTask( | 261 bool MessageLoop::TryPostTask( |
282 const tracked_objects::Location& from_here, | 262 const tracked_objects::Location& from_here, |
283 const Closure& task) { | 263 const Closure& task) { |
284 DCHECK(!task.is_null()) << from_here.ToString(); | 264 DCHECK(!task.is_null()) << from_here.ToString(); |
285 PendingTask pending_task( | 265 return incoming_task_queue_->TryAddToIncomingQueue(from_here, task); |
286 from_here, task, CalculateDelayedRuntime(TimeDelta()), true); | |
287 return AddToIncomingQueue(&pending_task, true); | |
288 } | 266 } |
289 | 267 |
290 void MessageLoop::PostDelayedTask( | 268 void MessageLoop::PostDelayedTask( |
291 const tracked_objects::Location& from_here, | 269 const tracked_objects::Location& from_here, |
292 const Closure& task, | 270 const Closure& task, |
293 TimeDelta delay) { | 271 TimeDelta delay) { |
294 DCHECK(!task.is_null()) << from_here.ToString(); | 272 DCHECK(!task.is_null()) << from_here.ToString(); |
295 PendingTask pending_task( | 273 incoming_task_queue_->AddToIncomingQueue(from_here, task, delay, true); |
296 from_here, task, CalculateDelayedRuntime(delay), true); | |
297 AddToIncomingQueue(&pending_task, false); | |
298 } | 274 } |
299 | 275 |
300 void MessageLoop::PostNonNestableTask( | 276 void MessageLoop::PostNonNestableTask( |
301 const tracked_objects::Location& from_here, | 277 const tracked_objects::Location& from_here, |
302 const Closure& task) { | 278 const Closure& task) { |
303 DCHECK(!task.is_null()) << from_here.ToString(); | 279 DCHECK(!task.is_null()) << from_here.ToString(); |
304 PendingTask pending_task( | 280 incoming_task_queue_->AddToIncomingQueue(from_here, task, TimeDelta(), false); |
305 from_here, task, CalculateDelayedRuntime(TimeDelta()), false); | |
306 AddToIncomingQueue(&pending_task, false); | |
307 } | 281 } |
308 | 282 |
309 void MessageLoop::PostNonNestableDelayedTask( | 283 void MessageLoop::PostNonNestableDelayedTask( |
310 const tracked_objects::Location& from_here, | 284 const tracked_objects::Location& from_here, |
311 const Closure& task, | 285 const Closure& task, |
312 TimeDelta delay) { | 286 TimeDelta delay) { |
313 DCHECK(!task.is_null()) << from_here.ToString(); | 287 DCHECK(!task.is_null()) << from_here.ToString(); |
314 PendingTask pending_task( | 288 incoming_task_queue_->AddToIncomingQueue(from_here, task, delay, false); |
315 from_here, task, CalculateDelayedRuntime(delay), false); | |
316 AddToIncomingQueue(&pending_task, false); | |
317 } | 289 } |
318 | 290 |
319 void MessageLoop::Run() { | 291 void MessageLoop::Run() { |
320 RunLoop run_loop; | 292 RunLoop run_loop; |
321 run_loop.Run(); | 293 run_loop.Run(); |
322 } | 294 } |
323 | 295 |
324 void MessageLoop::RunUntilIdle() { | 296 void MessageLoop::RunUntilIdle() { |
325 RunLoop run_loop; | 297 RunLoop run_loop; |
326 run_loop.RunUntilIdle(); | 298 run_loop.RunUntilIdle(); |
(...skipping 29 matching lines...) Expand all Loading... |
356 Closure MessageLoop::QuitWhenIdleClosure() { | 328 Closure MessageLoop::QuitWhenIdleClosure() { |
357 return Bind(&QuitCurrentWhenIdle); | 329 return Bind(&QuitCurrentWhenIdle); |
358 } | 330 } |
359 | 331 |
360 void MessageLoop::SetNestableTasksAllowed(bool allowed) { | 332 void MessageLoop::SetNestableTasksAllowed(bool allowed) { |
361 if (nestable_tasks_allowed_ != allowed) { | 333 if (nestable_tasks_allowed_ != allowed) { |
362 nestable_tasks_allowed_ = allowed; | 334 nestable_tasks_allowed_ = allowed; |
363 if (!nestable_tasks_allowed_) | 335 if (!nestable_tasks_allowed_) |
364 return; | 336 return; |
365 // Start the native pump if we are not already pumping. | 337 // Start the native pump if we are not already pumping. |
366 pump_->ScheduleWork(); | 338 WakeUpPump(); |
367 } | 339 } |
368 } | 340 } |
369 | 341 |
370 bool MessageLoop::NestableTasksAllowed() const { | 342 bool MessageLoop::NestableTasksAllowed() const { |
371 return nestable_tasks_allowed_; | 343 return nestable_tasks_allowed_; |
372 } | 344 } |
373 | 345 |
374 bool MessageLoop::IsNested() { | 346 bool MessageLoop::IsNested() { |
375 return run_loop_->run_depth_ > 1; | 347 return run_loop_->run_depth_ > 1; |
376 } | 348 } |
377 | 349 |
378 void MessageLoop::AddTaskObserver(TaskObserver* task_observer) { | 350 void MessageLoop::AddTaskObserver(TaskObserver* task_observer) { |
379 DCHECK_EQ(this, current()); | 351 DCHECK_EQ(this, current()); |
380 task_observers_.AddObserver(task_observer); | 352 task_observers_.AddObserver(task_observer); |
381 } | 353 } |
382 | 354 |
383 void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) { | 355 void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) { |
384 DCHECK_EQ(this, current()); | 356 DCHECK_EQ(this, current()); |
385 task_observers_.RemoveObserver(task_observer); | 357 task_observers_.RemoveObserver(task_observer); |
386 } | 358 } |
387 | 359 |
388 void MessageLoop::AssertIdle() const { | |
389 // We only check |incoming_queue_|, since we don't want to lock |work_queue_|. | |
390 AutoLock lock(incoming_queue_lock_); | |
391 DCHECK(incoming_queue_.empty()); | |
392 } | |
393 | |
394 bool MessageLoop::is_running() const { | 360 bool MessageLoop::is_running() const { |
395 DCHECK_EQ(this, current()); | 361 DCHECK_EQ(this, current()); |
396 return run_loop_ != NULL; | 362 return run_loop_ != NULL; |
397 } | 363 } |
398 | 364 |
| 365 bool MessageLoop::IsHighResolutionTimerEnabledForTest() { |
| 366 return incoming_task_queue_->IsHighResolutionTimerEnabledForTest(); |
| 367 } |
| 368 |
| 369 bool MessageLoop::IsIdleForTest() { |
| 370 // We only check the imcoming queue|, since we don't want to lock the work |
| 371 // queue. |
| 372 return incoming_task_queue_->IsIdleForTest(); |
| 373 } |
| 374 |
| 375 void MessageLoop::LockWaitUnLockForTest(WaitableEvent* caller_wait, |
| 376 WaitableEvent* caller_signal) { |
| 377 incoming_task_queue_->LockWaitUnLockForTest(caller_wait, caller_signal); |
| 378 } |
| 379 |
399 //------------------------------------------------------------------------------ | 380 //------------------------------------------------------------------------------ |
400 | 381 |
401 // Runs the loop in two different SEH modes: | 382 // Runs the loop in two different SEH modes: |
402 // enable_SEH_restoration_ = false : any unhandled exception goes to the last | 383 // enable_SEH_restoration_ = false : any unhandled exception goes to the last |
403 // one that calls SetUnhandledExceptionFilter(). | 384 // one that calls SetUnhandledExceptionFilter(). |
404 // enable_SEH_restoration_ = true : any unhandled exception goes to the filter | 385 // enable_SEH_restoration_ = true : any unhandled exception goes to the filter |
405 // that was existed before the loop was run. | 386 // that was existed before the loop was run. |
406 void MessageLoop::RunHandler() { | 387 void MessageLoop::RunHandler() { |
407 #if defined(OS_WIN) | 388 #if defined(OS_WIN) |
408 if (exception_restoration_) { | 389 if (exception_restoration_) { |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
453 | 434 |
454 RunTask(pending_task); | 435 RunTask(pending_task); |
455 return true; | 436 return true; |
456 } | 437 } |
457 | 438 |
458 void MessageLoop::RunTask(const PendingTask& pending_task) { | 439 void MessageLoop::RunTask(const PendingTask& pending_task) { |
459 tracked_objects::TrackedTime start_time = | 440 tracked_objects::TrackedTime start_time = |
460 tracked_objects::ThreadData::NowForStartOfRun(pending_task.birth_tally); | 441 tracked_objects::ThreadData::NowForStartOfRun(pending_task.birth_tally); |
461 | 442 |
462 TRACE_EVENT_FLOW_END1("task", "MessageLoop::PostTask", | 443 TRACE_EVENT_FLOW_END1("task", "MessageLoop::PostTask", |
463 TRACE_ID_MANGLE(GetTaskTraceID(pending_task, this)), | 444 TRACE_ID_MANGLE(GetTaskTraceID(pending_task)), |
464 "queue_duration", | 445 "queue_duration", |
465 (start_time - pending_task.EffectiveTimePosted()).InMilliseconds()); | 446 (start_time - pending_task.EffectiveTimePosted()).InMilliseconds()); |
466 TRACE_EVENT2("task", "MessageLoop::RunTask", | 447 TRACE_EVENT2("task", "MessageLoop::RunTask", |
467 "src_file", pending_task.posted_from.file_name(), | 448 "src_file", pending_task.posted_from.file_name(), |
468 "src_func", pending_task.posted_from.function_name()); | 449 "src_func", pending_task.posted_from.function_name()); |
469 | 450 |
470 DCHECK(nestable_tasks_allowed_); | 451 DCHECK(nestable_tasks_allowed_); |
471 // Execute the task and assume the worst: It is probably not reentrant. | 452 // Execute the task and assume the worst: It is probably not reentrant. |
472 nestable_tasks_allowed_ = false; | 453 nestable_tasks_allowed_ = false; |
473 | 454 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
506 // and the task isn't nestable. | 487 // and the task isn't nestable. |
507 deferred_non_nestable_work_queue_.push(pending_task); | 488 deferred_non_nestable_work_queue_.push(pending_task); |
508 return false; | 489 return false; |
509 } | 490 } |
510 | 491 |
511 void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) { | 492 void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) { |
512 // Move to the delayed work queue. | 493 // Move to the delayed work queue. |
513 delayed_work_queue_.push(pending_task); | 494 delayed_work_queue_.push(pending_task); |
514 } | 495 } |
515 | 496 |
516 void MessageLoop::ReloadWorkQueue() { | |
517 // We can improve performance of our loading tasks from incoming_queue_ to | |
518 // work_queue_ by waiting until the last minute (work_queue_ is empty) to | |
519 // load. That reduces the number of locks-per-task significantly when our | |
520 // queues get large. | |
521 if (!work_queue_.empty()) | |
522 return; // Wait till we *really* need to lock and load. | |
523 | |
524 // Acquire all we can from the inter-thread queue with one lock acquisition. | |
525 { | |
526 AutoLock lock(incoming_queue_lock_); | |
527 if (incoming_queue_.empty()) | |
528 return; | |
529 incoming_queue_.Swap(&work_queue_); // Constant time | |
530 DCHECK(incoming_queue_.empty()); | |
531 } | |
532 } | |
533 | |
534 bool MessageLoop::DeletePendingTasks() { | 497 bool MessageLoop::DeletePendingTasks() { |
535 bool did_work = !work_queue_.empty(); | 498 bool did_work = !work_queue_.empty(); |
536 while (!work_queue_.empty()) { | 499 while (!work_queue_.empty()) { |
537 PendingTask pending_task = work_queue_.front(); | 500 PendingTask pending_task = work_queue_.front(); |
538 work_queue_.pop(); | 501 work_queue_.pop(); |
539 if (!pending_task.delayed_run_time.is_null()) { | 502 if (!pending_task.delayed_run_time.is_null()) { |
540 // We want to delete delayed tasks in the same order in which they would | 503 // We want to delete delayed tasks in the same order in which they would |
541 // normally be deleted in case of any funny dependencies between delayed | 504 // normally be deleted in case of any funny dependencies between delayed |
542 // tasks. | 505 // tasks. |
543 AddToDelayedWorkQueue(pending_task); | 506 AddToDelayedWorkQueue(pending_task); |
544 } | 507 } |
545 } | 508 } |
546 did_work |= !deferred_non_nestable_work_queue_.empty(); | 509 did_work |= !deferred_non_nestable_work_queue_.empty(); |
547 while (!deferred_non_nestable_work_queue_.empty()) { | 510 while (!deferred_non_nestable_work_queue_.empty()) { |
548 deferred_non_nestable_work_queue_.pop(); | 511 deferred_non_nestable_work_queue_.pop(); |
549 } | 512 } |
550 did_work |= !delayed_work_queue_.empty(); | 513 did_work |= !delayed_work_queue_.empty(); |
551 | 514 |
552 // Historically, we always delete the task regardless of valgrind status. It's | 515 // Historically, we always delete the task regardless of valgrind status. It's |
553 // not completely clear why we want to leak them in the loops above. This | 516 // not completely clear why we want to leak them in the loops above. This |
554 // code is replicating legacy behavior, and should not be considered | 517 // code is replicating legacy behavior, and should not be considered |
555 // absolutely "correct" behavior. See TODO above about deleting all tasks | 518 // absolutely "correct" behavior. See TODO above about deleting all tasks |
556 // when it's safe. | 519 // when it's safe. |
557 while (!delayed_work_queue_.empty()) { | 520 while (!delayed_work_queue_.empty()) { |
558 delayed_work_queue_.pop(); | 521 delayed_work_queue_.pop(); |
559 } | 522 } |
560 return did_work; | 523 return did_work; |
561 } | 524 } |
562 | 525 |
563 TimeTicks MessageLoop::CalculateDelayedRuntime(TimeDelta delay) { | 526 uint64 MessageLoop::GetTaskTraceID(const PendingTask& task) { |
564 TimeTicks delayed_run_time; | 527 return (static_cast<uint64>(task.sequence_num) << 32) | |
565 if (delay > TimeDelta()) { | 528 static_cast<uint64>(reinterpret_cast<intptr_t>(this)); |
566 delayed_run_time = TimeTicks::Now() + delay; | |
567 | |
568 #if defined(OS_WIN) | |
569 if (high_resolution_timer_expiration_.is_null()) { | |
570 // Windows timers are granular to 15.6ms. If we only set high-res | |
571 // timers for those under 15.6ms, then a 18ms timer ticks at ~32ms, | |
572 // which as a percentage is pretty inaccurate. So enable high | |
573 // res timers for any timer which is within 2x of the granularity. | |
574 // This is a tradeoff between accuracy and power management. | |
575 bool needs_high_res_timers = delay.InMilliseconds() < | |
576 (2 * Time::kMinLowResolutionThresholdMs); | |
577 if (needs_high_res_timers) { | |
578 if (Time::ActivateHighResolutionTimer(true)) { | |
579 high_resolution_timer_expiration_ = TimeTicks::Now() + | |
580 TimeDelta::FromMilliseconds(kHighResolutionTimerModeLeaseTimeMs); | |
581 } | |
582 } | |
583 } | |
584 #endif | |
585 } else { | |
586 DCHECK_EQ(delay.InMilliseconds(), 0) << "delay should not be negative"; | |
587 } | |
588 | |
589 #if defined(OS_WIN) | |
590 if (!high_resolution_timer_expiration_.is_null()) { | |
591 if (TimeTicks::Now() > high_resolution_timer_expiration_) { | |
592 Time::ActivateHighResolutionTimer(false); | |
593 high_resolution_timer_expiration_ = TimeTicks(); | |
594 } | |
595 } | |
596 #endif | |
597 | |
598 return delayed_run_time; | |
599 } | 529 } |
600 | 530 |
601 // Possibly called on a background thread! | 531 void MessageLoop::ReloadWorkQueue() { |
602 bool MessageLoop::AddToIncomingQueue(PendingTask* pending_task, | 532 // We can improve performance of our loading tasks from the incoming queue to |
603 bool use_try_lock) { | 533 // |*work_queue| by waiting until the last minute (|*work_queue| is empty) to |
604 // Warning: Don't try to short-circuit, and handle this thread's tasks more | 534 // load. That reduces the number of locks-per-task significantly when our |
605 // directly, as it could starve handling of foreign threads. Put every task | 535 // queues get large. |
606 // into this queue. | 536 if (work_queue_.empty()) |
| 537 incoming_task_queue_->ReloadWorkQueue(&work_queue_); |
| 538 } |
607 | 539 |
608 scoped_refptr<MessagePump> pump; | 540 void MessageLoop::WakeUpPump() { |
609 { | 541 pump_->ScheduleWork(); |
610 if (use_try_lock) { | |
611 if (!incoming_queue_lock_.Try()) { | |
612 pending_task->task.Reset(); | |
613 return false; | |
614 } | |
615 } else { | |
616 incoming_queue_lock_.Acquire(); | |
617 } | |
618 AutoLock locked(incoming_queue_lock_, AutoLock::AlreadyAcquired()); | |
619 // Initialize the sequence number. The sequence number is used for delayed | |
620 // tasks (to faciliate FIFO sorting when two tasks have the same | |
621 // delayed_run_time value) and for identifying the task in about:tracing. | |
622 pending_task->sequence_num = next_sequence_num_++; | |
623 | |
624 TRACE_EVENT_FLOW_BEGIN0("task", "MessageLoop::PostTask", | |
625 TRACE_ID_MANGLE(GetTaskTraceID(*pending_task, this))); | |
626 | |
627 bool was_empty = incoming_queue_.empty(); | |
628 incoming_queue_.push(*pending_task); | |
629 pending_task->task.Reset(); | |
630 if (!was_empty) | |
631 return true; // Someone else should have started the sub-pump. | |
632 | |
633 pump = pump_; | |
634 } | |
635 // Since the incoming_queue_ may contain a task that destroys this message | |
636 // loop, we cannot exit incoming_queue_lock_ until we are done with |this|. | |
637 // We use a stack-based reference to the message pump so that we can call | |
638 // ScheduleWork outside of incoming_queue_lock_. | |
639 | |
640 pump->ScheduleWork(); | |
641 return true; | |
642 } | 542 } |
643 | 543 |
644 //------------------------------------------------------------------------------ | 544 //------------------------------------------------------------------------------ |
645 // Method and data for histogramming events and actions taken by each instance | 545 // Method and data for histogramming events and actions taken by each instance |
646 // on each thread. | 546 // on each thread. |
647 | 547 |
648 void MessageLoop::StartHistogrammer() { | 548 void MessageLoop::StartHistogrammer() { |
649 #if !defined(OS_NACL) // NaCl build has no metrics code. | 549 #if !defined(OS_NACL) // NaCl build has no metrics code. |
650 if (enable_histogrammer_ && !message_histogram_ | 550 if (enable_histogrammer_ && !message_histogram_ |
651 && StatisticsRecorder::IsActive()) { | 551 && StatisticsRecorder::IsActive()) { |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
828 fd, | 728 fd, |
829 persistent, | 729 persistent, |
830 mode, | 730 mode, |
831 controller, | 731 controller, |
832 delegate); | 732 delegate); |
833 } | 733 } |
834 | 734 |
835 #endif | 735 #endif |
836 | 736 |
837 } // namespace base | 737 } // namespace base |
OLD | NEW |