1 // 2 // Copyright (C) 2012 The Android Open Source Project 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 #ifndef SHILL_HOOK_TABLE_H_ 18 #define SHILL_HOOK_TABLE_H_ 19 20 // HookTable provides a facility for starting a set of generic actions and 21 // reporting for their completion. For example, on shutdown, each service gets 22 // disconnected. A disconnect action may be instantaneous or it may require 23 // some time to complete. Users of this facility use the Add() function to 24 // provide a closure for starting an action. Users report the completion of an 25 // action. When an event occurs, the Run() function is called, which starts 26 // each action and sets a timer. Upon completion or timeout, Run() calls a 27 // user-supplied callback to notify the caller of the state of actions. 28 // 29 // Usage example. Add an action to a hook table like this: 30 // 31 // HookTable hook_table_(&event_dispatcher); 32 // Closure start_callback = Bind(&MyService::Disconnect, &my_service); 33 // hook_table_.Add("MyService", start_callback); 34 // 35 // The code that catches an event runs the actions of the hook table like this: 36 // 37 // ResultCallback done_callback = Bind(Manager::OnDisconnect, &manager); 38 // hook_table_.Run(kTimeout, done_callback); 39 // 40 // When |my_service| has completed its disconnect process, 41 // Manager::OnDisconnect() gets called with Error::kSuccess. If |my_service| 42 // does not finish its disconnect processing before kTimeout, then it gets 43 // called with kOperationTimeout. 44 45 #include <map> 46 #include <string> 47 48 #include <base/cancelable_callback.h> 49 #include <base/macros.h> 50 #include <gtest/gtest_prod.h> 51 52 #include "shill/callbacks.h" 53 54 namespace shill { 55 class EventDispatcher; 56 class Error; 57 58 class HookTable { 59 public: 60 explicit HookTable(EventDispatcher* event_dispatcher); 61 ~HookTable(); 62 63 // Adds a closure to the hook table. |name| should be unique; otherwise, a 64 // previous closure by the same name will be replaced. |start| will be called 65 // when Run() is called. 66 void Add(const std::string& name, const base::Closure& start); 67 68 // Users call this function to report the completion of an action |name|. 69 void ActionComplete(const std::string& name); 70 71 // Removes the action associated with |name| from the hook table. If |name| 72 // does not exist, the hook table is unchanged. 73 void Remove(const std::string& name); 74 75 // Runs the actions that have been added to the HookTable via Add(). It 76 // starts a timer for completion in |timeout_ms|. If all actions complete 77 // successfully within the timeout period, |done| is called with a value of 78 // Error::kSuccess. Otherwise, it is called with Error::kOperationTimeout. 79 void Run(int timeout_ms, const ResultCallback& done); 80 81 bool IsEmpty() const { return hook_table_.empty(); } 82 83 private: 84 friend class HookTableTest; 85 86 // For each action, there is a |start| callback which is stored in this 87 // structure. 88 struct HookAction { 89 explicit HookAction(const base::Closure& start_callback) 90 : start_callback(start_callback), 91 started(false), 92 completed(false) {} 93 const base::Closure start_callback; 94 bool started; 95 bool completed; 96 }; 97 98 // Each action is stored in this table. The key is |name| passed to Add(). 99 typedef std::map<std::string, HookAction> HookTableMap; 100 101 // Returns true if all started actions have completed; false otherwise. If no 102 // actions have started, returns true. 103 bool AllActionsComplete() const; 104 105 // This function runs if all the actions do not complete before the timeout 106 // period. It invokes the user-supplied callback to Run() with an error value 107 // kOperationTimeout. 108 void ActionsTimedOut(); 109 110 // Each action is stored in this table. 111 HookTableMap hook_table_; 112 113 // This is the user-supplied callback to Run(). 114 ResultCallback done_callback_; 115 116 // This callback is created in Run() and is queued to the event dispatcher to 117 // run after a timeout period. If all the actions complete before the 118 // timeout, then this callback is canceled. 119 base::CancelableClosure timeout_callback_; 120 121 // Used for setting a timeout action to run in case all the actions do not 122 // complete in time. 123 EventDispatcher* const event_dispatcher_; 124 125 DISALLOW_COPY_AND_ASSIGN(HookTable); 126 }; 127 128 } // namespace shill 129 130 #endif // SHILL_HOOK_TABLE_H_ 131