1
1
/*
2
- * Copyright 2018 Google
2
+ * Copyright 2018 Google LLC
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
21
21
#include < functional>
22
22
#include < memory>
23
23
#include < string>
24
- #include < utility>
25
-
26
- #include " absl/types/optional.h"
27
24
28
25
namespace firebase {
29
26
namespace firestore {
30
27
namespace util {
31
28
32
- // A handle to an operation scheduled for future execution. The handle may
33
- // outlive the operation, but it *cannot* outlive the executor that created it.
34
- class DelayedOperation {
35
- public:
36
- // Creates an empty `DelayedOperation` not associated with any actual
37
- // operation. Calling `Cancel` on it is a no-op.
38
- DelayedOperation () {
39
- }
40
-
41
- // Returns whether this `DelayedOperation` is associated with an actual
42
- // operation.
43
- explicit operator bool () const {
44
- return static_cast <bool >(cancel_func_);
45
- }
46
-
47
- // If the operation has not been run yet, cancels the operation. Otherwise,
48
- // this function is a no-op.
49
- void Cancel () {
50
- if (cancel_func_) {
51
- cancel_func_ ();
52
- cancel_func_ = {};
53
- }
54
- }
55
-
56
- // Internal use only.
57
- explicit DelayedOperation (std::function<void ()>&& cancel_func)
58
- : cancel_func_{std::move (cancel_func)} {
59
- }
60
-
61
- private:
62
- std::function<void ()> cancel_func_;
63
- };
29
+ class DelayedOperation ;
30
+ class Task ;
64
31
65
32
// An interface to a platform-specific executor of asynchronous operations
66
33
// (called tasks on other platforms).
@@ -71,25 +38,23 @@ class DelayedOperation {
71
38
// The operations are executed sequentially; only a single operation is executed
72
39
// at any given time.
73
40
//
74
- // Delayed operations may be canceled if they have not already been run.
41
+ // Delayed operations may be cancelled if they have not already been run.
75
42
class Executor {
76
43
public:
44
+ // An opaque name for a kind of operation. All operations of the same type
45
+ // should share a tag.
77
46
using Tag = int ;
47
+ static constexpr Tag kNoTag = -1 ;
48
+
49
+ // An opaque, monotonically increasing identifier for each operation that does
50
+ // not depend on its address. Whereas the `Tag` identifies the kind of
51
+ // operation, the `Id` identifies the specific instance.
52
+ using Id = uint32_t ;
78
53
using Operation = std::function<void ()>;
79
- using Milliseconds = std::chrono::milliseconds;
80
54
81
- // Operations scheduled for future execution have an opaque tag. The value of
82
- // the tag is ignored by the executor but can be used to find operations with
83
- // a given tag after they are scheduled.
84
- struct TaggedOperation {
85
- TaggedOperation () {
86
- }
87
- TaggedOperation (const Tag tag, Operation&& operation)
88
- : tag{tag}, operation{std::move (operation)} {
89
- }
90
- Tag tag = 0 ;
91
- Operation operation;
92
- };
55
+ using Milliseconds = std::chrono::milliseconds;
56
+ using Clock = std::chrono::steady_clock;
57
+ using TimePoint = std::chrono::time_point<Clock, Milliseconds>;
93
58
94
59
// Creates a new serial Executor of the platform-appropriate type, and gives
95
60
// it the given label, if the implementation supports it.
@@ -113,15 +78,20 @@ class Executor {
113
78
// Like `Execute`, but blocks until the `operation` finishes, consequently
114
79
// draining immediate operations from the executor.
115
80
virtual void ExecuteBlocking (Operation&& operation) = 0;
81
+
116
82
// Scheduled the given `operation` to be executed after `delay` milliseconds
117
83
// from now, and returns a handle that allows to cancel the operation
118
- // (provided it hasn't been run already). The operation is tagged to allow
119
- // retrieving it later.
84
+ // (provided it hasn't been run already).
85
+ //
86
+ // Operations scheduled for future execution have an opaque tag. The value of
87
+ // the tag is ignored by the executor but can be used to find operations with
88
+ // a given tag after they are scheduled.
120
89
//
121
90
// `delay` must be non-negative; use `Execute` to schedule operations for
122
91
// immediate execution.
123
92
virtual DelayedOperation Schedule (Milliseconds delay,
124
- TaggedOperation&& operation) = 0;
93
+ Tag tag,
94
+ Operation&& operation) = 0;
125
95
126
96
// Checks for the caller whether it is being invoked by this executor.
127
97
virtual bool IsCurrentExecutor () const = 0;
@@ -135,13 +105,66 @@ class Executor {
135
105
136
106
// Checks whether an operation tagged with the given `tag` is currently
137
107
// scheduled for future execution.
138
- virtual bool IsScheduled (Tag tag) const = 0;
108
+ virtual bool IsTagScheduled (Tag tag) const = 0;
109
+ virtual bool IsIdScheduled (Id id) const = 0;
110
+
139
111
// Removes the nearest due scheduled operation from the schedule and returns
140
- // it to the caller. This function may be used to reschedule operations.
141
- // Immediate operations don't count; only operations scheduled for delayed
142
- // execution may be removed. If no such operations are currently scheduled, an
143
- // empty `optional` is returned.
144
- virtual absl::optional<TaggedOperation> PopFromSchedule () = 0;
112
+ // it to the caller.
113
+ //
114
+ // Only operations scheduled for delayed execution can be removed with this
115
+ // method; immediate operations don't count. If no such operations are
116
+ // currently scheduled, `nullptr` is returned.
117
+ //
118
+ // The caller is responsible for either executing or cancelling (and
119
+ // releasing) the returned Task.
120
+ virtual Task* PopFromSchedule () = 0;
121
+
122
+ private:
123
+ // Mark a task completed, removing it from any internal schedule or tracking.
124
+ // Called by Task once it has completed execution.
125
+ virtual void OnCompletion (Task* task) = 0;
126
+ friend class Task ;
127
+
128
+ // If the operation hasn't yet been run, it will be removed from the queue.
129
+ // Otherwise, this function is a no-op.
130
+ //
131
+ // Called by `DelayedOperation` when its user calls `Cancel`. Implementations
132
+ // of `Cancel` should also `Dispose` the underlying `Task` to actually prevent
133
+ // execution.
134
+ virtual void Cancel (Id operation_id) = 0;
135
+ friend class DelayedOperation ;
136
+ };
137
+
138
+ // A handle to an operation scheduled for future execution. The handle may
139
+ // outlive the operation, but it *cannot* outlive the executor that created it.
140
+ class DelayedOperation {
141
+ public:
142
+ // Creates an empty `DelayedOperation` not associated with any actual
143
+ // operation. Calling `Cancel` on it is a no-op.
144
+ DelayedOperation () = default ;
145
+
146
+ // Returns whether this `DelayedOperation` is associated with an actual
147
+ // operation.
148
+ explicit operator bool () const {
149
+ return executor_ && executor_->IsIdScheduled (id_);
150
+ }
151
+
152
+ // If the operation has not been run yet, cancels the operation. Otherwise,
153
+ // this function is a no-op.
154
+ void Cancel () {
155
+ if (executor_) {
156
+ executor_->Cancel (id_);
157
+ }
158
+ }
159
+
160
+ // Internal use only.
161
+ explicit DelayedOperation (Executor* executor, Executor::Id id)
162
+ : executor_(executor), id_(id) {
163
+ }
164
+
165
+ private:
166
+ Executor* executor_ = nullptr ;
167
+ Executor::Id id_ = 0 ;
145
168
};
146
169
147
170
} // namespace util
0 commit comments