-
Notifications
You must be signed in to change notification settings - Fork 37
/
Copy pathaction.h
238 lines (209 loc) · 9.16 KB
/
action.h
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
//
// Copyright (C) 2009 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef UPDATE_ENGINE_COMMON_ACTION_H_
#define UPDATE_ENGINE_COMMON_ACTION_H_
#include <stdio.h>
#include <memory>
#include <string>
#include <base/logging.h>
#include <base/macros.h>
#include "update_engine/common/action_pipe.h"
#include "update_engine/common/action_processor.h"
// The structure of these classes (Action, ActionPipe, ActionProcessor, etc.)
// is based on the KSAction* classes from the Google Update Engine code at
// http://code.google.com/p/update-engine/ . The author of this file sends
// a big thanks to that team for their high quality design, implementation,
// and documentation.
//
// Readers may want to consult this wiki page from the Update Engine site:
// http://code.google.com/p/update-engine/wiki/ActionProcessor
// Although it's referring to the Objective-C KSAction* classes, much
// applies here as well.
//
// How it works:
//
// First off, there is only one thread and all I/O should be asynchronous.
// A message loop blocks whenever there is no work to be done. This happens
// where there is no CPU work to be done and no I/O ready to transfer in or
// out. Two kinds of events can wake up the message loop: timer alarm or file
// descriptors. If either of these happens, the message loop finds out the owner
// of what fired and calls the appropriate code to handle it. As such, all the
// code in the Action* classes and the code that is calls is non-blocking.
//
// An ActionProcessor contains a queue of Actions to perform. When
// ActionProcessor::StartProcessing() is called, it executes the first action.
// Each action tells the processor when it has completed, which causes the
// Processor to execute the next action. ActionProcessor may have a delegate
// (an object of type ActionProcessorDelegate). If it does, the delegate
// is called to be notified of events as they happen.
//
// ActionPipe classes
//
// See action_pipe.h
//
// ActionTraits
//
// We need to use an extra class ActionTraits. ActionTraits is a simple
// templated class that contains only two typedefs: OutputObjectType and
// InputObjectType. Each action class also has two typedefs of the same name
// that are of the same type. So, to get the input/output types of, e.g., the
// DownloadAction class, we look at the type of
// DownloadAction::InputObjectType.
//
// Each concrete Action class derives from Action<T>. This means that during
// template instantiation of Action<T>, T is declared but not defined, which
// means that T::InputObjectType (and OutputObjectType) is not defined.
// However, the traits class is constructed in such a way that it will be
// template instantiated first, so Action<T> *can* find the types it needs by
// consulting ActionTraits<T>::InputObjectType (and OutputObjectType).
// This is why the ActionTraits classes are needed.
namespace chromeos_update_engine {
// It is handy to have a non-templated base class of all Actions.
class AbstractAction {
public:
AbstractAction() : processor_(nullptr) {}
virtual ~AbstractAction() = default;
// Begin performing the action. Since this code is asynchronous, when this
// method returns, it means only that the action has started, not necessarily
// completed. However, it's acceptable for this method to perform the
// action synchronously; Action authors should understand the implications
// of synchronously performing, though, because this is a single-threaded
// app, the entire process will be blocked while the action performs.
//
// When the action is complete, it must call
// ActionProcessor::ActionComplete(this); to notify the processor that it's
// done.
virtual void PerformAction() = 0;
// Called on ActionProcess::ActionComplete() by ActionProcessor.
virtual void ActionCompleted([[maybe_unused]] ErrorCode code) {}
// Called by the ActionProcessor to tell this Action which processor
// it belongs to.
void SetProcessor(ActionProcessor* processor) {
if (processor)
CHECK(!processor_);
else
CHECK(processor_);
processor_ = processor;
}
// Returns true iff the action is the current action of its ActionProcessor.
bool IsRunning() const {
if (!processor_)
return false;
return processor_->current_action() == this;
}
// Called on asynchronous actions if canceled. Actions may implement if
// there's any cleanup to do. There is no need to call
// ActionProcessor::ActionComplete() because the processor knows this
// action is terminating.
// Only the ActionProcessor should call this.
virtual void TerminateProcessing() {}
// Called on asynchronous actions if the processing is suspended and resumed,
// respectively. These methods are called by the ActionProcessor and should
// not be explicitly called.
// The action may still call ActionCompleted() once the action is completed
// while the processing is suspended, for example if suspend/resume is not
// implemented for the given action.
virtual void SuspendAction() {}
virtual void ResumeAction() {}
// These methods are useful for debugging. TODO(adlr): consider using
// std::type_info for this?
// Type() returns a string of the Action type. I.e., for DownloadAction,
// Type() would return "DownloadAction".
virtual std::string Type() const = 0;
protected:
// A weak pointer to the processor that owns this Action.
ActionProcessor* processor_;
};
// Forward declare a couple classes we use.
template <typename T>
class ActionPipe;
template <typename T>
class ActionTraits;
template <typename SubClass>
class Action : public AbstractAction {
public:
~Action() override {}
// Attaches an input pipe to this Action. This is optional; an Action
// doesn't need to have an input pipe. The input pipe must be of the type
// of object that this class expects.
// This is generally called by ActionPipe::Bond()
void set_in_pipe(
// this type is a fancy way of saying: a shared_ptr to an
// ActionPipe<InputObjectType>.
const std::shared_ptr<
ActionPipe<typename ActionTraits<SubClass>::InputObjectType>>&
in_pipe) {
in_pipe_ = in_pipe;
}
// Attaches an output pipe to this Action. This is optional; an Action
// doesn't need to have an output pipe. The output pipe must be of the type
// of object that this class expects.
// This is generally called by ActionPipe::Bond()
void set_out_pipe(
// this type is a fancy way of saying: a shared_ptr to an
// ActionPipe<OutputObjectType>.
const std::shared_ptr<
ActionPipe<typename ActionTraits<SubClass>::OutputObjectType>>&
out_pipe) {
out_pipe_ = out_pipe;
}
// Returns true iff there is an associated input pipe. If there's an input
// pipe, there's an input object, but it may have been constructed with the
// default ctor if the previous action didn't call SetOutputObject().
bool HasInputObject() const { return in_pipe_.get(); }
// returns a const reference to the object in the input pipe.
const typename ActionTraits<SubClass>::InputObjectType& GetInputObject()
const {
CHECK(HasInputObject());
return in_pipe_->contents();
}
// Returns true iff there's an output pipe.
bool HasOutputPipe() const { return out_pipe_.get(); }
// Copies the object passed into the output pipe. It will be accessible to
// the next Action via that action's input pipe (which is the same as this
// Action's output pipe).
void SetOutputObject(
const typename ActionTraits<SubClass>::OutputObjectType& out_obj) {
CHECK(HasOutputPipe());
out_pipe_->set_contents(out_obj);
}
// Returns a reference to the object sitting in the output pipe.
const typename ActionTraits<SubClass>::OutputObjectType& GetOutputObject() {
CHECK(HasOutputPipe());
return out_pipe_->contents();
}
protected:
// We use a shared_ptr to the pipe. shared_ptr objects destroy what they
// point to when the last such shared_ptr object dies. We consider the
// Actions on either end of a pipe to "own" the pipe. When the last Action
// of the two dies, the ActionPipe will die, too.
std::shared_ptr<ActionPipe<typename ActionTraits<SubClass>::InputObjectType>>
in_pipe_;
std::shared_ptr<ActionPipe<typename ActionTraits<SubClass>::OutputObjectType>>
out_pipe_;
};
// An action that does nothing and completes with kSuccess immediately.
class NoOpAction : public AbstractAction {
public:
~NoOpAction() override {}
void PerformAction() override {
processor_->ActionComplete(this, ErrorCode::kSuccess);
}
static std::string StaticType() { return "NoOpAction"; }
std::string Type() const override { return StaticType(); }
};
}; // namespace chromeos_update_engine
#endif // UPDATE_ENGINE_COMMON_ACTION_H_