|  | // Copyright 2014 The Chromium OS Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "buffet/async_event_sequencer.h" | 
|  |  | 
|  | namespace buffet { | 
|  |  | 
|  | namespace dbus_utils { | 
|  |  | 
|  | AsyncEventSequencer::AsyncEventSequencer() { } | 
|  | AsyncEventSequencer::~AsyncEventSequencer() { } | 
|  |  | 
|  | AsyncEventSequencer::Handler AsyncEventSequencer::GetHandler( | 
|  | const std::string& descriptive_message, bool failure_is_fatal) { | 
|  | CHECK(!started_) << "Cannot create handlers after OnAllTasksCompletedCall()"; | 
|  | int unique_registration_id = ++registration_counter_; | 
|  | outstanding_registrations_.insert(unique_registration_id); | 
|  | return base::Bind(&AsyncEventSequencer::HandleFinish, this, | 
|  | unique_registration_id, descriptive_message, | 
|  | failure_is_fatal); | 
|  | } | 
|  |  | 
|  | AsyncEventSequencer::ExportHandler AsyncEventSequencer::GetExportHandler( | 
|  | const std::string& interface_name, const std::string& method_name, | 
|  | const std::string& descriptive_message, bool failure_is_fatal) { | 
|  | auto finish_handler = GetHandler(descriptive_message, failure_is_fatal); | 
|  | return base::Bind(&AsyncEventSequencer::HandleDBusMethodExported, this, | 
|  | finish_handler, | 
|  | interface_name, | 
|  | method_name); | 
|  | } | 
|  |  | 
|  | void AsyncEventSequencer::OnAllTasksCompletedCall( | 
|  | std::vector<CompletionAction> actions) { | 
|  | CHECK(!started_) << "OnAllTasksCompletedCall called twice!"; | 
|  | started_ = true; | 
|  | completion_actions_.assign(actions.begin(), actions.end()); | 
|  | // All of our callbacks might have been called already. | 
|  | PossiblyRunCompletionActions(); | 
|  | } | 
|  |  | 
|  | namespace { | 
|  | void IgnoreSuccess(const AsyncEventSequencer::CompletionTask& task, | 
|  | bool /*success*/) { task.Run(); } | 
|  | }  // namespace | 
|  |  | 
|  | AsyncEventSequencer::CompletionAction AsyncEventSequencer::WrapCompletionTask( | 
|  | const CompletionTask& task) { | 
|  | return base::Bind(&IgnoreSuccess, task); | 
|  | } | 
|  |  | 
|  | void AsyncEventSequencer::HandleFinish(int registration_number, | 
|  | const std::string& error_message, | 
|  | bool failure_is_fatal, bool success) { | 
|  | RetireRegistration(registration_number); | 
|  | CheckForFailure(failure_is_fatal, success, error_message); | 
|  | PossiblyRunCompletionActions(); | 
|  | } | 
|  |  | 
|  | void AsyncEventSequencer::HandleDBusMethodExported( | 
|  | const AsyncEventSequencer::Handler& finish_handler, | 
|  | const std::string& expected_interface_name, | 
|  | const std::string& expected_method_name, | 
|  | const std::string& actual_interface_name, | 
|  | const std::string& actual_method_name, bool success) { | 
|  | CHECK_EQ(expected_method_name, actual_method_name) | 
|  | << "Exported DBus method '" << actual_method_name << "' " | 
|  | << "but expected '" << expected_method_name << "'"; | 
|  | CHECK_EQ(expected_interface_name, actual_interface_name) | 
|  | << "Exported method DBus interface '" << actual_interface_name << "' " | 
|  | << "but expected '" << expected_interface_name << "'"; | 
|  | finish_handler.Run(success); | 
|  | } | 
|  |  | 
|  |  | 
|  | void AsyncEventSequencer::RetireRegistration(int registration_number) { | 
|  | const size_t handlers_retired = outstanding_registrations_.erase( | 
|  | registration_number); | 
|  | CHECK_EQ(1, handlers_retired) | 
|  | << "Tried to retire invalid handler " << registration_number << ")"; | 
|  | } | 
|  |  | 
|  | void AsyncEventSequencer::CheckForFailure(bool failure_is_fatal, bool success, | 
|  | const std::string& error_message) { | 
|  | if (failure_is_fatal) { | 
|  | CHECK(success) << error_message; | 
|  | } | 
|  | if (!success) { | 
|  | LOG(ERROR) << error_message; | 
|  | had_failures_ = true; | 
|  | } | 
|  | } | 
|  |  | 
|  | void AsyncEventSequencer::PossiblyRunCompletionActions() { | 
|  | if (!started_ || !outstanding_registrations_.empty()) { | 
|  | // Don't run completion actions if we have any outstanding | 
|  | // Handlers outstanding or if any more handlers might | 
|  | // be scheduled in the future. | 
|  | return; | 
|  | } | 
|  | for (const auto& completion_action : completion_actions_) { | 
|  | // Should this be put on the message loop or run directly? | 
|  | completion_action.Run(!had_failures_); | 
|  | } | 
|  | // Discard our references to those actions. | 
|  | completion_actions_.clear(); | 
|  | } | 
|  |  | 
|  | }  // namespace dbus_utils | 
|  |  | 
|  | }  // namespace buffet |