1 // Copyright 2017 The Chromium 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 MOJO_PUBLIC_CPP_SYSTEM_SIMPLE_WATCHER_H_ 6 #define MOJO_PUBLIC_CPP_SYSTEM_SIMPLE_WATCHER_H_ 7 8 #include "base/bind.h" 9 #include "base/callback.h" 10 #include "base/location.h" 11 #include "base/macros.h" 12 #include "base/memory/ref_counted.h" 13 #include "base/memory/weak_ptr.h" 14 #include "base/sequence_checker.h" 15 #include "base/threading/sequenced_task_runner_handle.h" 16 #include "mojo/public/c/system/types.h" 17 #include "mojo/public/cpp/system/handle_signals_state.h" 18 #include "mojo/public/cpp/system/system_export.h" 19 #include "mojo/public/cpp/system/trap.h" 20 21 namespace base { 22 class SequencedTaskRunner; 23 } 24 25 namespace mojo { 26 27 // This provides a convenient sequence-bound watcher implementation to safely 28 // watch a single handle, dispatching state change notifications to an arbitrary 29 // SequencedTaskRunner running on the same sequence as the SimpleWatcher. 30 // 31 // SimpleWatcher exposes the concept of "arming" from the low-level Watcher API. 32 // In general, a SimpleWatcher must be "armed" in order to dispatch a single 33 // notification, and must then be rearmed before it will dispatch another. For 34 // more details, see the documentation for ArmingPolicy and the Arm() and 35 // ArmOrNotify() methods below. 36 class MOJO_CPP_SYSTEM_EXPORT SimpleWatcher { 37 public: 38 // A callback to be called any time a watched handle changes state in some 39 // interesting way. The |result| argument indicates one of the following 40 // conditions depending on its value: 41 // 42 // |MOJO_RESULT_OK|: One or more of the signals being watched is satisfied. 43 // 44 // |MOJO_RESULT_FAILED_PRECONDITION|: None of the signals being watched can 45 // ever be satisfied again. 46 // 47 // |MOJO_RESULT_CANCELLED|: The watched handle has been closed. No further 48 // notifications will be fired, as this equivalent to an implicit 49 // CancelWatch(). 50 // 51 // Note that unlike the first two conditions, this callback may be invoked 52 // with |MOJO_RESULT_CANCELLED| even while the SimpleWatcher is disarmed. 53 using ReadyCallback = base::RepeatingCallback<void(MojoResult result)>; 54 55 // Like above but also receives the last known handle signal state at the time 56 // of the notification. 57 using ReadyCallbackWithState = 58 base::RepeatingCallback<void(MojoResult result, 59 const HandleSignalsState& state)>; 60 61 // Selects how this SimpleWatcher is to be armed. 62 enum class ArmingPolicy { 63 // The SimpleWatcher is armed automatically on Watch() and rearmed again 64 // after every invocation of the ReadyCallback. There is no need to manually 65 // call Arm() on a SimpleWatcher using this policy. This mode is equivalent 66 // to calling ArmOrNotify() once after Watch() and once again after every 67 // dispatched notification in MANUAL mode. 68 // 69 // This provides a reasonable approximation of edge-triggered behavior, 70 // mitigating (but not completely eliminating) the potential for redundant 71 // notifications. 72 // 73 // NOTE: It is important when using AUTOMATIC policy that your ReadyCallback 74 // always attempt to change the state of the handle (e.g. read available 75 // messages on a message pipe.) Otherwise this will result in a potentially 76 // large number of avoidable redundant tasks. 77 // 78 // For perfect edge-triggered behavior, use MANUAL policy and manually Arm() 79 // the SimpleWatcher as soon as it becomes possible to do so again. 80 AUTOMATIC, 81 82 // The SimpleWatcher is never armed automatically. Arm() or ArmOrNotify() 83 // must be called manually before any non-cancellation notification can be 84 // dispatched to the ReadyCallback. See the documentation for Arm() and 85 // ArmNotify() methods below for more details. 86 MANUAL, 87 }; 88 89 SimpleWatcher(const base::Location& from_here, 90 ArmingPolicy arming_policy, 91 scoped_refptr<base::SequencedTaskRunner> runner = 92 base::SequencedTaskRunnerHandle::Get()); 93 ~SimpleWatcher(); 94 95 // Indicates if the SimpleWatcher is currently watching a handle. 96 bool IsWatching() const; 97 98 // Starts watching |handle|. A SimpleWatcher may only watch one handle at a 99 // time, but it is safe to call this more than once as long as the previous 100 // watch has been cancelled (i.e. |IsWatching()| returns |false|.) 101 // 102 // If |handle| is not a valid watchable (message or data pipe) handle or 103 // |signals| is not a valid set of signals to watch, this returns 104 // |MOJO_RESULT_INVALID_ARGUMENT|. 105 // 106 // Otherwise |MOJO_RESULT_OK| is returned and the handle will be watched until 107 // either |handle| is closed, the SimpleWatcher is destroyed, or Cancel() is 108 // explicitly called. 109 // 110 // Once the watch is started, |callback| may be called at any time on the 111 // current sequence until |Cancel()| is called or the handle is closed. Note 112 // that |callback| can be called for results other than 113 // |MOJO_RESULT_CANCELLED| only if the SimpleWatcher is currently armed. Use 114 // ArmingPolicy to configure how a SimpleWatcher is armed. 115 // 116 // |MOJO_RESULT_CANCELLED| may be dispatched even while the SimpleWatcher 117 // is disarmed, and no further notifications will be dispatched after that. 118 // 119 // Destroying the SimpleWatcher implicitly calls |Cancel()|. 120 MojoResult Watch(Handle handle, 121 MojoHandleSignals signals, 122 MojoTriggerCondition condition, 123 const ReadyCallbackWithState& callback); 124 125 // DEPRECATED: Please use the above signature instead. 126 // 127 // This watches a handle for |signals| to be satisfied, provided with a 128 // callback which takes only a MojoResult value corresponding to the result of 129 // a notification. Watch(Handle handle,MojoHandleSignals signals,const ReadyCallback & callback)130 MojoResult Watch(Handle handle, 131 MojoHandleSignals signals, 132 const ReadyCallback& callback) { 133 return Watch(handle, signals, MOJO_WATCH_CONDITION_SATISFIED, 134 base::Bind(&DiscardReadyState, callback)); 135 } 136 137 // Cancels the current watch. Once this returns, the ReadyCallback previously 138 // passed to |Watch()| will never be called again for this SimpleWatcher. 139 // 140 // Note that when cancelled with an explicit call to |Cancel()| the 141 // ReadyCallback will not be invoked with a |MOJO_RESULT_CANCELLED| result. 142 void Cancel(); 143 144 // Manually arms the SimpleWatcher. 145 // 146 // Arming the SimpleWatcher allows it to fire a single notification regarding 147 // some future relevant change in the watched handle's state. It's only valid 148 // to call Arm() while a handle is being watched (see Watch() above.) 149 // 150 // SimpleWatcher is always disarmed immediately before invoking its 151 // ReadyCallback and must be rearmed again before another notification can 152 // fire. 153 // 154 // If the watched handle already meets the watched signaling conditions - 155 // i.e., if it would have notified immediately once armed - the SimpleWatcher 156 // is NOT armed, and this call fails with a return value of 157 // |MOJO_RESULT_FAILED_PRECONDITION|. In that case, what would have been the 158 // result code for that immediate notification is instead placed in 159 // |*ready_result| if |ready_result| is non-null, and the last known signaling 160 // state of the handle is placed in |*ready_state| if |ready_state| is 161 // non-null. 162 // 163 // If the watcher is successfully armed (or was already armed), this returns 164 // |MOJO_RESULT_OK| and |ready_result| and |ready_state| are ignored. 165 MojoResult Arm(MojoResult* ready_result = nullptr, 166 HandleSignalsState* ready_state = nullptr); 167 168 // Manually arms the SimpleWatcher OR posts a task to invoke the ReadyCallback 169 // with the ready result of the failed arming attempt. 170 // 171 // This is meant as a convenient helper for a common usage of Arm(), and it 172 // ensures that the ReadyCallback will be invoked asynchronously again as soon 173 // as the watch's conditions are satisfied, assuming the SimpleWatcher isn't 174 // cancelled first. 175 // 176 // Unlike Arm() above, this can never fail. 177 void ArmOrNotify(); 178 handle()179 Handle handle() const { return handle_; } ready_callback()180 ReadyCallbackWithState ready_callback() const { return callback_; } 181 182 // Sets the tag used by the heap profiler. 183 // |tag| must be a const string literal. set_heap_profiler_tag(const char * heap_profiler_tag)184 void set_heap_profiler_tag(const char* heap_profiler_tag) { 185 heap_profiler_tag_ = heap_profiler_tag; 186 } 187 188 private: 189 class Context; 190 DiscardReadyState(const ReadyCallback & callback,MojoResult result,const HandleSignalsState & state)191 static void DiscardReadyState(const ReadyCallback& callback, 192 MojoResult result, 193 const HandleSignalsState& state) { 194 callback.Run(result); 195 } 196 197 void OnHandleReady(int watch_id, 198 MojoResult result, 199 const HandleSignalsState& state); 200 201 SEQUENCE_CHECKER(sequence_checker_); 202 203 // The policy used to determine how this SimpleWatcher is armed. 204 const ArmingPolicy arming_policy_; 205 206 // The TaskRunner of this SimpleWatcher's owning sequence. This field is safe 207 // to access from any sequence. 208 const scoped_refptr<base::SequencedTaskRunner> task_runner_; 209 210 // Whether |task_runner_| is the same as 211 // base::SequencedTaskRunnerHandle::Get() for the thread. 212 const bool is_default_task_runner_; 213 214 ScopedTrapHandle trap_handle_; 215 216 // A thread-safe context object corresponding to the currently active watch, 217 // if any. 218 scoped_refptr<Context> context_; 219 220 // Fields below must only be accessed on the SimpleWatcher's owning sequence. 221 222 // The handle currently under watch. Not owned. 223 Handle handle_; 224 225 // A simple counter to disambiguate notifications from multiple watch contexts 226 // in the event that this SimpleWatcher cancels and watches multiple times. 227 int watch_id_ = 0; 228 229 // The callback to call when the handle is signaled. 230 ReadyCallbackWithState callback_; 231 232 // Tag used to ID memory allocations that originated from notifications in 233 // this watcher. 234 const char* heap_profiler_tag_ = nullptr; 235 236 base::WeakPtrFactory<SimpleWatcher> weak_factory_; 237 238 DISALLOW_COPY_AND_ASSIGN(SimpleWatcher); 239 }; 240 241 } // namespace mojo 242 243 #endif // MOJO_PUBLIC_CPP_SYSTEM_SIMPLE_WATCHER_H_ 244