2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * @file waitable_handle_watch_support.cpp
18 * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
20 * @brief This file is the implementation file of waitable handle watch
24 #include <dpl/waitable_handle_watch_support.h>
25 #include <dpl/thread.h>
27 #include <dpl/log/wrt_log.h>
29 #include <dpl/assert.h>
32 WaitableHandleWatchSupport::WaitableHandleWatchSupport()
35 WaitableHandleWatchSupport::~WaitableHandleWatchSupport()
37 // Developer assertions
38 if (!m_watchersMap.empty()) {
39 WrtLogW("### Leaked watchers map dump ###");
41 for (WaitableHandleWatchersMap::const_iterator iterator =
42 m_watchersMap.begin();
43 iterator != m_watchersMap.end();
46 WrtLogW("### Waitable handle: %i", iterator->first);
48 WrtLogW("### Read listeners: %u", iterator->second.readListenersCount);
49 WrtLogW("### Write listeners: %u", iterator->second.writeListenersCount);
51 for (WaitableHandleListenerList::const_iterator listenersIterator =
52 iterator->second.listeners.begin();
53 listenersIterator != iterator->second.listeners.end();
56 WrtLogW("### Mode: %i. Listener: %p",
57 listenersIterator->mode, listenersIterator->listener);
63 WaitableHandle WaitableHandleWatchSupport::WaitableInvokerHandle() const
65 return m_watchersInvoker.GetHandle();
68 WaitableHandleListEx WaitableHandleWatchSupport::WaitableWatcherHandles() const
72 std::lock_guard<std::recursive_mutex> lock(m_watchersMutex);
74 WaitableHandleListEx handleList;
76 for (WaitableHandleWatchersMap::const_iterator iterator =
77 m_watchersMap.begin();
78 iterator != m_watchersMap.end();
81 // Register waitable event id for wait
82 // Check if there are any read listeners and write listeners
83 // and register for both if applicable
84 if (iterator->second.readListenersCount > 0) {
85 handleList.push_back(std::make_pair(iterator->first,
89 if (iterator->second.writeListenersCount > 0) {
90 handleList.push_back(std::make_pair(iterator->first,
99 void WaitableHandleWatchSupport::InvokerFinished()
101 WrtLogD("Invoker finished called");
104 m_watchersInvoker.Reset();
107 m_watchersInvokerCommit.Signal();
110 void WaitableHandleWatchSupport::HandleWatcher(WaitableHandle waitableHandle,
114 // Waitable event occurred
115 // Now call all listeners for that waitable event. It is possible
116 // that some of listeners early disappeared. This is not a problem.
117 // Warning: Listeners and/or watcher may also disappear during dispatching
120 WrtLogD("Waitable event occurred");
122 // Critical section for other threads
124 std::lock_guard<std::recursive_mutex> lock(m_watchersMutex);
126 // Notice: We must carefully call watchers here as they may disappear
127 // (zero listeners) or be created during each of handler call
128 // All removed listeners are handled correctly. Adding
129 // additional listener to the same waitable handle
130 // during handler dispatch sequence is _not_ supported.
131 WaitableHandleWatchersMap trackedWatchers = m_watchersMap;
133 for (WaitableHandleWatchersMap::const_iterator trackedWatchersIterator
134 = trackedWatchers.begin();
135 trackedWatchersIterator != trackedWatchers.end();
136 ++trackedWatchersIterator)
138 // Check if this watcher still exists
139 // If not, go to next tracked watcher
140 if (m_watchersMap.find(trackedWatchersIterator->first) ==
143 WrtLogD("Watcher disappeared during watcher handler");
147 // Is this is a waitable handle that we are searching for ?
148 if (waitableHandle != trackedWatchersIterator->first) {
152 // Track watcher listeners list
153 WaitableHandleListenerList trackedListeners =
154 trackedWatchersIterator->second.listeners;
156 WrtLogD("Calling waitable event listeners (%u)...",
157 trackedListeners.size());
159 // Notice: We must carefully call listeners here as they may
160 // disappear or be created during each of handler call
161 // All removed listeners are handled correctly. Adding
162 // additional listener to the same waitable handle
163 // during handler dispatch sequence is should be also
164 // handled, as an extremly case.
166 // Call all waitable event listeners who listen for that event
167 for (WaitableHandleListenerList::const_iterator
168 trackedListenersIterator = trackedListeners.begin();
169 trackedListenersIterator != trackedListeners.end();
170 ++trackedListenersIterator)
172 // Check if this watcher still exists
173 // If not, there cannot be another one. Must exit now (after
174 // break, we actually exit)
175 if (m_watchersMap.find(trackedWatchersIterator->first) ==
178 WrtLogD("Watcher disappeared during watcher handler");
182 // Check if this watcher listener still exists
183 // If not, go to next tracked watcher listener
184 bool listenerStillExists = false;
186 for (WaitableHandleListenerList::const_iterator
187 searchListenerIterator =
188 trackedWatchersIterator->second.listeners.begin();
189 searchListenerIterator !=
190 trackedWatchersIterator->second.listeners.end();
191 ++searchListenerIterator)
193 if (searchListenerIterator->listener ==
194 trackedListenersIterator->listener &&
195 searchListenerIterator->mode ==
196 trackedListenersIterator->mode)
198 listenerStillExists = true;
203 if (!listenerStillExists) {
204 WrtLogD("Watcher listener disappeared during watcher handler");
208 // Is this is a listener mode that we are searching for ?
209 if (mode != trackedListenersIterator->mode) {
213 // Call waitable event watch listener
214 WrtLogD("Before tracker listener call...");
215 trackedListenersIterator->listener->OnWaitableHandleEvent(
216 trackedWatchersIterator->first,
217 trackedListenersIterator->mode);
218 WrtLogD("After tracker listener call...");
221 // Now call all those listeners who registered during listener calls
222 // FIXME: Implement! Notice, that scenario may be recursive!
224 WrtLogD("Waitable event listeners called");
226 // No more waitable events possible - consistency check
232 void WaitableHandleWatchSupport::AddWaitableHandleWatch(
233 WaitableHandleListener* listener,
234 WaitableHandle waitableHandle,
237 // Enter waitable event list critical section
238 std::lock_guard<std::recursive_mutex> lock(m_watchersMutex);
240 // Find proper list to register into
241 WaitableHandleWatchersMap::iterator mapIterator = m_watchersMap.find(
244 if (mapIterator != m_watchersMap.end()) {
245 // Assert if there is no such listener already that is listening in this
247 for (WaitableHandleListenerList::iterator listenersIterator =
248 mapIterator->second.listeners.begin();
249 listenersIterator != mapIterator->second.listeners.end();
252 // Must not insert same listener-mode pair
254 listenersIterator->listener != listener ||
255 listenersIterator->mode != mode);
259 WrtLogD("Adding waitable handle watch: %i", waitableHandle);
261 // Push new waitable event watch
262 if (mapIterator != m_watchersMap.end()) {
263 mapIterator->second.listeners.push_back(WaitableHandleWatcher(listener,
266 m_watchersMap[waitableHandle].listeners.push_back(WaitableHandleWatcher(
273 m_watchersMap[waitableHandle].readListenersCount++;
276 case WaitMode::Write:
277 m_watchersMap[waitableHandle].writeListenersCount++;
284 // Trigger waitable event invoker to commit changes
287 WrtLogD("Waitable event watch added and invoker signaled");
290 void WaitableHandleWatchSupport::RemoveWaitableHandleWatch(
291 WaitableHandleListener *listener,
292 WaitableHandle waitableHandle,
295 // Enter waitable event list critical section
296 std::lock_guard<std::recursive_mutex> lock(m_watchersMutex);
298 // Find proper list with listener
299 WaitableHandleWatchersMap::iterator mapIterator = m_watchersMap.find(
302 Assert(mapIterator != m_watchersMap.end());
304 // Assert if there is such listener and mode
305 WaitableHandleListenerList::iterator listIterator =
306 mapIterator->second.listeners.end();
308 for (WaitableHandleListenerList::iterator listenersIterator =
309 mapIterator->second.listeners.begin();
310 listenersIterator != mapIterator->second.listeners.end();
313 // Check same pair listener-mode
314 if (listenersIterator->listener == listener &&
315 listenersIterator->mode == mode)
317 listIterator = listenersIterator;
322 // Same pair listener-mode must exist
323 Assert(listIterator != mapIterator->second.listeners.end());
325 WrtLogD("Removing waitable handle watch: %i", waitableHandle);
327 // Remove waitable event watch
328 mapIterator->second.listeners.erase(listIterator);
333 mapIterator->second.readListenersCount--;
336 case WaitMode::Write:
337 mapIterator->second.writeListenersCount--;
344 // If list is empty, remove it too
345 if (mapIterator->second.listeners.empty()) {
346 m_watchersMap.erase(mapIterator);
349 // Trigger waitable event invoker to commit changes
352 WrtLogD("Waitable event watch removed and invoker signaled");
355 void WaitableHandleWatchSupport::CommitInvoker()
357 // Check calling context and execute invoker
358 if (Thread::GetCurrentThread() == GetInvokerThread()) {
359 WrtLogD("Calling direct invoker");
361 // Direct invoker call
362 HandleDirectInvoker();
364 WrtLogD("Calling indirect invoker");
366 // Indirect invoker call
367 m_watchersInvoker.Signal();
369 WaitableHandleList waitHandles;
370 waitHandles.push_back(m_watchersInvokerCommit.GetHandle());
371 WaitForMultipleHandles(waitHandles);
373 m_watchersInvokerCommit.Reset();
377 WaitableHandleWatchSupport *WaitableHandleWatchSupport::InheritedContext()
379 // In threaded context, return thread waitable handle watch implementation
380 // In main loop, return main waitable handle watch implementation
381 if (Thread::GetCurrentThread() != NULL) {
382 return Thread::GetCurrentThread();
384 return &MainSingleton::Instance();