blob: d04842b51ef628e4bedb0c557d62fc1f95a6fe93 [file] [log] [blame]
// Copyright (c) 2012 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 "shill/hook_table.h"
#include <string>
#include <base/bind.h>
#include <base/callback.h>
#include <base/cancelable_callback.h>
#include "shill/error.h"
#include "shill/event_dispatcher.h"
using base::Bind;
using base::Callback;
using base::Closure;
using base::ConstRef;
using base::Unretained;
using std::string;
namespace shill {
HookTable::HookTable(EventDispatcher *event_dispatcher)
: event_dispatcher_(event_dispatcher) {}
void HookTable::Add(const string &name, const base::Closure &start) {
Remove(name);
hook_table_.insert(
HookTableMap::value_type(name, HookAction(start)));
}
HookTable::~HookTable() {
timeout_cb_.Cancel();
}
void HookTable::Remove(const std::string &name) {
HookTableMap::iterator it = hook_table_.find(name);
if (it != hook_table_.end()) {
hook_table_.erase(it);
}
}
void HookTable::ActionComplete(const std::string &name) {
HookTableMap::iterator it = hook_table_.find(name);
if (it != hook_table_.end()) {
HookAction *action = &it->second;
if (action->started && !action->completed) {
action->completed = true;
}
}
if (AllActionsComplete() && !done_cb_.is_null()) {
timeout_cb_.Cancel();
done_cb_.Run(Error(Error::kSuccess));
done_cb_.Reset();
}
}
void HookTable::Run(int timeout_ms,
const Callback<void(const Error &)> &done) {
if (hook_table_.empty()) {
done.Run(Error(Error::kSuccess));
return;
}
done_cb_ = done;
timeout_cb_.Reset(Bind(&HookTable::ActionsTimedOut, Unretained(this)));
event_dispatcher_->PostDelayedTask(timeout_cb_.callback(), timeout_ms);
// Mark all actions as having started before we execute any actions.
// Otherwise, if the first action completes inline, its call to
// ActionComplete() will cause the |done| callback to be invoked before the
// rest of the actions get started.
for (HookTableMap::iterator it = hook_table_.begin();
it != hook_table_.end(); ++it) {
HookAction *action = &it->second;
action->started = true;
action->completed = false;
}
// Now start the actions.
for (HookTableMap::iterator it = hook_table_.begin();
it != hook_table_.end(); ++it) {
it->second.start.Run();
}
}
bool HookTable::AllActionsComplete() {
for (HookTableMap::const_iterator it = hook_table_.begin();
it != hook_table_.end(); ++it) {
const HookAction &action = it->second;
if (action.started && !action.completed) {
return false;
}
}
return true;
}
void HookTable::ActionsTimedOut() {
done_cb_.Run(Error(Error::kOperationTimeout));
done_cb_.Reset();
}
} // namespace shill