blob: 7ac4a13c0bbc6cccc3ae0dddba2fa2eba31820c5 [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
Alex Deymo759c2752014-03-17 21:09:36 -07005#ifndef CHROMEOS_PLATFORM_UPDATE_ENGINE_ACTION_H_
6#define CHROMEOS_PLATFORM_UPDATE_ENGINE_ACTION_H_
rspangler@google.com49fdf182009-10-10 00:57:34 +00007
8#include <stdio.h>
9#include <tr1/memory>
10#include <iostream>
rspangler@google.com49fdf182009-10-10 00:57:34 +000011#include "base/basictypes.h"
Chris Masone790e62e2010-08-12 10:41:18 -070012#include "base/logging.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000013#include "update_engine/action_processor.h"
adlr@google.comc98a7ed2009-12-04 18:54:03 +000014#include "update_engine/action_pipe.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000015
16// The structure of these classes (Action, ActionPipe, ActionProcessor, etc.)
17// is based on the KSAction* classes from the Google Update Engine code at
18// http://code.google.com/p/update-engine/ . The author of this file sends
19// a big thanks to that team for their high quality design, implementation,
20// and documentation.
21//
22// Readers may want to consult this wiki page from the Update Engine site:
23// http://code.google.com/p/update-engine/wiki/ActionProcessor
24// Although it's referring to the Objective-C KSAction* classes, much
25// applies here as well.
26//
27// How it works:
28//
29// First off, there is only one thread and all I/O should be asynchronous.
30// A glib main loop blocks whenever there is no work to be done. This happens
31// where there is no CPU work to be done and no I/O ready to transfer in or
32// out. Two kinds of events can wake up the main loop: timer alarm or file
33// descriptors. If either of these happens, glib finds out the owner of what
34// fired and calls the appropriate code to handle it. As such, all the code
35// in the Action* classes and the code that is calls is non-blocking.
36//
37// An ActionProcessor contains a queue of Actions to perform. When
38// ActionProcessor::StartProcessing() is called, it executes the first action.
39// Each action tells the processor when it has completed, which causes the
40// Processor to execute the next action. ActionProcessor may have a delegate
41// (an object of type ActionProcessorDelegate). If it does, the delegate
42// is called to be notified of events as they happen.
43//
44// ActionPipe classes
45//
46// See action_pipe.h
47//
48// ActionTraits
49//
50// We need to use an extra class ActionTraits. ActionTraits is a simple
51// templated class that contains only two typedefs: OutputObjectType and
52// InputObjectType. Each action class also has two typedefs of the same name
53// that are of the same type. So, to get the input/output types of, e.g., the
54// DownloadAction class, we look at the type of
55// DownloadAction::InputObjectType.
56//
57// Each concrete Action class derives from Action<T>. This means that during
58// template instatiation of Action<T>, T is declared but not defined, which
59// means that T::InputObjectType (and OutputObjectType) is not defined.
60// However, the traits class is constructed in such a way that it will be
61// template instatiated first, so Action<T> *can* find the types it needs by
62// consulting ActionTraits<T>::InputObjectType (and OutputObjectType).
63// This is why the ActionTraits classes are needed.
64
rspangler@google.com49fdf182009-10-10 00:57:34 +000065namespace chromeos_update_engine {
66
67// It is handy to have a non-templated base class of all Actions.
68class AbstractAction {
69 public:
70 AbstractAction() : processor_(NULL) {}
71
72 // Begin performing the action. Since this code is asynchronous, when this
73 // method returns, it means only that the action has started, not necessarily
74 // completed. However, it's acceptable for this method to perform the
75 // action synchronously; Action authors should understand the implications
76 // of synchronously performing, though, because this is a single-threaded
77 // app, the entire process will be blocked while the action performs.
78 //
79 // When the action is complete, it must call
80 // ActionProcessor::ActionComplete(this); to notify the processor that it's
81 // done.
82 virtual void PerformAction() = 0;
83
David Zeuthen33bae492014-02-25 16:16:18 -080084 // Called on ActionProcess::ActionComplete() by ActionProcessor.
85 virtual void ActionCompleted(ErrorCode code) {}
86
rspangler@google.com49fdf182009-10-10 00:57:34 +000087 // Called by the ActionProcessor to tell this Action which processor
88 // it belongs to.
89 void SetProcessor(ActionProcessor* processor) {
90 if (processor)
91 CHECK(!processor_);
92 else
93 CHECK(processor_);
94 processor_ = processor;
95 }
96
97 // Returns true iff the action is the current action of its ActionProcessor.
98 bool IsRunning() const {
99 if (!processor_)
100 return false;
101 return processor_->current_action() == this;
102 }
103
104 // Called on asynchronous actions if canceled. Actions may implement if
105 // there's any cleanup to do. There is no need to call
106 // ActionProcessor::ActionComplete() because the processor knows this
107 // action is terminating.
108 // Only the ActionProcessor should call this.
109 virtual void TerminateProcessing() {};
110
111 // These methods are useful for debugging. TODO(adlr): consider using
112 // std::type_info for this?
113 // Type() returns a string of the Action type. I.e., for DownloadAction,
114 // Type() would return "DownloadAction".
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800115 virtual std::string Type() const = 0;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000116
117 protected:
118 // A weak pointer to the processor that owns this Action.
119 ActionProcessor* processor_;
120};
121
122// Forward declare a couple classes we use.
123template<typename T>
124class ActionPipe;
125template<typename T>
126class ActionTraits;
127
128template<typename SubClass>
129class Action : public AbstractAction {
130 public:
Darin Petkovfbb40092010-07-29 17:05:50 -0700131 virtual ~Action() {}
rspangler@google.com49fdf182009-10-10 00:57:34 +0000132
133 // Attaches an input pipe to this Action. This is optional; an Action
134 // doesn't need to have an input pipe. The input pipe must be of the type
135 // of object that this class expects.
136 // This is generally called by ActionPipe::Bond()
137 void set_in_pipe(
138 // this type is a fancy way of saying: a shared_ptr to an
139 // ActionPipe<InputObjectType>.
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800140 const std::tr1::shared_ptr<ActionPipe<
rspangler@google.com49fdf182009-10-10 00:57:34 +0000141 typename ActionTraits<SubClass>::InputObjectType> >&
142 in_pipe) {
143 in_pipe_ = in_pipe;
144 }
145
146 // Attaches an output pipe to this Action. This is optional; an Action
147 // doesn't need to have an output pipe. The output pipe must be of the type
148 // of object that this class expects.
149 // This is generally called by ActionPipe::Bond()
150 void set_out_pipe(
151 // this type is a fancy way of saying: a shared_ptr to an
152 // ActionPipe<OutputObjectType>.
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800153 const std::tr1::shared_ptr<ActionPipe<
rspangler@google.com49fdf182009-10-10 00:57:34 +0000154 typename ActionTraits<SubClass>::OutputObjectType> >&
155 out_pipe) {
156 out_pipe_ = out_pipe;
157 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000158
rspangler@google.com49fdf182009-10-10 00:57:34 +0000159 // Returns true iff there is an associated input pipe. If there's an input
160 // pipe, there's an input object, but it may have been constructed with the
161 // default ctor if the previous action didn't call SetOutputObject().
162 bool HasInputObject() const { return in_pipe_.get(); }
163
164 // returns a const reference to the object in the input pipe.
165 const typename ActionTraits<SubClass>::InputObjectType& GetInputObject()
166 const {
167 CHECK(HasInputObject());
168 return in_pipe_->contents();
169 }
170
171 // Returns true iff there's an output pipe.
172 bool HasOutputPipe() const {
173 return out_pipe_.get();
174 }
175
176 // Copies the object passed into the output pipe. It will be accessible to
177 // the next Action via that action's input pipe (which is the same as this
178 // Action's output pipe).
179 void SetOutputObject(
180 const typename ActionTraits<SubClass>::OutputObjectType& out_obj) {
181 CHECK(HasOutputPipe());
182 out_pipe_->set_contents(out_obj);
183 }
184
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000185 // Returns a reference to the object sitting in the output pipe.
186 const typename ActionTraits<SubClass>::OutputObjectType& GetOutputObject() {
187 CHECK(HasOutputPipe());
188 return out_pipe_->contents();
189 }
190
Andrew de los Reyesf98bff82010-05-06 13:33:25 -0700191 protected:
rspangler@google.com49fdf182009-10-10 00:57:34 +0000192 // We use a shared_ptr to the pipe. shared_ptr objects destroy what they
193 // point to when the last such shared_ptr object dies. We consider the
194 // Actions on either end of a pipe to "own" the pipe. When the last Action
195 // of the two dies, the ActionPipe will die, too.
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800196 std::tr1::shared_ptr<
197 ActionPipe<typename ActionTraits<SubClass>::InputObjectType> >
rspangler@google.com49fdf182009-10-10 00:57:34 +0000198 in_pipe_;
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800199 std::tr1::shared_ptr<
200 ActionPipe<typename ActionTraits<SubClass>::OutputObjectType> >
rspangler@google.com49fdf182009-10-10 00:57:34 +0000201 out_pipe_;
202};
203
204}; // namespace chromeos_update_engine
205
Alex Deymo759c2752014-03-17 21:09:36 -0700206#endif // CHROMEOS_PLATFORM_UPDATE_ENGINE_ACTION_H_