1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/dns/serial_worker.h"
6
7#include "base/bind.h"
8#include "base/location.h"
9#include "base/message_loop/message_loop_proxy.h"
10#include "base/threading/worker_pool.h"
11
12namespace net {
13
14namespace {
15  // Delay between calls to WorkerPool::PostTask
16  const int kWorkerPoolRetryDelayMs = 100;
17}
18
19SerialWorker::SerialWorker()
20  : message_loop_(base::MessageLoopProxy::current()),
21    state_(IDLE) {}
22
23SerialWorker::~SerialWorker() {}
24
25void SerialWorker::WorkNow() {
26  DCHECK(message_loop_->BelongsToCurrentThread());
27  switch (state_) {
28    case IDLE:
29      if (!base::WorkerPool::PostTask(FROM_HERE, base::Bind(
30          &SerialWorker::DoWorkJob, this), false)) {
31#if defined(OS_POSIX)
32        // See worker_pool_posix.cc.
33        NOTREACHED() << "WorkerPool::PostTask is not expected to fail on posix";
34#else
35        LOG(WARNING) << "Failed to WorkerPool::PostTask, will retry later";
36        message_loop_->PostDelayedTask(
37            FROM_HERE,
38            base::Bind(&SerialWorker::RetryWork, this),
39            base::TimeDelta::FromMilliseconds(kWorkerPoolRetryDelayMs));
40        state_ = WAITING;
41        return;
42#endif
43      }
44      state_ = WORKING;
45      return;
46    case WORKING:
47      // Remember to re-read after |DoRead| finishes.
48      state_ = PENDING;
49      return;
50    case CANCELLED:
51    case PENDING:
52    case WAITING:
53      return;
54    default:
55      NOTREACHED() << "Unexpected state " << state_;
56  }
57}
58
59void SerialWorker::Cancel() {
60  DCHECK(message_loop_->BelongsToCurrentThread());
61  state_ = CANCELLED;
62}
63
64void SerialWorker::DoWorkJob() {
65  this->DoWork();
66  // If this fails, the loop is gone, so there is no point retrying.
67  message_loop_->PostTask(FROM_HERE, base::Bind(
68      &SerialWorker::OnWorkJobFinished, this));
69}
70
71void SerialWorker::OnWorkJobFinished() {
72  DCHECK(message_loop_->BelongsToCurrentThread());
73  switch (state_) {
74    case CANCELLED:
75      return;
76    case WORKING:
77      state_ = IDLE;
78      this->OnWorkFinished();
79      return;
80    case PENDING:
81      state_ = IDLE;
82      WorkNow();
83      return;
84    default:
85      NOTREACHED() << "Unexpected state " << state_;
86  }
87}
88
89void SerialWorker::RetryWork() {
90  DCHECK(message_loop_->BelongsToCurrentThread());
91  switch (state_) {
92    case CANCELLED:
93      return;
94    case WAITING:
95      state_ = IDLE;
96      WorkNow();
97      return;
98    default:
99      NOTREACHED() << "Unexpected state " << state_;
100  }
101}
102
103}  // namespace net
104
105