blob: 104ef9e16ed4a46b6d22f01bd765d2adf8048414 [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"
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
84 // Called by the ActionProcessor to tell this Action which processor
85 // it belongs to.
86 void SetProcessor(ActionProcessor* processor) {
87 if (processor)
88 CHECK(!processor_);
89 else
90 CHECK(processor_);
91 processor_ = processor;
92 }
93
94 // Returns true iff the action is the current action of its ActionProcessor.
95 bool IsRunning() const {
96 if (!processor_)
97 return false;
98 return processor_->current_action() == this;
99 }
100
101 // Called on asynchronous actions if canceled. Actions may implement if
102 // there's any cleanup to do. There is no need to call
103 // ActionProcessor::ActionComplete() because the processor knows this
104 // action is terminating.
105 // Only the ActionProcessor should call this.
106 virtual void TerminateProcessing() {};
107
108 // These methods are useful for debugging. TODO(adlr): consider using
109 // std::type_info for this?
110 // Type() returns a string of the Action type. I.e., for DownloadAction,
111 // Type() would return "DownloadAction".
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800112 virtual std::string Type() const = 0;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000113
114 protected:
115 // A weak pointer to the processor that owns this Action.
116 ActionProcessor* processor_;
117};
118
119// Forward declare a couple classes we use.
120template<typename T>
121class ActionPipe;
122template<typename T>
123class ActionTraits;
124
125template<typename SubClass>
126class Action : public AbstractAction {
127 public:
Darin Petkovfbb40092010-07-29 17:05:50 -0700128 virtual ~Action() {}
rspangler@google.com49fdf182009-10-10 00:57:34 +0000129
130 // Attaches an input pipe to this Action. This is optional; an Action
131 // doesn't need to have an input pipe. The input pipe must be of the type
132 // of object that this class expects.
133 // This is generally called by ActionPipe::Bond()
134 void set_in_pipe(
135 // this type is a fancy way of saying: a shared_ptr to an
136 // ActionPipe<InputObjectType>.
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800137 const std::tr1::shared_ptr<ActionPipe<
rspangler@google.com49fdf182009-10-10 00:57:34 +0000138 typename ActionTraits<SubClass>::InputObjectType> >&
139 in_pipe) {
140 in_pipe_ = in_pipe;
141 }
142
143 // Attaches an output pipe to this Action. This is optional; an Action
144 // doesn't need to have an output pipe. The output pipe must be of the type
145 // of object that this class expects.
146 // This is generally called by ActionPipe::Bond()
147 void set_out_pipe(
148 // this type is a fancy way of saying: a shared_ptr to an
149 // ActionPipe<OutputObjectType>.
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800150 const std::tr1::shared_ptr<ActionPipe<
rspangler@google.com49fdf182009-10-10 00:57:34 +0000151 typename ActionTraits<SubClass>::OutputObjectType> >&
152 out_pipe) {
153 out_pipe_ = out_pipe;
154 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000155
rspangler@google.com49fdf182009-10-10 00:57:34 +0000156 // Returns true iff there is an associated input pipe. If there's an input
157 // pipe, there's an input object, but it may have been constructed with the
158 // default ctor if the previous action didn't call SetOutputObject().
159 bool HasInputObject() const { return in_pipe_.get(); }
160
161 // returns a const reference to the object in the input pipe.
162 const typename ActionTraits<SubClass>::InputObjectType& GetInputObject()
163 const {
164 CHECK(HasInputObject());
165 return in_pipe_->contents();
166 }
167
168 // Returns true iff there's an output pipe.
169 bool HasOutputPipe() const {
170 return out_pipe_.get();
171 }
172
173 // Copies the object passed into the output pipe. It will be accessible to
174 // the next Action via that action's input pipe (which is the same as this
175 // Action's output pipe).
176 void SetOutputObject(
177 const typename ActionTraits<SubClass>::OutputObjectType& out_obj) {
178 CHECK(HasOutputPipe());
179 out_pipe_->set_contents(out_obj);
180 }
181
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000182 // Returns a reference to the object sitting in the output pipe.
183 const typename ActionTraits<SubClass>::OutputObjectType& GetOutputObject() {
184 CHECK(HasOutputPipe());
185 return out_pipe_->contents();
186 }
187
Andrew de los Reyesf98bff82010-05-06 13:33:25 -0700188 protected:
rspangler@google.com49fdf182009-10-10 00:57:34 +0000189 // We use a shared_ptr to the pipe. shared_ptr objects destroy what they
190 // point to when the last such shared_ptr object dies. We consider the
191 // Actions on either end of a pipe to "own" the pipe. When the last Action
192 // of the two dies, the ActionPipe will die, too.
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800193 std::tr1::shared_ptr<
194 ActionPipe<typename ActionTraits<SubClass>::InputObjectType> >
rspangler@google.com49fdf182009-10-10 00:57:34 +0000195 in_pipe_;
Andrew de los Reyes4fe15d02009-12-10 19:01:36 -0800196 std::tr1::shared_ptr<
197 ActionPipe<typename ActionTraits<SubClass>::OutputObjectType> >
rspangler@google.com49fdf182009-10-10 00:57:34 +0000198 out_pipe_;
199};
200
201}; // namespace chromeos_update_engine
202
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000203#endif // CHROMEOS_PLATFORM_UPDATE_ENGINE_ACTION_H__