blob: 8d5f3ab93c66acca3aa39d7c4bea6608df9216f3 [file] [log] [blame]
Gary Morainf80ef062012-05-16 14:57:04 -07001// Copyright (c) 2012 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#include "shill/hook_table.h"
6
Ben Chan255f5652014-06-03 22:14:15 -07007#include <list>
Gary Morainf80ef062012-05-16 14:57:04 -07008#include <string>
9
10#include <base/bind.h>
11#include <base/callback.h>
Gary Moraina9fb3252012-05-31 12:05:31 -070012#include <base/cancelable_callback.h>
Gary Morainf80ef062012-05-16 14:57:04 -070013
14#include "shill/error.h"
15#include "shill/event_dispatcher.h"
mukesh agrawalb1136662013-10-14 16:39:38 -070016#include "shill/logging.h"
Gary Morainf80ef062012-05-16 14:57:04 -070017
18using base::Bind;
Gary Moraina9fb3252012-05-31 12:05:31 -070019using base::Callback;
Gary Morainf80ef062012-05-16 14:57:04 -070020using base::Closure;
21using base::ConstRef;
22using base::Unretained;
Ben Chan255f5652014-06-03 22:14:15 -070023using std::list;
Gary Morainf80ef062012-05-16 14:57:04 -070024using std::string;
25
26namespace shill {
27
Gary Morainf80ef062012-05-16 14:57:04 -070028HookTable::HookTable(EventDispatcher *event_dispatcher)
Gary Moraina9fb3252012-05-31 12:05:31 -070029 : event_dispatcher_(event_dispatcher) {}
Gary Morainf80ef062012-05-16 14:57:04 -070030
Ben Chan255f5652014-06-03 22:14:15 -070031void HookTable::Add(const string &name, const Closure &start) {
Gary Moraina9fb3252012-05-31 12:05:31 -070032 Remove(name);
Gary Morainf80ef062012-05-16 14:57:04 -070033 hook_table_.insert(
Gary Moraina9fb3252012-05-31 12:05:31 -070034 HookTableMap::value_type(name, HookAction(start)));
Gary Morainf80ef062012-05-16 14:57:04 -070035}
36
Gary Moraina9fb3252012-05-31 12:05:31 -070037HookTable::~HookTable() {
38 timeout_cb_.Cancel();
39}
40
41void HookTable::Remove(const std::string &name) {
42 HookTableMap::iterator it = hook_table_.find(name);
43 if (it != hook_table_.end()) {
44 hook_table_.erase(it);
Gary Morainf80ef062012-05-16 14:57:04 -070045 }
Gary Morainf80ef062012-05-16 14:57:04 -070046}
47
Gary Moraina9fb3252012-05-31 12:05:31 -070048void HookTable::ActionComplete(const std::string &name) {
mukesh agrawalb1136662013-10-14 16:39:38 -070049 SLOG(Manager, 2) << __func__ << ": " << name;
Gary Moraina9fb3252012-05-31 12:05:31 -070050 HookTableMap::iterator it = hook_table_.find(name);
51 if (it != hook_table_.end()) {
52 HookAction *action = &it->second;
53 if (action->started && !action->completed) {
54 action->completed = true;
Gary Morainf80ef062012-05-16 14:57:04 -070055 }
56 }
Gary Moraina9fb3252012-05-31 12:05:31 -070057 if (AllActionsComplete() && !done_cb_.is_null()) {
58 timeout_cb_.Cancel();
59 done_cb_.Run(Error(Error::kSuccess));
60 done_cb_.Reset();
61 }
62}
Gary Morainf80ef062012-05-16 14:57:04 -070063
Gary Moraina9fb3252012-05-31 12:05:31 -070064void HookTable::Run(int timeout_ms,
65 const Callback<void(const Error &)> &done) {
mukesh agrawalb1136662013-10-14 16:39:38 -070066 SLOG(Manager, 2) << __func__;
Gary Moraina9fb3252012-05-31 12:05:31 -070067 if (hook_table_.empty()) {
Gary Morainf80ef062012-05-16 14:57:04 -070068 done.Run(Error(Error::kSuccess));
69 return;
70 }
Gary Moraina9fb3252012-05-31 12:05:31 -070071 done_cb_ = done;
72 timeout_cb_.Reset(Bind(&HookTable::ActionsTimedOut, Unretained(this)));
73 event_dispatcher_->PostDelayedTask(timeout_cb_.callback(), timeout_ms);
Gary Morainf80ef062012-05-16 14:57:04 -070074
Gary Moraina9fb3252012-05-31 12:05:31 -070075 // Mark all actions as having started before we execute any actions.
76 // Otherwise, if the first action completes inline, its call to
77 // ActionComplete() will cause the |done| callback to be invoked before the
78 // rest of the actions get started.
Ben Chan255f5652014-06-03 22:14:15 -070079 //
80 // An action that completes inline could call HookTable::Remove(), which
81 // modifies |hook_table_|. It is thus not safe to iterate through
82 // |hook_table_| to execute the actions. Instead, we keep a list of start
83 // callback of each action and iterate through that to invoke the callback.
84 list<Closure> action_start_callbacks;
Paul Stewart6db7b242014-05-02 15:34:21 -070085 for (auto &hook_entry : hook_table_) {
86 HookAction *action = &hook_entry.second;
Ben Chan255f5652014-06-03 22:14:15 -070087 action_start_callbacks.push_back(action->start);
Gary Moraina9fb3252012-05-31 12:05:31 -070088 action->started = true;
89 action->completed = false;
Gary Morainf80ef062012-05-16 14:57:04 -070090 }
Gary Moraina9fb3252012-05-31 12:05:31 -070091 // Now start the actions.
Ben Chan255f5652014-06-03 22:14:15 -070092 for (auto &callback : action_start_callbacks) {
93 callback.Run();
Gary Moraina9fb3252012-05-31 12:05:31 -070094 }
95}
Gary Morainf80ef062012-05-16 14:57:04 -070096
Gary Moraina9fb3252012-05-31 12:05:31 -070097bool HookTable::AllActionsComplete() {
mukesh agrawalb1136662013-10-14 16:39:38 -070098 SLOG(Manager, 2) << __func__;
Gary Moraina9fb3252012-05-31 12:05:31 -070099 for (HookTableMap::const_iterator it = hook_table_.begin();
100 it != hook_table_.end(); ++it) {
101 const HookAction &action = it->second;
102 if (action.started && !action.completed) {
103 return false;
104 }
105 }
106 return true;
107}
108
109void HookTable::ActionsTimedOut() {
110 done_cb_.Run(Error(Error::kOperationTimeout));
Darin Petkov3ec55342012-09-28 14:04:44 +0200111 done_cb_.Reset();
Gary Morainf80ef062012-05-16 14:57:04 -0700112}
113
114} // namespace shill