blob: 237f13247d635031b50d25b3060b1882f4976c6d [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
9// polling for their completion. For example, on shutdown, each service gets
10// 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
12// provide a closure for starting an action and a callback for polling its
13// completion. When an event occurs, the Run() function is called, which starts
14// each action and polls for completion. Upon completion or timeout, Run()
15// calls a user-supplied callback to notify the caller of the state of actions.
16//
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);
21// Callback poll_cb = Bind(&MyService::IsConnected, &my_service);
22// hook_table_.Add("MyService", start_cb, poll_cb);
23//
24// The code that catches an event runs the actions of the hook table like this:
25//
26// Callback<void(const Error &)> done_cb =
27// Bind(Manager::OnDisconnect, &manager);
28// hook_table_.Run(kTimeout, done_cb);
29//
30// When |my_service| has completed its disconnect process,
31// Manager::OnDisconnect() gets called with Error::kSuccess. If |my_service|
32// does not finish its disconnect processing before kTimeout, then it gets
33// called with kOperationTimeout.
34
35#include <map>
36#include <string>
37
38#include <base/basictypes.h>
39#include <base/callback.h>
40#include <gtest/gtest_prod.h>
41
42namespace shill {
43class Error;
44class EventDispatcher;
45
46class HookTable {
47 public:
48 explicit HookTable(EventDispatcher *event_dispatcher);
49
50 // Adds a closure to the hook table. |name| should be unique; otherwise, a
51 // previous closure by the same name will NOT be replaced. |start| will be
52 // called when Run() is called. Run() will poll to see if the action has
53 // completed by calling |poll|, which should return true when the action has
54 // completed.
55 void Add(const std::string &name, const base::Closure &start,
56 const base::Callback<bool()> &poll);
57
58 // Runs the actions that have been added to the HookTable via Add(). It polls
59 // for completion up to |timeout_seconds|. If all actions complete within the
60 // timeout period, |done| is called with a value of Error::kSuccess.
61 // Otherwise, it is called with Error::kOperationTimeout.
62 void Run(int timeout_seconds,
63 const base::Callback<void(const Error &)> &done);
64
65 private:
66 FRIEND_TEST(HookTableTest, ActionTimesOut);
67 FRIEND_TEST(HookTableTest, DelayedAction);
68 FRIEND_TEST(HookTableTest, MultipleActionsAllSucceed);
69 FRIEND_TEST(HookTableTest, MultipleActionsAndOneTimesOut);
70
71 // The |timeout_seconds| passed to Run() is divided into |kPollIterations|,
72 // polled once iteration.
73 static const int kPollIterations;
74
75 // For each action, there is a |start| and a |poll| callback, which are stored
76 // in this structure.
77 struct HookCallbacks {
78 HookCallbacks(const base::Closure &s, const base::Callback<bool()> &p)
79 : start(s), poll(p) {}
80 const base::Closure start;
81 const base::Callback<bool()> poll;
82 };
83
84 // Each action is stored in this table. The key is |name| passed to Add().
85 typedef std::map<std::string, HookCallbacks> HookTableMap;
86
87 // Calls all the |poll| callbacks in |hook_table_|. If all of them return
88 // true, then |done| is called with Error::kSuccess. Otherwise, it queues
89 // itself in the |event_dispatcher_| to be called again later. It repeats
90 // this process up to |kPollIterations|, after which if an action still has
91 // not completed, |done| is called with Error::kOperationTimeout.
92 void PollActions(int timeout_seconds,
93 const base::Callback<void(const Error &)> &done);
94
95 // Each action is stored in this table.
96 HookTableMap hook_table_;
97
98 // Used for polling actions that do not complete immediately.
99 EventDispatcher *const event_dispatcher_;
100
101 // Counts the number of polling attempts.
102 int iteration_counter_;
103
104 DISALLOW_COPY_AND_ASSIGN(HookTable);
105};
106
107} // namespace shill
108
109#endif // SHILL_HOOK_TABLE_H_