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