Gary Morain | f80ef06 | 2012-05-16 14:57:04 -0700 | [diff] [blame] | 1 | // 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 Morain | a9fb325 | 2012-05-31 12:05:31 -0700 | [diff] [blame^] | 9 | // reporting for their completion. For example, on shutdown, each service gets |
Gary Morain | f80ef06 | 2012-05-16 14:57:04 -0700 | [diff] [blame] | 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 |
Gary Morain | a9fb325 | 2012-05-31 12:05:31 -0700 | [diff] [blame^] | 12 | // 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 Morain | f80ef06 | 2012-05-16 14:57:04 -0700 | [diff] [blame] | 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); |
Gary Morain | a9fb325 | 2012-05-31 12:05:31 -0700 | [diff] [blame^] | 21 | // hook_table_.Add("MyService", start_cb); |
Gary Morain | f80ef06 | 2012-05-16 14:57:04 -0700 | [diff] [blame] | 22 | // |
| 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 Morain | a9fb325 | 2012-05-31 12:05:31 -0700 | [diff] [blame^] | 39 | #include <base/cancelable_callback.h> |
Gary Morain | f80ef06 | 2012-05-16 14:57:04 -0700 | [diff] [blame] | 40 | #include <gtest/gtest_prod.h> |
| 41 | |
| 42 | namespace shill { |
Gary Morain | f80ef06 | 2012-05-16 14:57:04 -0700 | [diff] [blame] | 43 | class EventDispatcher; |
Gary Morain | a9fb325 | 2012-05-31 12:05:31 -0700 | [diff] [blame^] | 44 | class Error; |
Gary Morain | f80ef06 | 2012-05-16 14:57:04 -0700 | [diff] [blame] | 45 | |
| 46 | class HookTable { |
| 47 | public: |
| 48 | explicit HookTable(EventDispatcher *event_dispatcher); |
Gary Morain | a9fb325 | 2012-05-31 12:05:31 -0700 | [diff] [blame^] | 49 | ~HookTable(); |
Gary Morain | f80ef06 | 2012-05-16 14:57:04 -0700 | [diff] [blame] | 50 | |
| 51 | // Adds a closure to the hook table. |name| should be unique; otherwise, a |
Gary Morain | a9fb325 | 2012-05-31 12:05:31 -0700 | [diff] [blame^] | 52 | // 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 Morain | f80ef06 | 2012-05-16 14:57:04 -0700 | [diff] [blame] | 55 | |
Gary Morain | a9fb325 | 2012-05-31 12:05:31 -0700 | [diff] [blame^] | 56 | // 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 Morain | f80ef06 | 2012-05-16 14:57:04 -0700 | [diff] [blame] | 68 | const base::Callback<void(const Error &)> &done); |
| 69 | |
| 70 | private: |
Gary Morain | a9fb325 | 2012-05-31 12:05:31 -0700 | [diff] [blame^] | 71 | // For each action, there is a |start| callback which is stored in this |
| 72 | // structure. |
| 73 | struct HookAction { |
| 74 | HookAction(const base::Closure &start_cb) |
| 75 | : start(start_cb), |
| 76 | started(false), |
| 77 | completed(false) {} |
Gary Morain | f80ef06 | 2012-05-16 14:57:04 -0700 | [diff] [blame] | 78 | const base::Closure start; |
Gary Morain | a9fb325 | 2012-05-31 12:05:31 -0700 | [diff] [blame^] | 79 | bool started; |
| 80 | bool completed; |
Gary Morain | f80ef06 | 2012-05-16 14:57:04 -0700 | [diff] [blame] | 81 | }; |
| 82 | |
| 83 | // Each action is stored in this table. The key is |name| passed to Add(). |
Gary Morain | a9fb325 | 2012-05-31 12:05:31 -0700 | [diff] [blame^] | 84 | typedef std::map<std::string, HookAction> HookTableMap; |
Gary Morain | f80ef06 | 2012-05-16 14:57:04 -0700 | [diff] [blame] | 85 | |
Gary Morain | a9fb325 | 2012-05-31 12:05:31 -0700 | [diff] [blame^] | 86 | // Returns true if all started actions have completed; false otherwise. If no |
| 87 | // actions have started, returns true. |
| 88 | bool AllActionsComplete(); |
| 89 | |
| 90 | // This function runs if all the actions do not complete before the timeout |
| 91 | // period. It invokes the user-supplied callback to Run() with an error value |
| 92 | // kOperationTimeout. |
| 93 | void ActionsTimedOut(); |
Gary Morain | f80ef06 | 2012-05-16 14:57:04 -0700 | [diff] [blame] | 94 | |
| 95 | // Each action is stored in this table. |
| 96 | HookTableMap hook_table_; |
| 97 | |
Gary Morain | a9fb325 | 2012-05-31 12:05:31 -0700 | [diff] [blame^] | 98 | // This is the user-supplied callback to Run(). |
| 99 | base::Callback<void(const Error &)> done_cb_; |
Gary Morain | f80ef06 | 2012-05-16 14:57:04 -0700 | [diff] [blame] | 100 | |
Gary Morain | a9fb325 | 2012-05-31 12:05:31 -0700 | [diff] [blame^] | 101 | // This callback is creted in Run() and is queued to the event dispatcher to |
| 102 | // run after a timeout period. If all the actions complete before the |
| 103 | // timeout, then this callback is cancelled. |
| 104 | base::CancelableClosure timeout_cb_; |
| 105 | |
| 106 | // Used for setting a timeout action to run in case all the actions do not |
| 107 | // complete in time. |
| 108 | EventDispatcher *const event_dispatcher_; |
Gary Morain | f80ef06 | 2012-05-16 14:57:04 -0700 | [diff] [blame] | 109 | |
| 110 | DISALLOW_COPY_AND_ASSIGN(HookTable); |
| 111 | }; |
| 112 | |
| 113 | } // namespace shill |
| 114 | |
| 115 | #endif // SHILL_HOOK_TABLE_H_ |