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
14SerialWorker::SerialWorker()
15  : message_loop_(base::MessageLoopProxy::current()),
16    state_(IDLE) {}
17
18SerialWorker::~SerialWorker() {}
19
20void SerialWorker::WorkNow() {
21  DCHECK(message_loop_->BelongsToCurrentThread());
22  switch (state_) {
23    case IDLE:
24      if (!base::WorkerPool::PostTask(FROM_HERE, base::Bind(
25          &SerialWorker::DoWorkJob, this), false)) {
26#if defined(OS_POSIX)
27        // See worker_pool_posix.cc.
28        NOTREACHED() << "WorkerPool::PostTask is not expected to fail on posix";
29#else
30        LOG(WARNING) << "Failed to WorkerPool::PostTask, will retry later";
31        const int kWorkerPoolRetryDelayMs = 100;
32        message_loop_->PostDelayedTask(
33            FROM_HERE,
34            base::Bind(&SerialWorker::RetryWork, this),
35            base::TimeDelta::FromMilliseconds(kWorkerPoolRetryDelayMs));
36        state_ = WAITING;
37        return;
38#endif
39      }
40      state_ = WORKING;
41      return;
42    case WORKING:
43      // Remember to re-read after |DoRead| finishes.
44      state_ = PENDING;
45      return;
46    case CANCELLED:
47    case PENDING:
48    case WAITING:
49      return;
50    default:
51      NOTREACHED() << "Unexpected state " << state_;
52  }
53}
54
55void SerialWorker::Cancel() {
56  DCHECK(message_loop_->BelongsToCurrentThread());
57  state_ = CANCELLED;
58}
59
60void SerialWorker::DoWorkJob() {
61  this->DoWork();
62  // If this fails, the loop is gone, so there is no point retrying.
63  message_loop_->PostTask(FROM_HERE, base::Bind(
64      &SerialWorker::OnWorkJobFinished, this));
65}
66
67void SerialWorker::OnWorkJobFinished() {
68  DCHECK(message_loop_->BelongsToCurrentThread());
69  switch (state_) {
70    case CANCELLED:
71      return;
72    case WORKING:
73      state_ = IDLE;
74      this->OnWorkFinished();
75      return;
76    case PENDING:
77      state_ = IDLE;
78      WorkNow();
79      return;
80    default:
81      NOTREACHED() << "Unexpected state " << state_;
82  }
83}
84
85void SerialWorker::RetryWork() {
86  DCHECK(message_loop_->BelongsToCurrentThread());
87  switch (state_) {
88    case CANCELLED:
89      return;
90    case WAITING:
91      state_ = IDLE;
92      WorkNow();
93      return;
94    default:
95      NOTREACHED() << "Unexpected state " << state_;
96  }
97}
98
99}  // namespace net
100
101