1 // 2 // Copyright (C) 2013 The Android Open Source Project 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 #ifndef SHILL_RESULT_AGGREGATOR_H_ 18 #define SHILL_RESULT_AGGREGATOR_H_ 19 20 #include <base/cancelable_callback.h> 21 #include <base/macros.h> 22 #include <base/memory/ref_counted.h> 23 24 #include "shill/callbacks.h" 25 #include "shill/error.h" 26 27 namespace shill { 28 29 class EventDispatcher; 30 31 // The ResultAggregator is used to aggregate the result of multiple 32 // asynchronous operations. To use: construct a ResultAggregator, and 33 // Bind its ReportResult methods to some Callbacks. The ResultAggregator 34 // can also be constructed with an EventDispatcher pointer and timeout delay if 35 // we want to wait for a limited period of time for asynchronous operations 36 // to complete. 37 // 38 // When the Callbacks are destroyed, they will drop their references 39 // to the ResultAggregator. When all references to the ResultAggregator are 40 // destroyed, or if a timeout occurs, the ResultAggregator will invoke 41 // |callback_|. |callback_| will only be invoked exactly once by whichever of 42 // these two events occurs first. 43 // 44 // |callback_| will see Error type of Success if all Callbacks reported 45 // Success to ResultAggregator. If the timeout occurs, |callback_| will see 46 // Error type of OperationTimeout. Otherwise, |callback_| will see the first of 47 // the Errors reported to ResultAggregator. 48 // 49 // Note: If no callbacks invoked ReportResult and the ResultAggregator is 50 // destructed (before timing out), the ResultAggregator will be destructed 51 // silently and will not invoke |callback_|. This can cause unexpected 52 // behavior if the user expects |callback_| to be invoked after the 53 // result_aggregator goes out of scope. For example: 54 // 55 // void Manager::Foo() { 56 // auto result_aggregator(make_scoped_refptr(new ResultAggregator( 57 // Bind(&Manager::Func, AsWeakPtr()), dispatcher_, 1000))); 58 // if (condition) { 59 // LOG(ERROR) << "Failed!" 60 // return; 61 // } 62 // ResultCallback aggregator_callback( 63 // Bind(&ResultAggregator::ReportResult, result_aggregator)); 64 // devices_[0]->OnBeforeSuspend(aggregator_callback); 65 // } 66 // 67 // If |condition| is true and the function returns without passing the 68 // reference to |result_aggregator| to devices_[0], |result_aggregator| will 69 // be destructed upon returning from Manager::Foo and will never call 70 // Manager::Func(). This is problematic if the owner of |result_aggregator| 71 // expects Manager::Func to be called when |result_aggregator| goes out of 72 // scope. 73 // 74 // Another anomaly that can occur is it the ResultCallback that is being 75 // passed around is allowed to go out to scope without being run. If at least 76 // one object ran the ResultCallback, the ResultAggregator will invoke 77 // |callback_| upon going out of scope, even though there exists an object 78 // that was passed a ResultCallback but did not actually run it. This is 79 // incorrect behavior, as we assume that |callback_| will only be run if 80 // the ResultAggregator times out or if all objects that were passed the 81 // ResultCallback run it. 82 // 83 // In order to ensure that ResultAggregator behaves as it is meant to, follow 84 // these conventions when using it: 85 // 1) Always run any ResultCallback that is passed around before letting it 86 // go out of scope. 87 // 2) If the ResultAggregator will go out of scope without passing any 88 // ResultCallback objects (i.e. references to itself) to other objects, 89 // invoke the callback the ResultAggregator was constructed with directly 90 // before letting ResultAggregator go out of scope. 91 92 class ResultAggregator : public base::RefCounted<ResultAggregator> { 93 public: 94 explicit ResultAggregator(const ResultCallback& callback); 95 ResultAggregator(const ResultCallback& callback, EventDispatcher* dispatcher, 96 int timeout_milliseconds); 97 virtual ~ResultAggregator(); 98 99 void ReportResult(const Error& error); 100 101 private: 102 // Callback for timeout registered with EventDispatcher. 103 void Timeout(); 104 105 base::WeakPtrFactory<ResultAggregator> weak_ptr_factory_; 106 const ResultCallback callback_; 107 base::CancelableClosure timeout_callback_; 108 bool got_result_; 109 bool timed_out_; 110 Error error_; 111 112 DISALLOW_COPY_AND_ASSIGN(ResultAggregator); 113 }; 114 115 } // namespace shill 116 117 #endif // SHILL_RESULT_AGGREGATOR_H_ 118