blob: d80af1ccc552ea29e4a95df4bd4af3d3546d550b [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.
#ifndef SHILL_HOOK_TABLE_H_
#define SHILL_HOOK_TABLE_H_
// HookTable provides a facility for starting a set of generic actions and
// reporting for their completion. For example, on shutdown, each service gets
// disconnected. A disconnect action may be instantaneous or it may require
// some time to complete. Users of this facility use the Add() function to
// provide a closure for starting an action. Users report the completion of an
// action. When an event occurs, the Run() function is called, which starts
// each action and sets a timer. Upon completion or timeout, Run() calls a
// user-supplied callback to notify the caller of the state of actions.
//
// Usage example. Add an action to a hook table like this:
//
// HookTable hook_table_(&event_dispatcher);
// Closure start_cb = Bind(&MyService::Disconnect, &my_service);
// hook_table_.Add("MyService", start_cb);
//
// The code that catches an event runs the actions of the hook table like this:
//
// Callback<void(const Error &)> done_cb =
// Bind(Manager::OnDisconnect, &manager);
// hook_table_.Run(kTimeout, done_cb);
//
// When |my_service| has completed its disconnect process,
// Manager::OnDisconnect() gets called with Error::kSuccess. If |my_service|
// does not finish its disconnect processing before kTimeout, then it gets
// called with kOperationTimeout.
#include <map>
#include <string>
#include <base/basictypes.h>
#include <base/callback.h>
#include <base/cancelable_callback.h>
#include <gtest/gtest_prod.h>
namespace shill {
class EventDispatcher;
class Error;
class HookTable {
public:
explicit HookTable(EventDispatcher *event_dispatcher);
~HookTable();
// Adds a closure to the hook table. |name| should be unique; otherwise, a
// previous closure by the same name will be replaced. |start| will be called
// when Run() is called.
void Add(const std::string &name, const base::Closure &start);
// Users call this function to report the completion of an action |name|.
void ActionComplete(const std::string &name);
// Removes the action associtated with |name| from the hook table. If |name|
// does not exist, the hook table is unchanged.
void Remove(const std::string &name);
// Runs the actions that have been added to the HookTable via Add(). It
// starts a timer for completion in |timeout_ms|. If all actions complete
// succesfully within the timeout period, |done| is called with a value of
// Error::kSuccess. Otherwise, it is called with Error::kOperationTimeout.
void Run(int timeout_ms,
const base::Callback<void(const Error &)> &done);
bool IsEmpty() const { return hook_table_.empty(); }
private:
friend class HookTableTest;
// For each action, there is a |start| callback which is stored in this
// structure.
struct HookAction {
HookAction(const base::Closure &start_cb)
: start(start_cb),
started(false),
completed(false) {}
const base::Closure start;
bool started;
bool completed;
};
// Each action is stored in this table. The key is |name| passed to Add().
typedef std::map<std::string, HookAction> HookTableMap;
// Returns true if all started actions have completed; false otherwise. If no
// actions have started, returns true.
bool AllActionsComplete();
// This function runs if all the actions do not complete before the timeout
// period. It invokes the user-supplied callback to Run() with an error value
// kOperationTimeout.
void ActionsTimedOut();
// Each action is stored in this table.
HookTableMap hook_table_;
// This is the user-supplied callback to Run().
base::Callback<void(const Error &)> done_cb_;
// This callback is creted in Run() and is queued to the event dispatcher to
// run after a timeout period. If all the actions complete before the
// timeout, then this callback is cancelled.
base::CancelableClosure timeout_cb_;
// Used for setting a timeout action to run in case all the actions do not
// complete in time.
EventDispatcher *const event_dispatcher_;
DISALLOW_COPY_AND_ASSIGN(HookTable);
};
} // namespace shill
#endif // SHILL_HOOK_TABLE_H_