Chromium Code Reviews| Index: base/threading/sequenced_worker_pool.cc |
| diff --git a/base/threading/sequenced_worker_pool.cc b/base/threading/sequenced_worker_pool.cc |
| index 61cef6adf6b01c360299b2940f7c473ef3684ac8..e72b533acb22569715cddedd5e4e64ab71880f96 100644 |
| --- a/base/threading/sequenced_worker_pool.cc |
| +++ b/base/threading/sequenced_worker_pool.cc |
| @@ -381,6 +381,13 @@ class SequencedWorkerPool::Inner { |
| CLEANUP_DONE, |
| }; |
| + // Clears ScheduledTasks in |delete_these_outside_lock| while ensuring that |
| + // |this_worker| has the desired task info context for ~ScheduledTask() to |
| + // allow RunsTasksOnCurrentThread() like checks. |
| + void DeleteTheseOutsideLockHelper( |
|
vmpstr
2016/12/03 01:14:04
WDYT about just "DeleteWithoutLock" with "tasks_to
gab
2016/12/23 20:22:10
Done on https://codereview.chromium.org/2581213002
|
| + std::vector<SequencedTask>* delete_these_outside_lock, |
| + Worker* this_worker); |
| + |
| // Helper used by PostTask() to complete the work when redirection is on. |
| // Returns true if the task may run at some point in the future and false if |
| // it will definitely not run. |
| @@ -418,7 +425,7 @@ class SequencedWorkerPool::Inner { |
| // See the implementation for a more detailed description. |
| GetWorkStatus GetWork(SequencedTask* task, |
| TimeDelta* wait_time, |
| - std::vector<Closure>* delete_these_outside_lock); |
| + std::vector<SequencedTask>* delete_these_outside_lock); |
| void HandleCleanup(); |
| @@ -977,7 +984,7 @@ void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) { |
| // See GetWork for what delete_these_outside_lock is doing. |
| SequencedTask task; |
| TimeDelta wait_time; |
| - std::vector<Closure> delete_these_outside_lock; |
| + std::vector<SequencedTask> delete_these_outside_lock; |
| GetWorkStatus status = |
| GetWork(&task, &wait_time, &delete_these_outside_lock); |
| if (status == GET_WORK_FOUND) { |
| @@ -994,7 +1001,7 @@ void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) { |
| // already get a signal for each new task, but it doesn't |
| // hurt.) |
| SignalHasWork(); |
| - delete_these_outside_lock.clear(); |
| + DeleteTheseOutsideLockHelper(&delete_these_outside_lock, this_worker); |
| // Complete thread creation outside the lock if necessary. |
| if (new_thread_id) |
| @@ -1025,7 +1032,8 @@ void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) { |
| switch (status) { |
| case GET_WORK_WAIT: { |
| AutoUnlock unlock(lock_); |
| - delete_these_outside_lock.clear(); |
| + DeleteTheseOutsideLockHelper(&delete_these_outside_lock, |
| + this_worker); |
| } |
| break; |
| case GET_WORK_NOT_FOUND: |
| @@ -1047,7 +1055,7 @@ void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) { |
| // help this case. |
| if (shutdown_called_ && blocking_shutdown_pending_task_count_ == 0) { |
| AutoUnlock unlock(lock_); |
| - delete_these_outside_lock.clear(); |
| + DeleteTheseOutsideLockHelper(&delete_these_outside_lock, this_worker); |
| break; |
| } |
| @@ -1055,7 +1063,7 @@ void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) { |
| // deletion must happen outside of the lock. |
| if (delete_these_outside_lock.size()) { |
| AutoUnlock unlock(lock_); |
| - delete_these_outside_lock.clear(); |
| + DeleteTheseOutsideLockHelper(&delete_these_outside_lock, this_worker); |
| // Since the lock has been released, |status| may no longer be |
| // accurate. It might read GET_WORK_WAIT even if there are tasks |
| @@ -1078,6 +1086,9 @@ void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) { |
| } |
| waiting_thread_count_--; |
| } |
| + // |delete_these_outside_lock| should have been cleared via |
| + // DeleteTheseOutsideLockHelper() above already. |
| + DCHECK(delete_these_outside_lock.empty()); |
| } |
| } // Release lock_. |
| @@ -1089,6 +1100,19 @@ void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) { |
| can_shutdown_cv_.Signal(); |
| } |
| +void SequencedWorkerPool::Inner::DeleteTheseOutsideLockHelper( |
| + std::vector<SequencedTask>* delete_these_outside_lock, |
| + Worker* this_worker) { |
| + while (!delete_these_outside_lock->empty()) { |
| + const SequencedTask& deleted_task = delete_these_outside_lock->back(); |
| + this_worker->set_running_task_info( |
| + SequenceToken(deleted_task.sequence_token_id), |
| + deleted_task.shutdown_behavior); |
| + delete_these_outside_lock->pop_back(); |
| + this_worker->reset_running_task_info(); |
|
vmpstr
2016/12/03 01:14:04
Does this need to happen after every iteration, or
gab
2016/12/23 20:22:10
Done on https://codereview.chromium.org/2581213002
|
| + } |
| +} |
| + |
| void SequencedWorkerPool::Inner::HandleCleanup() { |
| DCHECK_EQ(AllPoolsState::USE_WORKER_POOL, g_all_pools_state); |
| @@ -1156,7 +1180,7 @@ int64_t SequencedWorkerPool::Inner::LockedGetNextSequenceTaskNumber() { |
| SequencedWorkerPool::Inner::GetWorkStatus SequencedWorkerPool::Inner::GetWork( |
| SequencedTask* task, |
| TimeDelta* wait_time, |
| - std::vector<Closure>* delete_these_outside_lock) { |
| + std::vector<SequencedTask>* delete_these_outside_lock) { |
| DCHECK_EQ(AllPoolsState::USE_WORKER_POOL, g_all_pools_state); |
| lock_.AssertAcquired(); |
| @@ -1202,18 +1226,17 @@ SequencedWorkerPool::Inner::GetWorkStatus SequencedWorkerPool::Inner::GetWork( |
| // shutdown. Delete it and get more work. |
| // |
| // Note that we do not want to delete unrunnable tasks. Deleting a task |
| - // can have side effects (like freeing some objects) and deleting a |
| - // task that's supposed to run after one that's currently running could |
| - // cause an obscure crash. |
| + // can have side effects (like freeing some objects) and deleting a task |
| + // that's supposed to run after one that's currently running could cause |
| + // an obscure crash. |
| // |
| // We really want to delete these tasks outside the lock in case the |
| - // closures are holding refs to objects that want to post work from |
| - // their destructorss (which would deadlock). The closures are |
| - // internally refcounted, so we just need to keep a copy of them alive |
| - // until the lock is exited. The calling code can just clear() the |
| - // vector they passed to us once the lock is exited to make this |
| - // happen. |
| - delete_these_outside_lock->push_back(i->task); |
| + // closures are holding refs to objects that want to post work from their |
| + // destructors (which would deadlock). The closures are internally |
| + // refcounted, so we just need to keep a copy of them alive until the lock |
| + // is exited. The calling code can just clear() the vector they passed to |
| + // us once the lock is exited to make this happen. |
| + delete_these_outside_lock->push_back(*i); |
| pending_tasks_.erase(i++); |
| continue; |
| } |
| @@ -1224,7 +1247,7 @@ SequencedWorkerPool::Inner::GetWorkStatus SequencedWorkerPool::Inner::GetWork( |
| status = GET_WORK_WAIT; |
| if (cleanup_state_ == CLEANUP_RUNNING) { |
| // Deferred tasks are deleted when cleaning up, see Inner::ThreadLoop. |
| - delete_these_outside_lock->push_back(i->task); |
| + delete_these_outside_lock->push_back(*i); |
| pending_tasks_.erase(i); |
| } |
| break; |