xref: /aosp_15_r20/external/cronet/net/base/prioritized_dispatcher.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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_BASE_PRIORITIZED_DISPATCHER_H_
6 #define NET_BASE_PRIORITIZED_DISPATCHER_H_
7 
8 #include <stddef.h>
9 
10 #include <vector>
11 
12 #include "net/base/net_export.h"
13 #include "net/base/priority_queue.h"
14 
15 namespace net {
16 
17 // A priority-based dispatcher of jobs. Dispatch order is by priority (highest
18 // first) and then FIFO. The dispatcher enforces limits on the number of running
19 // jobs. It never revokes a job once started. The job must call OnJobFinished
20 // once it finishes in order to dispatch further jobs.
21 //
22 // This class is NOT thread-safe which is enforced by the underlying
23 // non-thread-safe PriorityQueue. All operations are O(p) time for p priority
24 // levels. It is safe to execute any method, including destructor, from within
25 // Job::Start.
26 //
27 class NET_EXPORT_PRIVATE PrioritizedDispatcher {
28  public:
29   class Job;
30   typedef PriorityQueue<Job*>::Priority Priority;
31 
32   // Describes the limits for the number of jobs started by the dispatcher.
33   // For example, |total_jobs| = 30 and |reserved_slots| = { 0, 5, 10, 5 } allow
34   // for at most 30 running jobs in total. Jobs at priority 0 can't use slots
35   // reserved for higher priorities, so they are limited to 10.
36   // If there are already 24 jobs running, then only 6 more jobs can start. No
37   // jobs at priority 1 or below can start. After one more job starts, no jobs
38   // at priority 2 or below can start, since the remaining 5 slots are reserved
39   // for priority 3 or above.
40   struct NET_EXPORT_PRIVATE Limits {
41     Limits(Priority num_priorities, size_t total_jobs);
42     Limits(const Limits& other);
43     ~Limits();
44 
45     // Total allowed running jobs.
46     size_t total_jobs;
47     // Number of slots reserved for each priority and higher.
48     // Sum of |reserved_slots| must be no greater than |total_jobs|.
49     std::vector<size_t> reserved_slots;
50   };
51 
52   // An interface to the job dispatched by PrioritizedDispatcher. The dispatcher
53   // does not own the Job but expects it to live as long as the Job is queued.
54   // Use Cancel to remove Job from queue before it is dispatched. The Job can be
55   // deleted after it is dispatched or canceled, or the dispatcher is destroyed.
56   class Job {
57    public:
58     // Note: PrioritizedDispatcher will never delete a Job.
59     virtual ~Job() = default;
60     // Called when the dispatcher starts the job. Once the job finishes, it must
61     // call OnJobFinished.
62     virtual void Start() = 0;
63   };
64 
65   // A handle to the enqueued job. The handle becomes invalid when the job is
66   // canceled, updated, or started.
67   typedef PriorityQueue<Job*>::Pointer Handle;
68 
69   // Creates a dispatcher enforcing |limits| on number of running jobs.
70   explicit PrioritizedDispatcher(const Limits& limits);
71 
72   PrioritizedDispatcher(const PrioritizedDispatcher&) = delete;
73   PrioritizedDispatcher& operator=(const PrioritizedDispatcher&) = delete;
74   ~PrioritizedDispatcher();
75 
num_running_jobs()76   size_t num_running_jobs() const { return num_running_jobs_; }
num_queued_jobs()77   size_t num_queued_jobs() const { return queue_.size(); }
num_priorities()78   size_t num_priorities() const { return max_running_jobs_.size(); }
79 
80   // Adds |job| with |priority| to the dispatcher. If limits permit, |job| is
81   // started immediately. Returns handle to the job or null-handle if the job is
82   // started. The dispatcher does not own |job|, but |job| must live as long as
83   // it is queued in the dispatcher.
84   Handle Add(Job* job, Priority priority);
85 
86   // Just like Add, except that it adds Job at the font of queue of jobs with
87   // priorities of |priority|.
88   Handle AddAtHead(Job* job, Priority priority);
89 
90   // Removes the job with |handle| from the queue. Invalidates |handle|.
91   // Note: a Handle is valid iff the job is in the queue, i.e. has not Started.
92   void Cancel(const Handle& handle);
93 
94   // Cancels and returns the oldest-lowest-priority Job invalidating any
95   // handles to it. Returns NULL if the queue is empty.
96   Job* EvictOldestLowest();
97 
98   // Moves the queued job with |handle| to the end of all values with priority
99   // |priority| and returns the updated handle, or null-handle if it starts the
100   // job. Invalidates |handle|. No-op if priority did not change.
101   Handle ChangePriority(const Handle& handle, Priority priority);
102 
103   // Notifies the dispatcher that a running job has finished. Could start a job.
104   void OnJobFinished();
105 
106   // Retrieves the Limits that |this| is currently using.  This may not exactly
107   // match the Limits this was created with.  In particular, the number of slots
108   // reserved for the lowest priority will always be 0, even if it was non-zero
109   // in the Limits passed to the constructor or to SetLimits.
110   Limits GetLimits() const;
111 
112   // Updates |max_running_jobs_| to match |limits|.  Starts jobs if new limit
113   // allows.  Does not stop jobs if the new limits are lower than the old ones.
114   void SetLimits(const Limits& limits);
115 
116   // Set the limits to zero for all priorities, allowing no new jobs to start.
117   void SetLimitsToZero();
118 
119  private:
120   // Attempts to dispatch the job with |handle| at priority |priority| (might be
121   // different than |handle.priority()|. Returns true if successful. If so
122   // the |handle| becomes invalid.
123   bool MaybeDispatchJob(const Handle& handle, Priority priority);
124 
125   // Attempts to dispatch the next highest priority job in the queue. Returns
126   // true if successful, and all handles to that job become invalid.
127   bool MaybeDispatchNextJob();
128 
129   // Queue for jobs that need to wait for a spare slot.
130   PriorityQueue<Job*> queue_;
131   // Maximum total number of running jobs allowed after a job at a particular
132   // priority is started. If a greater or equal number of jobs are running, then
133   // another job cannot be started.
134   std::vector<size_t> max_running_jobs_;
135   // Total number of running jobs.
136   size_t num_running_jobs_ = 0;
137 };
138 
139 }  // namespace net
140 
141 #endif  // NET_BASE_PRIORITIZED_DISPATCHER_H_
142