1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef NET_DNS_SERIAL_WORKER_H_
#define NET_DNS_SERIAL_WORKER_H_
#include <memory>
#include "base/compiler_specific.h"
#include "base/functional/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/task/task_traits.h"
#include "base/timer/timer.h"
#include "net/base/backoff_entry.h"
#include "net/base/net_export.h"
namespace net {
// `SerialWorker` executes a job on `ThreadPool` serially -- **one at a time**.
// On `WorkNow()`, a `WorkItem` is created using `CreateWorkItem()` and sent to
// the `ThreadPool`. There, a call to `DoWork()` is made. On completion of work,
// `OnWorkFinished()` is called on the origin thread (if the `SerialWorker` is
// still alive), passing back the `WorkItem` to allow retrieving any results or
// passed objects. If `WorkNow()` is called (1 or more times) while a `WorkItem`
// is already under way, after completion of the work and before any call is
// made to `OnWorkFinished()` the same `WorkItem` will be passed back to the
// `ThreadPool`, and `DoWork()` will be called once more.
//
// If |OnWorkFinished| returns a failure and |max_number_of_retries|
// is non-zero, retries will be scheduled according to the |backoff_policy|.
// A default backoff policy is used if one is not provided.
//
// This behavior is designed for updating a result after some trigger, for
// example reading a file once FilePathWatcher indicates it changed.
//
// Derived classes should store results of work in the `WorkItem` and retrieve
// results from it when passed back to `OnWorkFinished()`. The `SerialWorker` is
// guaranteed to only run one `WorkItem` at a time, always passing it back to
// `OnWorkFinished()` before calling `CreateWorkItem()` again. Therefore, a
// derived class may safely pass objects between `WorkItem`s, or even reuse the
// same `WorkItem`, to allow storing helper objects directly in the `WorkItem`.
// However, it is not guaranteed that the `SerialWorker` will remain alive while
// the `WorkItem` runs. Therefore, the `WorkItem` should never access any memory
// owned by the `SerialWorker` or derived class.
class NET_EXPORT_PRIVATE SerialWorker {
public:
// A work item that will be passed to and run on the `ThreadPool` (potentially
// multiple times if the `SerialWorker` needs to run again immediately) and
// then passed back to the origin thread on completion. Expected usage is to
// store any parameters, results, and helper objects in the `WorkItem` and
// read results from it when passed back to the origin thread.
//
// `SerialWorker` calls `FollowupWork()` *on the origin thread* after calling
// `DoWork()` on the `ThreadPool` to asynchronously handle any work that must
// be part of the serialization but that cannot run on a worker thread.
class NET_EXPORT_PRIVATE WorkItem {
public:
virtual ~WorkItem() = default;
virtual void DoWork() = 0;
virtual void FollowupWork(base::OnceClosure closure);
};
explicit SerialWorker(
int max_number_of_retries = 0,
const net::BackoffEntry::Policy* backoff_policy = nullptr);
SerialWorker(const SerialWorker&) = delete;
SerialWorker& operator=(const SerialWorker&) = delete;
// Unless already scheduled, post |DoWork| to ThreadPool.
// Made virtual to allow mocking.
virtual void WorkNow();
// Stop scheduling jobs.
void Cancel();
bool IsCancelled() const { return state_ == State::kCancelled; }
// Allows tests to inspect the current backoff/retry state.
const BackoffEntry& GetBackoffEntryForTesting() const;
const base::OneShotTimer& GetRetryTimerForTesting() const;
protected:
// protected to allow sub-classing, but prevent deleting
virtual ~SerialWorker();
// Create a new WorkItem to be passed to and run on the ThreadPool.
virtual std::unique_ptr<WorkItem> CreateWorkItem() = 0;
// Executed on origin thread after `WorkItem` completes.
// Must return true on success.
virtual bool OnWorkFinished(std::unique_ptr<WorkItem> work_item) = 0;
// Returns the failure count for this job.
int GetFailureCount() const;
base::WeakPtr<SerialWorker> AsWeakPtr();
// Used to verify that the constructor, WorkNow(), Cancel() and
// OnWorkJobFinished() are called on the same sequence.
SEQUENCE_CHECKER(sequence_checker_);
private:
enum class State {
kCancelled = -1,
kIdle = 0,
kWorking, // |DoWorkJob| posted to ThreadPool, until |OnWorkJobFinished|
kPending, // |WorkNow| while WORKING, must re-do work
};
void WorkNowInternal();
// Called on the origin thread after `WorkItem::DoWork()` completes.
void OnDoWorkFinished(std::unique_ptr<WorkItem> work_item);
// Called on the origin thread after `WorkItem::FollowupWork()` completes.
void OnFollowupWorkFinished(std::unique_ptr<WorkItem> work_item);
void RerunWork(std::unique_ptr<WorkItem> work_item);
State state_ = State::kIdle;
// Max retries and backoff entry to control timing.
const int max_number_of_retries_;
BackoffEntry backoff_entry_;
base::OneShotTimer retry_timer_;
base::WeakPtrFactory<SerialWorker> weak_factory_{this};
};
} // namespace net
#endif // NET_DNS_SERIAL_WORKER_H_
|