| Index: base/threading/sequenced_worker_pool.cc
|
| diff --git a/base/threading/sequenced_worker_pool.cc b/base/threading/sequenced_worker_pool.cc
|
| index 56bbb62dd09f58bb92f05340598a109e715c5aee..af22098effca47dbeb484d95244f1bd1a928819e 100644
|
| --- a/base/threading/sequenced_worker_pool.cc
|
| +++ b/base/threading/sequenced_worker_pool.cc
|
| @@ -383,6 +383,12 @@ class SequencedWorkerPool::Inner {
|
| CLEANUP_DONE,
|
| };
|
|
|
| + // Clears ScheduledTasks in |tasks_to_delete| while ensuring that
|
| + // |this_worker| has the desired task info context during ~ScheduledTask() to
|
| + // allow sequence-checking.
|
| + void DeleteWithoutLock(std::vector<SequencedTask>* tasks_to_delete,
|
| + 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.
|
| @@ -420,7 +426,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();
|
|
|
| @@ -983,7 +989,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) {
|
| @@ -1000,7 +1006,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();
|
| + DeleteWithoutLock(&delete_these_outside_lock, this_worker);
|
|
|
| // Complete thread creation outside the lock if necessary.
|
| if (new_thread_id)
|
| @@ -1031,7 +1037,7 @@ void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) {
|
| switch (status) {
|
| case GET_WORK_WAIT: {
|
| AutoUnlock unlock(lock_);
|
| - delete_these_outside_lock.clear();
|
| + DeleteWithoutLock(&delete_these_outside_lock, this_worker);
|
| }
|
| break;
|
| case GET_WORK_NOT_FOUND:
|
| @@ -1053,7 +1059,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();
|
| + DeleteWithoutLock(&delete_these_outside_lock, this_worker);
|
| break;
|
| }
|
|
|
| @@ -1061,7 +1067,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();
|
| + DeleteWithoutLock(&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
|
| @@ -1084,6 +1090,9 @@ void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) {
|
| }
|
| waiting_thread_count_--;
|
| }
|
| + // |delete_these_outside_lock| should have been cleared via
|
| + // DeleteWithoutLock() above already.
|
| + DCHECK(delete_these_outside_lock.empty());
|
| }
|
| } // Release lock_.
|
|
|
| @@ -1095,6 +1104,19 @@ void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) {
|
| can_shutdown_cv_.Signal();
|
| }
|
|
|
| +void SequencedWorkerPool::Inner::DeleteWithoutLock(
|
| + std::vector<SequencedTask>* tasks_to_delete,
|
| + Worker* this_worker) {
|
| + while (!tasks_to_delete->empty()) {
|
| + const SequencedTask& deleted_task = tasks_to_delete->back();
|
| + this_worker->set_running_task_info(
|
| + SequenceToken(deleted_task.sequence_token_id),
|
| + deleted_task.shutdown_behavior);
|
| + tasks_to_delete->pop_back();
|
| + }
|
| + this_worker->reset_running_task_info();
|
| +}
|
| +
|
| void SequencedWorkerPool::Inner::HandleCleanup() {
|
| DCHECK_EQ(AllPoolsState::USE_WORKER_POOL, g_all_pools_state);
|
|
|
| @@ -1162,7 +1184,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();
|
| @@ -1208,18 +1230,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;
|
| }
|
| @@ -1230,7 +1251,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;
|
|
|