blob: af6deee0b0c14ea6e52941cc0b409de18ce1bba4 [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
adlr@google.comc98a7ed2009-12-04 18:54:03 +00005#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"
adlr@google.comc98a7ed2009-12-04 18:54:03 +000012#include "chromeos/obsolete_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
65using std::tr1::shared_ptr;
66
67namespace chromeos_update_engine {
68
69// It is handy to have a non-templated base class of all Actions.
70class AbstractAction {
71 public:
72 AbstractAction() : processor_(NULL) {}
73
74 // Begin performing the action. Since this code is asynchronous, when this
75 // method returns, it means only that the action has started, not necessarily
76 // completed. However, it's acceptable for this method to perform the
77 // action synchronously; Action authors should understand the implications
78 // of synchronously performing, though, because this is a single-threaded
79 // app, the entire process will be blocked while the action performs.
80 //
81 // When the action is complete, it must call
82 // ActionProcessor::ActionComplete(this); to notify the processor that it's
83 // done.
84 virtual void PerformAction() = 0;
85
86 // Called by the ActionProcessor to tell this Action which processor
87 // it belongs to.
88 void SetProcessor(ActionProcessor* processor) {
89 if (processor)
90 CHECK(!processor_);
91 else
92 CHECK(processor_);
93 processor_ = processor;
94 }
95
96 // Returns true iff the action is the current action of its ActionProcessor.
97 bool IsRunning() const {
98 if (!processor_)
99 return false;
100 return processor_->current_action() == this;
101 }
102
103 // Called on asynchronous actions if canceled. Actions may implement if
104 // there's any cleanup to do. There is no need to call
105 // ActionProcessor::ActionComplete() because the processor knows this
106 // action is terminating.
107 // Only the ActionProcessor should call this.
108 virtual void TerminateProcessing() {};
109
110 // These methods are useful for debugging. TODO(adlr): consider using
111 // std::type_info for this?
112 // Type() returns a string of the Action type. I.e., for DownloadAction,
113 // Type() would return "DownloadAction".
114 virtual string Type() const = 0;
115
116 protected:
117 // A weak pointer to the processor that owns this Action.
118 ActionProcessor* processor_;
119};
120
121// Forward declare a couple classes we use.
122template<typename T>
123class ActionPipe;
124template<typename T>
125class ActionTraits;
126
127template<typename SubClass>
128class Action : public AbstractAction {
129 public:
130 virtual ~Action() {
131 LOG(INFO) << "Action died";
132 }
133
134 // Attaches an input pipe to this Action. This is optional; an Action
135 // doesn't need to have an input pipe. The input pipe must be of the type
136 // of object that this class expects.
137 // This is generally called by ActionPipe::Bond()
138 void set_in_pipe(
139 // this type is a fancy way of saying: a shared_ptr to an
140 // ActionPipe<InputObjectType>.
141 const shared_ptr<ActionPipe<
142 typename ActionTraits<SubClass>::InputObjectType> >&
143 in_pipe) {
144 in_pipe_ = in_pipe;
145 }
146
147 // Attaches an output pipe to this Action. This is optional; an Action
148 // doesn't need to have an output pipe. The output pipe must be of the type
149 // of object that this class expects.
150 // This is generally called by ActionPipe::Bond()
151 void set_out_pipe(
152 // this type is a fancy way of saying: a shared_ptr to an
153 // ActionPipe<OutputObjectType>.
154 const shared_ptr<ActionPipe<
155 typename ActionTraits<SubClass>::OutputObjectType> >&
156 out_pipe) {
157 out_pipe_ = out_pipe;
158 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000159
rspangler@google.com49fdf182009-10-10 00:57:34 +0000160 // Returns true iff there is an associated input pipe. If there's an input
161 // pipe, there's an input object, but it may have been constructed with the
162 // default ctor if the previous action didn't call SetOutputObject().
163 bool HasInputObject() const { return in_pipe_.get(); }
164
165 // returns a const reference to the object in the input pipe.
166 const typename ActionTraits<SubClass>::InputObjectType& GetInputObject()
167 const {
168 CHECK(HasInputObject());
169 return in_pipe_->contents();
170 }
171
172 // Returns true iff there's an output pipe.
173 bool HasOutputPipe() const {
174 return out_pipe_.get();
175 }
176
177 // Copies the object passed into the output pipe. It will be accessible to
178 // the next Action via that action's input pipe (which is the same as this
179 // Action's output pipe).
180 void SetOutputObject(
181 const typename ActionTraits<SubClass>::OutputObjectType& out_obj) {
182 CHECK(HasOutputPipe());
183 out_pipe_->set_contents(out_obj);
184 }
185
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000186 // Returns a reference to the object sitting in the output pipe.
187 const typename ActionTraits<SubClass>::OutputObjectType& GetOutputObject() {
188 CHECK(HasOutputPipe());
189 return out_pipe_->contents();
190 }
191
192protected:
rspangler@google.com49fdf182009-10-10 00:57:34 +0000193 // We use a shared_ptr to the pipe. shared_ptr objects destroy what they
194 // point to when the last such shared_ptr object dies. We consider the
195 // Actions on either end of a pipe to "own" the pipe. When the last Action
196 // of the two dies, the ActionPipe will die, too.
197 shared_ptr<ActionPipe<typename ActionTraits<SubClass>::InputObjectType> >
198 in_pipe_;
199 shared_ptr<ActionPipe<typename ActionTraits<SubClass>::OutputObjectType> >
200 out_pipe_;
201};
202
203}; // namespace chromeos_update_engine
204
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000205#endif // CHROMEOS_PLATFORM_UPDATE_ENGINE_ACTION_H__