Index: base/message_loop/incoming_task_queue.cc |
diff --git a/base/message_loop/incoming_task_queue.cc b/base/message_loop/incoming_task_queue.cc |
index ebecc1ba54ce35df2cfef606eca13c8ed4062569..2020cd4da61da1e0d1e36829392e225469e8ed07 100644 |
--- a/base/message_loop/incoming_task_queue.cc |
+++ b/base/message_loop/incoming_task_queue.cc |
@@ -37,6 +37,16 @@ bool AlwaysNotifyPump(MessageLoop::Type type) { |
#endif |
} |
+// Calculates the time at which a PendingTask should run. |
+TimeTicks CalculateDelayedRuntime(TimeDelta delay) { |
+ TimeTicks delayed_run_time; |
+ if (delay > TimeDelta()) |
+ delayed_run_time = TimeTicks::Now() + delay; |
+ else |
+ DCHECK_EQ(delay.InMilliseconds(), 0) << "delay should not be negative"; |
+ return delayed_run_time; |
+} |
+ |
} // namespace |
IncomingTaskQueue::IncomingTaskQueue(MessageLoop* message_loop) |
@@ -58,7 +68,6 @@ bool IncomingTaskQueue::AddToIncomingQueue( |
<< "Requesting super-long task delay period of " << delay.InSeconds() |
<< " seconds from here: " << from_here.ToString(); |
- AutoLock locked(incoming_queue_lock_); |
PendingTask pending_task( |
from_here, task, CalculateDelayedRuntime(delay), nestable); |
#if defined(OS_WIN) |
@@ -68,7 +77,6 @@ bool IncomingTaskQueue::AddToIncomingQueue( |
// resolution on Windows is between 10 and 15ms. |
if (delay > TimeDelta() && |
delay.InMilliseconds() < (2 * Time::kMinLowResolutionThresholdMs)) { |
- ++high_res_task_count_; |
pending_task.is_high_res = true; |
} |
#endif |
@@ -106,17 +114,24 @@ int IncomingTaskQueue::ReloadWorkQueue(TaskQueue* work_queue) { |
} |
void IncomingTaskQueue::WillDestroyCurrentMessageLoop() { |
- AutoLock lock(incoming_queue_lock_); |
+ AutoWriteLock lock(message_loop_lock_); |
message_loop_ = NULL; |
} |
void IncomingTaskQueue::StartScheduling() { |
- AutoLock lock(incoming_queue_lock_); |
- DCHECK(!is_ready_for_scheduling_); |
- DCHECK(!message_loop_scheduled_); |
- is_ready_for_scheduling_ = true; |
- if (!incoming_queue_.empty()) |
- ScheduleWork(); |
+ bool schedule_work; |
+ { |
+ AutoLock lock(incoming_queue_lock_); |
+ DCHECK(!is_ready_for_scheduling_); |
+ DCHECK(!message_loop_scheduled_); |
+ is_ready_for_scheduling_ = true; |
+ schedule_work = !incoming_queue_.empty(); |
+ } |
+ if (schedule_work) { |
+ AutoReadLock lock(message_loop_lock_); |
danakj
2016/05/19 22:29:37
nit: name "hold_message_loop"
Anand Mistry (off Chromium)
2016/05/20 04:45:38
Removed as per comment below.
|
+ DCHECK(message_loop_); |
danakj
2016/05/19 22:29:37
This method is called from the MessageLoop which i
Anand Mistry (off Chromium)
2016/05/20 04:45:38
Done. Thinking about it a bit more, calling Schedu
|
+ message_loop_->ScheduleWork(); |
danakj
2016/05/19 22:29:37
How come this doesn't set message_loop_scheduled_
Anand Mistry (off Chromium)
2016/05/20 04:45:38
It's not necessary. The worst that can happen is a
|
+ } |
} |
IncomingTaskQueue::~IncomingTaskQueue() { |
@@ -124,58 +139,60 @@ IncomingTaskQueue::~IncomingTaskQueue() { |
DCHECK(!message_loop_); |
} |
-TimeTicks IncomingTaskQueue::CalculateDelayedRuntime(TimeDelta delay) { |
- TimeTicks delayed_run_time; |
- if (delay > TimeDelta()) |
- delayed_run_time = TimeTicks::Now() + delay; |
- else |
- DCHECK_EQ(delay.InMilliseconds(), 0) << "delay should not be negative"; |
- return delayed_run_time; |
-} |
- |
bool IncomingTaskQueue::PostPendingTask(PendingTask* pending_task) { |
// Warning: Don't try to short-circuit, and handle this thread's tasks more |
// directly, as it could starve handling of foreign threads. Put every task |
// into this queue. |
- // This should only be called while the lock is taken. |
- incoming_queue_lock_.AssertAcquired(); |
+ // Ensures |message_loop_| isn't null'd while running. |
danakj
2016/05/19 22:29:37
"nulled". tho it's more like ensures the message l
Anand Mistry (off Chromium)
2016/05/20 04:45:37
yeha, changed to destroyed. The nulling happens in
|
+ AutoReadLock ml_lock(message_loop_lock_); |
danakj
2016/05/19 22:29:37
nit: name this variable "hold_message_loop"
Anand Mistry (off Chromium)
2016/05/20 04:45:38
Done.
|
if (!message_loop_) { |
pending_task->task.Reset(); |
return false; |
} |
- // Initialize the sequence number. The sequence number is used for delayed |
- // tasks (to facilitate FIFO sorting when two tasks have the same |
- // delayed_run_time value) and for identifying the task in about:tracing. |
- pending_task->sequence_num = next_sequence_num_++; |
+ bool schedule_work = false; |
+ { |
+ AutoLock locked(incoming_queue_lock_); |
danakj
2016/05/19 22:29:37
nit: name this variable "hold"
Anand Mistry (off Chromium)
2016/05/20 04:45:37
Done.
|
- message_loop_->task_annotator()->DidQueueTask("MessageLoop::PostTask", |
- *pending_task); |
- |
- bool was_empty = incoming_queue_.empty(); |
- incoming_queue_.push(*pending_task); |
- pending_task->task.Reset(); |
+#if defined(OS_WIN) |
+ if (pending_task->is_high_res) |
+ ++high_res_task_count_; |
+#endif |
- if (is_ready_for_scheduling_ && |
- (always_schedule_work_ || (!message_loop_scheduled_ && was_empty))) { |
- ScheduleWork(); |
+ // Initialize the sequence number. The sequence number is used for delayed |
+ // tasks (to facilitate FIFO sorting when two tasks have the same |
+ // delayed_run_time value) and for identifying the task in about:tracing. |
+ pending_task->sequence_num = next_sequence_num_++; |
+ |
+ message_loop_->task_annotator()->DidQueueTask("MessageLoop::PostTask", |
+ *pending_task); |
+ |
+ bool was_empty = incoming_queue_.empty(); |
+ incoming_queue_.push(std::move(*pending_task)); |
+ |
+ if (is_ready_for_scheduling_ && |
+ (always_schedule_work_ || (!message_loop_scheduled_ && was_empty))) { |
+ schedule_work = true; |
+ // After we've scheduled the message loop, we do not need to do so again |
+ // until we know it has processed all of the work in our queue and is |
+ // waiting for more work again. The message loop will always attempt to |
+ // reload from the incoming queue before waiting again so we clear this |
+ // flag in ReloadWorkQueue(). |
+ message_loop_scheduled_ = true; |
+ } |
} |
- return true; |
-} |
+ // Wake up the message loop and schedule work. This is done outside |
+ // |incoming_queue_lock_| because signalling the message loop may cause this |
+ // thread to be switched. If |incoming_queue_lock_| is held, any other thread |
+ // that wants to post a task will be blocked until this thread switches back |
+ // in and releases |incoming_queue_lock_|. |
+ if (schedule_work) |
+ message_loop_->ScheduleWork(); |
-void IncomingTaskQueue::ScheduleWork() { |
- DCHECK(is_ready_for_scheduling_); |
- // Wake up the message loop. |
- message_loop_->ScheduleWork(); |
- // After we've scheduled the message loop, we do not need to do so again |
- // until we know it has processed all of the work in our queue and is |
- // waiting for more work again. The message loop will always attempt to |
- // reload from the incoming queue before waiting again so we clear this flag |
- // in ReloadWorkQueue(). |
- message_loop_scheduled_ = true; |
+ return true; |
} |
} // namespace internal |