blob: d80af1ccc552ea29e4a95df4bd4af3d3546d550b [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#ifndef SHILL_HOOK_TABLE_H_
6#define SHILL_HOOK_TABLE_H_
7
8// HookTable provides a facility for starting a set of generic actions and
Gary Moraina9fb3252012-05-31 12:05:31 -07009// reporting for their completion. For example, on shutdown, each service gets
Gary Morainf80ef062012-05-16 14:57:04 -070010// disconnected. A disconnect action may be instantaneous or it may require
11// some time to complete. Users of this facility use the Add() function to
Gary Moraina9fb3252012-05-31 12:05:31 -070012// provide a closure for starting an action. Users report the completion of an
13// action. When an event occurs, the Run() function is called, which starts
14// each action and sets a timer. Upon completion or timeout, Run() calls a
15// user-supplied callback to notify the caller of the state of actions.
Gary Morainf80ef062012-05-16 14:57:04 -070016//
17// Usage example. Add an action to a hook table like this:
18//
19// HookTable hook_table_(&event_dispatcher);
20// Closure start_cb = Bind(&MyService::Disconnect, &my_service);
Gary Moraina9fb3252012-05-31 12:05:31 -070021// hook_table_.Add("MyService", start_cb);
Gary Morainf80ef062012-05-16 14:57:04 -070022//
23// The code that catches an event runs the actions of the hook table like this:
24//
25// Callback<void(const Error &)> done_cb =
26// Bind(Manager::OnDisconnect, &manager);
27// hook_table_.Run(kTimeout, done_cb);
28//
29// When |my_service| has completed its disconnect process,
30// Manager::OnDisconnect() gets called with Error::kSuccess. If |my_service|
31// does not finish its disconnect processing before kTimeout, then it gets
32// called with kOperationTimeout.
33
34#include <map>
35#include <string>
36
37#include <base/basictypes.h>
38#include <base/callback.h>
Gary Moraina9fb3252012-05-31 12:05:31 -070039#include <base/cancelable_callback.h>
Gary Morainf80ef062012-05-16 14:57:04 -070040#include <gtest/gtest_prod.h>
41
42namespace shill {
Gary Morainf80ef062012-05-16 14:57:04 -070043class EventDispatcher;
Gary Moraina9fb3252012-05-31 12:05:31 -070044class Error;
Gary Morainf80ef062012-05-16 14:57:04 -070045
46class HookTable {
47 public:
48 explicit HookTable(EventDispatcher *event_dispatcher);
Gary Moraina9fb3252012-05-31 12:05:31 -070049 ~HookTable();
Gary Morainf80ef062012-05-16 14:57:04 -070050
51 // Adds a closure to the hook table. |name| should be unique; otherwise, a
Gary Moraina9fb3252012-05-31 12:05:31 -070052 // previous closure by the same name will be replaced. |start| will be called
53 // when Run() is called.
54 void Add(const std::string &name, const base::Closure &start);
Gary Morainf80ef062012-05-16 14:57:04 -070055
Gary Moraina9fb3252012-05-31 12:05:31 -070056 // Users call this function to report the completion of an action |name|.
57 void ActionComplete(const std::string &name);
58
59 // Removes the action associtated with |name| from the hook table. If |name|
60 // does not exist, the hook table is unchanged.
61 void Remove(const std::string &name);
62
63 // Runs the actions that have been added to the HookTable via Add(). It
64 // starts a timer for completion in |timeout_ms|. If all actions complete
65 // succesfully within the timeout period, |done| is called with a value of
66 // Error::kSuccess. Otherwise, it is called with Error::kOperationTimeout.
67 void Run(int timeout_ms,
Gary Morainf80ef062012-05-16 14:57:04 -070068 const base::Callback<void(const Error &)> &done);
69
Darin Petkov3ec55342012-09-28 14:04:44 +020070 bool IsEmpty() const { return hook_table_.empty(); }
71
Gary Morainf80ef062012-05-16 14:57:04 -070072 private:
Darin Petkov3ec55342012-09-28 14:04:44 +020073 friend class HookTableTest;
74
Gary Moraina9fb3252012-05-31 12:05:31 -070075 // For each action, there is a |start| callback which is stored in this
76 // structure.
77 struct HookAction {
78 HookAction(const base::Closure &start_cb)
79 : start(start_cb),
80 started(false),
81 completed(false) {}
Gary Morainf80ef062012-05-16 14:57:04 -070082 const base::Closure start;
Gary Moraina9fb3252012-05-31 12:05:31 -070083 bool started;
84 bool completed;
Gary Morainf80ef062012-05-16 14:57:04 -070085 };
86
87 // Each action is stored in this table. The key is |name| passed to Add().
Gary Moraina9fb3252012-05-31 12:05:31 -070088 typedef std::map<std::string, HookAction> HookTableMap;
Gary Morainf80ef062012-05-16 14:57:04 -070089
Gary Moraina9fb3252012-05-31 12:05:31 -070090 // Returns true if all started actions have completed; false otherwise. If no
91 // actions have started, returns true.
92 bool AllActionsComplete();
93
94 // This function runs if all the actions do not complete before the timeout
95 // period. It invokes the user-supplied callback to Run() with an error value
96 // kOperationTimeout.
97 void ActionsTimedOut();
Gary Morainf80ef062012-05-16 14:57:04 -070098
99 // Each action is stored in this table.
100 HookTableMap hook_table_;
101
Gary Moraina9fb3252012-05-31 12:05:31 -0700102 // This is the user-supplied callback to Run().
103 base::Callback<void(const Error &)> done_cb_;
Gary Morainf80ef062012-05-16 14:57:04 -0700104
Gary Moraina9fb3252012-05-31 12:05:31 -0700105 // This callback is creted in Run() and is queued to the event dispatcher to
106 // run after a timeout period. If all the actions complete before the
107 // timeout, then this callback is cancelled.
108 base::CancelableClosure timeout_cb_;
109
110 // Used for setting a timeout action to run in case all the actions do not
111 // complete in time.
112 EventDispatcher *const event_dispatcher_;
Gary Morainf80ef062012-05-16 14:57:04 -0700113
114 DISALLOW_COPY_AND_ASSIGN(HookTable);
115};
116
117} // namespace shill
118
119#endif // SHILL_HOOK_TABLE_H_