blob: ed68f6afac75ba2c96460ce5347c7ad722f99668 [file] [log] [blame]
mukesh agrawal46c27cc2013-07-10 16:39:10 -07001// Copyright (c) 2013 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
5#ifndef SHILL_RESULT_AGGREGATOR_H_
6#define SHILL_RESULT_AGGREGATOR_H_
7
Samuel Tan7c1aacb2014-09-15 17:13:40 -07008#include <base/cancelable_callback.h>
Ben Chancc67c522014-09-03 07:19:18 -07009#include <base/macros.h>
mukesh agrawal46c27cc2013-07-10 16:39:10 -070010#include <base/memory/ref_counted.h>
11
12#include "shill/callbacks.h"
13#include "shill/error.h"
14
15namespace shill {
16
Samuel Tan7c1aacb2014-09-15 17:13:40 -070017class EventDispatcher;
18
mukesh agrawal46c27cc2013-07-10 16:39:10 -070019// The ResultAggregator is used to aggregate the result of multiple
20// asynchronous operations. To use: construct a ResultAggregator, and
Samuel Tan7c1aacb2014-09-15 17:13:40 -070021// Bind its ReportResult methods to some Callbacks. The ResultAggregator
22// can also be constructed with an EventDispatcher pointer and timeout delay if
23// we want to wait for a limited period of time for asynchronous operations
24// to complete.
mukesh agrawal46c27cc2013-07-10 16:39:10 -070025//
26// When the Callbacks are destroyed, they will drop their references
Samuel Tanfbe8d2b2014-09-15 20:23:59 -070027// to the ResultAggregator. When all references to the ResultAggregator are
28// destroyed, or if a timeout occurs, the ResultAggregator will invoke
29// |callback_|. |callback_| will only be invoked exactly once by whichever of
30// these two events occurs first.
mukesh agrawal46c27cc2013-07-10 16:39:10 -070031//
Samuel Tanfbe8d2b2014-09-15 20:23:59 -070032// |callback_| will see Error type of Success if all Callbacks reported
33// Success to ResultAggregator. If the timeout occurs, |callback_| will see
34// Error type of OperationTimeout. Otherwise, |callback_| will see the first of
35// the Errors reported to ResultAggregator.
36//
37// Note: If no callbacks invoked ReportResult and the ResultAggregator is
38// destructed (before timing out), the ResultAggregator will be destructed
39// silently and will not invoke |callback_|. This can cause unexpected
40// behavior if the user expects |callback_| to be invoked after the
41// result_aggregator goes out of scope. For example:
42//
43// void Manager::Foo() {
44// auto result_aggregator(make_scoped_refptr(new ResultAggregator(
45// Bind(&Manager::Func, AsWeakPtr()), dispatcher_, 1000)));
46// if (condition) {
47// LOG(ERROR) << "Failed!"
48// return;
49// }
50// ResultCallback aggregator_callback(
51// Bind(&ResultAggregator::ReportResult, result_aggregator));
52// devices_[0]->OnBeforeSuspend(aggregator_callback);
53// }
54//
55// If |condition| is true and the function returns without passing the
56// reference to |result_aggregator| to devices_[0], |result_aggregator| will
57// be destructed upon returning from Manager::Foo and will never call
58// Manager::Func(). This is problematic if the owner of |result_aggregator|
59// expects Manager::Func to be called when |result_aggregator| goes out of
60// scope.
61//
62// Another anomaly that can occur is it the ResultCallback that is being
63// passed around is allowed to go out to scope without being run. If at least
64// one object ran the ResultCallback, the ResultAggregator will invoke
65// |callback_| upon going out of scope, even though there exists an object
66// that was passed a ResultCallback but did not actually run it. This is
67// incorrect behavior, as we assume that |callback_| will only be run if
68// the ResultAggregator times out or if all objects that were passed the
69// ResultCallback run it.
70//
71// In order to ensure that ResultAggregator behaves as it is meant to, follow
72// these conventions when using it:
73// 1) Always run any ResultCallback that is passed around before letting it
74// go out of scope.
75// 2) If the ResultAggregator will go out of scope without passing any
76// ResultCallback objects (i.e. references to itself) to other objects,
77// invoke the callback the ResultAggregator was constructed with directly
78// before letting ResultAggregator go out of scope.
79
mukesh agrawal46c27cc2013-07-10 16:39:10 -070080class ResultAggregator : public base::RefCounted<ResultAggregator> {
81 public:
Paul Stewart1a212a62015-06-16 13:13:10 -070082 explicit ResultAggregator(const ResultCallback& callback);
83 ResultAggregator(const ResultCallback& callback, EventDispatcher* dispatcher,
Samuel Tan7c1aacb2014-09-15 17:13:40 -070084 int timeout_milliseconds);
mukesh agrawal46c27cc2013-07-10 16:39:10 -070085 virtual ~ResultAggregator();
86
Paul Stewart1a212a62015-06-16 13:13:10 -070087 void ReportResult(const Error& error);
mukesh agrawal46c27cc2013-07-10 16:39:10 -070088
89 private:
Samuel Tan7c1aacb2014-09-15 17:13:40 -070090 // Callback for timeout registered with EventDispatcher.
91 void Timeout();
92
93 base::WeakPtrFactory<ResultAggregator> weak_ptr_factory_;
mukesh agrawal46c27cc2013-07-10 16:39:10 -070094 const ResultCallback callback_;
Samuel Tan7c1aacb2014-09-15 17:13:40 -070095 base::CancelableClosure timeout_callback_;
mukesh agrawal46c27cc2013-07-10 16:39:10 -070096 bool got_result_;
Samuel Tan7c1aacb2014-09-15 17:13:40 -070097 bool timed_out_;
mukesh agrawal46c27cc2013-07-10 16:39:10 -070098 Error error_;
99
100 DISALLOW_COPY_AND_ASSIGN(ResultAggregator);
101};
102
103} // namespace shill
104
105#endif // SHILL_RESULT_AGGREGATOR_H_