|  | // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "net/dns/serial_worker.h" | 
|  |  | 
|  | #include "base/bind.h" | 
|  | #include "base/location.h" | 
|  | #include "base/message_loop_proxy.h" | 
|  | #include "base/threading/worker_pool.h" | 
|  |  | 
|  | namespace net { | 
|  |  | 
|  | SerialWorker::SerialWorker() | 
|  | : message_loop_(base::MessageLoopProxy::current()), | 
|  | state_(IDLE) {} | 
|  |  | 
|  | SerialWorker::~SerialWorker() {} | 
|  |  | 
|  | void SerialWorker::WorkNow() { | 
|  | DCHECK(message_loop_->BelongsToCurrentThread()); | 
|  | switch (state_) { | 
|  | case IDLE: | 
|  | if (!base::WorkerPool::PostTask(FROM_HERE, base::Bind( | 
|  | &SerialWorker::DoWorkJob, this), false)) { | 
|  | #if defined(OS_POSIX) | 
|  | // See worker_pool_posix.cc. | 
|  | NOTREACHED() << "WorkerPool::PostTask is not expected to fail on posix"; | 
|  | #else | 
|  | LOG(WARNING) << "Failed to WorkerPool::PostTask, will retry later"; | 
|  | const int kWorkerPoolRetryDelayMs = 100; | 
|  | message_loop_->PostDelayedTask( | 
|  | FROM_HERE, | 
|  | base::Bind(&SerialWorker::RetryWork, this), | 
|  | base::TimeDelta::FromMilliseconds(kWorkerPoolRetryDelayMs)); | 
|  | state_ = WAITING; | 
|  | return; | 
|  | #endif | 
|  | } | 
|  | state_ = WORKING; | 
|  | return; | 
|  | case WORKING: | 
|  | // Remember to re-read after |DoRead| finishes. | 
|  | state_ = PENDING; | 
|  | return; | 
|  | case CANCELLED: | 
|  | case PENDING: | 
|  | case WAITING: | 
|  | return; | 
|  | default: | 
|  | NOTREACHED() << "Unexpected state " << state_; | 
|  | } | 
|  | } | 
|  |  | 
|  | void SerialWorker::Cancel() { | 
|  | DCHECK(message_loop_->BelongsToCurrentThread()); | 
|  | state_ = CANCELLED; | 
|  | } | 
|  |  | 
|  | void SerialWorker::DoWorkJob() { | 
|  | this->DoWork(); | 
|  | // If this fails, the loop is gone, so there is no point retrying. | 
|  | message_loop_->PostTask(FROM_HERE, base::Bind( | 
|  | &SerialWorker::OnWorkJobFinished, this)); | 
|  | } | 
|  |  | 
|  | void SerialWorker::OnWorkJobFinished() { | 
|  | DCHECK(message_loop_->BelongsToCurrentThread()); | 
|  | switch (state_) { | 
|  | case CANCELLED: | 
|  | return; | 
|  | case WORKING: | 
|  | state_ = IDLE; | 
|  | this->OnWorkFinished(); | 
|  | return; | 
|  | case PENDING: | 
|  | state_ = IDLE; | 
|  | WorkNow(); | 
|  | return; | 
|  | default: | 
|  | NOTREACHED() << "Unexpected state " << state_; | 
|  | } | 
|  | } | 
|  |  | 
|  | void SerialWorker::RetryWork() { | 
|  | DCHECK(message_loop_->BelongsToCurrentThread()); | 
|  | switch (state_) { | 
|  | case CANCELLED: | 
|  | return; | 
|  | case WAITING: | 
|  | state_ = IDLE; | 
|  | WorkNow(); | 
|  | return; | 
|  | default: | 
|  | NOTREACHED() << "Unexpected state " << state_; | 
|  | } | 
|  | } | 
|  |  | 
|  | }  // namespace net | 
|  |  |