blob: c7fcba608b67b93b248d9af4e93f0498f6c347fe [file] [log] [blame]
rspangler@google.com49fdf182009-10-10 00:57:34 +00001// Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Gilad Arnoldcf175a02014-07-10 16:48:47 -07005#ifndef UPDATE_ENGINE_ACTION_H_
6#define UPDATE_ENGINE_ACTION_H_
rspangler@google.com49fdf182009-10-10 00:57:34 +00007
8#include <stdio.h>
Alex Deymobc91a272014-05-20 16:45:33 -07009
Alex Deymobc91a272014-05-20 16:45:33 -070010#include <memory>
Alex Vakulenkod2779df2014-06-16 13:19:00 -070011#include <string>
Alex Deymobc91a272014-05-20 16:45:33 -070012
13#include <base/basictypes.h>
14#include <base/logging.h>
15
adlr@google.comc98a7ed2009-12-04 18:54:03 +000016#include "update_engine/action_pipe.h"
Alex Deymobc91a272014-05-20 16:45:33 -070017#include "update_engine/action_processor.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000018
19// The structure of these classes (Action, ActionPipe, ActionProcessor, etc.)
20// is based on the KSAction* classes from the Google Update Engine code at
21// http://code.google.com/p/update-engine/ . The author of this file sends
22// a big thanks to that team for their high quality design, implementation,
23// and documentation.
24//
25// Readers may want to consult this wiki page from the Update Engine site:
26// http://code.google.com/p/update-engine/wiki/ActionProcessor
27// Although it's referring to the Objective-C KSAction* classes, much
28// applies here as well.
29//
30// How it works:
31//
32// First off, there is only one thread and all I/O should be asynchronous.
33// A glib main loop blocks whenever there is no work to be done. This happens
34// where there is no CPU work to be done and no I/O ready to transfer in or
35// out. Two kinds of events can wake up the main loop: timer alarm or file
36// descriptors. If either of these happens, glib finds out the owner of what
37// fired and calls the appropriate code to handle it. As such, all the code
38// in the Action* classes and the code that is calls is non-blocking.
39//
40// An ActionProcessor contains a queue of Actions to perform. When
41// ActionProcessor::StartProcessing() is called, it executes the first action.
42// Each action tells the processor when it has completed, which causes the
43// Processor to execute the next action. ActionProcessor may have a delegate
44// (an object of type ActionProcessorDelegate). If it does, the delegate
45// is called to be notified of events as they happen.
46//
47// ActionPipe classes
48//
49// See action_pipe.h
50//
51// ActionTraits
52//
53// We need to use an extra class ActionTraits. ActionTraits is a simple
54// templated class that contains only two typedefs: OutputObjectType and
55// InputObjectType. Each action class also has two typedefs of the same name
56// that are of the same type. So, to get the input/output types of, e.g., the
57// DownloadAction class, we look at the type of
58// DownloadAction::InputObjectType.
59//
60// Each concrete Action class derives from Action<T>. This means that during
Alex Vakulenkod2779df2014-06-16 13:19:00 -070061// template instantiation of Action<T>, T is declared but not defined, which
rspangler@google.com49fdf182009-10-10 00:57:34 +000062// means that T::InputObjectType (and OutputObjectType) is not defined.
63// However, the traits class is constructed in such a way that it will be
Alex Vakulenkod2779df2014-06-16 13:19:00 -070064// template instantiated first, so Action<T> *can* find the types it needs by
rspangler@google.com49fdf182009-10-10 00:57:34 +000065// consulting ActionTraits<T>::InputObjectType (and OutputObjectType).
66// This is why the ActionTraits classes are needed.
67
rspangler@google.com49fdf182009-10-10 00:57:34 +000068namespace chromeos_update_engine {
69
70// It is handy to have a non-templated base class of all Actions.
71class AbstractAction {
72 public:
Alex Vakulenko88b591f2014-08-28 16:48:57 -070073 AbstractAction() : processor_(nullptr) {}
rspangler@google.com49fdf182009-10-10 00:57:34 +000074
75 // Begin performing the action. Since this code is asynchronous, when this
76 // method returns, it means only that the action has started, not necessarily
77 // completed. However, it's acceptable for this method to perform the
78 // action synchronously; Action authors should understand the implications
79 // of synchronously performing, though, because this is a single-threaded
80 // app, the entire process will be blocked while the action performs.
81 //
82 // When the action is complete, it must call
83 // ActionProcessor::ActionComplete(this); to notify the processor that it's
84 // done.
85 virtual void PerformAction() = 0;
86
David Zeuthen33bae492014-02-25 16:16:18 -080087 // Called on ActionProcess::ActionComplete() by ActionProcessor.
88 virtual void ActionCompleted(ErrorCode code) {}
89
rspangler@google.com49fdf182009-10-10 00:57:34 +000090 // Called by the ActionProcessor to tell this Action which processor
91 // it belongs to.
92 void SetProcessor(ActionProcessor* processor) {
93 if (processor)
94 CHECK(!processor_);
95 else
96 CHECK(processor_);
97 processor_ = processor;
98 }
99
100 // Returns true iff the action is the current action of its ActionProcessor.
101 bool IsRunning() const {
102 if (!processor_)
103 return false;
104 return processor_->current_action() == this;
105 }
106
107 // Called on asynchronous actions if canceled. Actions may implement if
108 // there's any cleanup to do. There is no need to call
109 // ActionProcessor::ActionComplete() because the processor knows this
110 // action is terminating.
111 // Only the ActionProcessor should call this.
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700112 virtual void TerminateProcessing() {}
rspangler@google.com49fdf182009-10-10 00:57:34 +0000113
114 // These methods are useful for debugging. TODO(adlr): consider using
115 // std::type_info for this?
116 // Type() returns a string of the Action type. I.e., for DownloadAction,
117 // Type() would return "DownloadAction".
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800118 virtual std::string Type() const = 0;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000119
120 protected:
121 // A weak pointer to the processor that owns this Action.
122 ActionProcessor* processor_;
123};
124
125// Forward declare a couple classes we use.
126template<typename T>
127class ActionPipe;
128template<typename T>
129class ActionTraits;
130
131template<typename SubClass>
132class Action : public AbstractAction {
133 public:
Darin Petkovfbb40092010-07-29 17:05:50 -0700134 virtual ~Action() {}
rspangler@google.com49fdf182009-10-10 00:57:34 +0000135
136 // Attaches an input pipe to this Action. This is optional; an Action
137 // doesn't need to have an input pipe. The input pipe must be of the type
138 // of object that this class expects.
139 // This is generally called by ActionPipe::Bond()
140 void set_in_pipe(
141 // this type is a fancy way of saying: a shared_ptr to an
142 // ActionPipe<InputObjectType>.
Alex Deymobc91a272014-05-20 16:45:33 -0700143 const std::shared_ptr<ActionPipe<
rspangler@google.com49fdf182009-10-10 00:57:34 +0000144 typename ActionTraits<SubClass>::InputObjectType> >&
145 in_pipe) {
146 in_pipe_ = in_pipe;
147 }
148
149 // Attaches an output pipe to this Action. This is optional; an Action
150 // doesn't need to have an output pipe. The output pipe must be of the type
151 // of object that this class expects.
152 // This is generally called by ActionPipe::Bond()
153 void set_out_pipe(
154 // this type is a fancy way of saying: a shared_ptr to an
155 // ActionPipe<OutputObjectType>.
Alex Deymobc91a272014-05-20 16:45:33 -0700156 const std::shared_ptr<ActionPipe<
rspangler@google.com49fdf182009-10-10 00:57:34 +0000157 typename ActionTraits<SubClass>::OutputObjectType> >&
158 out_pipe) {
159 out_pipe_ = out_pipe;
160 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000161
rspangler@google.com49fdf182009-10-10 00:57:34 +0000162 // Returns true iff there is an associated input pipe. If there's an input
163 // pipe, there's an input object, but it may have been constructed with the
164 // default ctor if the previous action didn't call SetOutputObject().
165 bool HasInputObject() const { return in_pipe_.get(); }
166
167 // returns a const reference to the object in the input pipe.
168 const typename ActionTraits<SubClass>::InputObjectType& GetInputObject()
169 const {
170 CHECK(HasInputObject());
171 return in_pipe_->contents();
172 }
173
174 // Returns true iff there's an output pipe.
175 bool HasOutputPipe() const {
176 return out_pipe_.get();
177 }
178
179 // Copies the object passed into the output pipe. It will be accessible to
180 // the next Action via that action's input pipe (which is the same as this
181 // Action's output pipe).
182 void SetOutputObject(
183 const typename ActionTraits<SubClass>::OutputObjectType& out_obj) {
184 CHECK(HasOutputPipe());
185 out_pipe_->set_contents(out_obj);
186 }
187
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000188 // Returns a reference to the object sitting in the output pipe.
189 const typename ActionTraits<SubClass>::OutputObjectType& GetOutputObject() {
190 CHECK(HasOutputPipe());
191 return out_pipe_->contents();
192 }
193
Andrew de los Reyesf98bff82010-05-06 13:33:25 -0700194 protected:
rspangler@google.com49fdf182009-10-10 00:57:34 +0000195 // We use a shared_ptr to the pipe. shared_ptr objects destroy what they
196 // point to when the last such shared_ptr object dies. We consider the
197 // Actions on either end of a pipe to "own" the pipe. When the last Action
198 // of the two dies, the ActionPipe will die, too.
Alex Deymobc91a272014-05-20 16:45:33 -0700199 std::shared_ptr<
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800200 ActionPipe<typename ActionTraits<SubClass>::InputObjectType> >
rspangler@google.com49fdf182009-10-10 00:57:34 +0000201 in_pipe_;
Alex Deymobc91a272014-05-20 16:45:33 -0700202 std::shared_ptr<
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800203 ActionPipe<typename ActionTraits<SubClass>::OutputObjectType> >
rspangler@google.com49fdf182009-10-10 00:57:34 +0000204 out_pipe_;
205};
206
207}; // namespace chromeos_update_engine
208
Gilad Arnoldcf175a02014-07-10 16:48:47 -0700209#endif // UPDATE_ENGINE_ACTION_H_