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/log.h>
29 #include <dpl/assert.h>
32 WaitableHandleWatchSupport::WaitableHandleWatchSupport()
35 WaitableHandleWatchSupport::~WaitableHandleWatchSupport()
37 // Developer assertions
38 if (!m_watchersMap.empty()) {
39 LogWarning("### Leaked watchers map dump ###");
41 for (WaitableHandleWatchersMap::const_iterator iterator =
42 m_watchersMap.begin();
43 iterator != m_watchersMap.end();
46 LogWarning("### Waitable handle: " << iterator->first);
49 "### Read listeners: " <<
50 iterator->second.readListenersCount);
52 "### Write listeners: " <<
53 iterator->second.writeListenersCount);
55 for (WaitableHandleListenerList::const_iterator listenersIterator =
56 iterator->second.listeners.begin();
57 listenersIterator != iterator->second.listeners.end();
61 "### Mode: " << listenersIterator->mode <<
62 ". Listener: 0x" << std::hex << listenersIterator->listener);
68 WaitableHandle WaitableHandleWatchSupport::WaitableInvokerHandle() const
70 return m_watchersInvoker.GetHandle();
73 WaitableHandleListEx WaitableHandleWatchSupport::WaitableWatcherHandles() const
77 RecursiveMutex::ScopedLock lock(&m_watchersMutex);
79 WaitableHandleListEx handleList;
81 for (WaitableHandleWatchersMap::const_iterator iterator =
82 m_watchersMap.begin();
83 iterator != m_watchersMap.end();
86 // Register waitable event id for wait
87 // Check if there are any read listeners and write listeners
88 // and register for both if applicable
89 if (iterator->second.readListenersCount > 0) {
90 handleList.push_back(std::make_pair(iterator->first,
94 if (iterator->second.writeListenersCount > 0) {
95 handleList.push_back(std::make_pair(iterator->first,
104 void WaitableHandleWatchSupport::InvokerFinished()
106 LogPedantic("Invoker finished called");
109 m_watchersInvoker.Reset();
112 m_watchersInvokerCommit.Signal();
115 void WaitableHandleWatchSupport::HandleWatcher(WaitableHandle waitableHandle,
119 // Waitable event occurred
120 // Now call all listeners for that waitable event. It is possible
121 // that some of listeners early disappeared. This is not a problem.
122 // Warning: Listeners and/or watcher may also disappear during dispatching
125 LogPedantic("Waitable event occurred");
127 // Critical section for other threads
129 RecursiveMutex::ScopedLock lock(&m_watchersMutex);
131 // Notice: We must carefully call watchers here as they may disappear
132 // (zero listeners) or be created during each of handler call
133 // All removed listeners are handled correctly. Adding
134 // additional listener to the same waitable handle
135 // during handler dispatch sequence is _not_ supported.
136 WaitableHandleWatchersMap trackedWatchers = m_watchersMap;
138 for (WaitableHandleWatchersMap::const_iterator trackedWatchersIterator
139 = trackedWatchers.begin();
140 trackedWatchersIterator != trackedWatchers.end();
141 ++trackedWatchersIterator)
143 // Check if this watcher still exists
144 // If not, go to next tracked watcher
145 if (m_watchersMap.find(trackedWatchersIterator->first) ==
148 LogPedantic("Watcher disappeared during watcher handler");
152 // Is this is a waitable handle that we are searching for ?
153 if (waitableHandle != trackedWatchersIterator->first) {
157 // Track watcher listeners list
158 WaitableHandleListenerList trackedListeners =
159 trackedWatchersIterator->second.listeners;
162 "Calling waitable event listeners (" <<
163 trackedListeners.size() << ")...");
165 // Notice: We must carefully call listeners here as they may
166 // disappear or be created during each of handler call
167 // All removed listeners are handled correctly. Adding
168 // additional listener to the same waitable handle
169 // during handler dispatch sequence is should be also
170 // handled, as an extremly case.
172 // Call all waitable event listeners who listen for that event
173 for (WaitableHandleListenerList::const_iterator
174 trackedListenersIterator = trackedListeners.begin();
175 trackedListenersIterator != trackedListeners.end();
176 ++trackedListenersIterator)
178 // Check if this watcher still exists
179 // If not, there cannot be another one. Must exit now (after
180 // break, we actually exit)
181 if (m_watchersMap.find(trackedWatchersIterator->first) ==
184 LogPedantic("Watcher disappeared during watcher handler");
188 // Check if this watcher listener still exists
189 // If not, go to next tracked watcher listener
190 bool listenerStillExists = false;
192 for (WaitableHandleListenerList::const_iterator
193 searchListenerIterator =
194 trackedWatchersIterator->second.listeners.begin();
195 searchListenerIterator !=
196 trackedWatchersIterator->second.listeners.end();
197 ++searchListenerIterator)
199 if (searchListenerIterator->listener ==
200 trackedListenersIterator->listener &&
201 searchListenerIterator->mode ==
202 trackedListenersIterator->mode)
204 listenerStillExists = true;
209 if (!listenerStillExists) {
211 "Watcher listener disappeared during watcher handler");
215 // Is this is a listener mode that we are searching for ?
216 if (mode != trackedListenersIterator->mode) {
220 // Call waitable event watch listener
221 LogPedantic("Before tracker listener call...");
222 trackedListenersIterator->listener->OnWaitableHandleEvent(
223 trackedWatchersIterator->first,
224 trackedListenersIterator->mode);
225 LogPedantic("After tracker listener call...");
228 // Now call all those listeners who registered during listener calls
229 // FIXME: Implement! Notice, that scenario may be recursive!
231 LogPedantic("Waitable event listeners called");
233 // No more waitable events possible - consistency check
239 void WaitableHandleWatchSupport::AddWaitableHandleWatch(
240 WaitableHandleListener* listener,
241 WaitableHandle waitableHandle,
244 // Enter waitable event list critical section
245 RecursiveMutex::ScopedLock lock(&m_watchersMutex);
247 // Find proper list to register into
248 WaitableHandleWatchersMap::iterator mapIterator = m_watchersMap.find(
251 if (mapIterator != m_watchersMap.end()) {
252 // Assert if there is no such listener already that is listening in this
254 for (WaitableHandleListenerList::iterator listenersIterator =
255 mapIterator->second.listeners.begin();
256 listenersIterator != mapIterator->second.listeners.end();
259 // Must not insert same listener-mode pair
261 listenersIterator->listener != listener ||
262 listenersIterator->mode != mode);
266 LogPedantic("Adding waitable handle watch: " << waitableHandle);
268 // Push new waitable event watch
269 if (mapIterator != m_watchersMap.end()) {
270 mapIterator->second.listeners.push_back(WaitableHandleWatcher(listener,
273 m_watchersMap[waitableHandle].listeners.push_back(WaitableHandleWatcher(
280 m_watchersMap[waitableHandle].readListenersCount++;
283 case WaitMode::Write:
284 m_watchersMap[waitableHandle].writeListenersCount++;
291 // Trigger waitable event invoker to commit changes
294 LogPedantic("Waitable event watch added and invoker signaled");
297 void WaitableHandleWatchSupport::RemoveWaitableHandleWatch(
298 WaitableHandleListener *listener,
299 WaitableHandle waitableHandle,
302 // Enter waitable event list critical section
303 RecursiveMutex::ScopedLock lock(&m_watchersMutex);
305 // Find proper list with listener
306 WaitableHandleWatchersMap::iterator mapIterator = m_watchersMap.find(
309 Assert(mapIterator != m_watchersMap.end());
311 // Assert if there is such listener and mode
312 WaitableHandleListenerList::iterator listIterator =
313 mapIterator->second.listeners.end();
315 for (WaitableHandleListenerList::iterator listenersIterator =
316 mapIterator->second.listeners.begin();
317 listenersIterator != mapIterator->second.listeners.end();
320 // Check same pair listener-mode
321 if (listenersIterator->listener == listener &&
322 listenersIterator->mode == mode)
324 listIterator = listenersIterator;
329 // Same pair listener-mode must exist
330 Assert(listIterator != mapIterator->second.listeners.end());
332 LogPedantic("Removing waitable handle watch: " << waitableHandle);
334 // Remove waitable event watch
335 mapIterator->second.listeners.erase(listIterator);
340 mapIterator->second.readListenersCount--;
343 case WaitMode::Write:
344 mapIterator->second.writeListenersCount--;
351 // If list is empty, remove it too
352 if (mapIterator->second.listeners.empty()) {
353 m_watchersMap.erase(mapIterator);
356 // Trigger waitable event invoker to commit changes
359 LogPedantic("Waitable event watch removed and invoker signaled");
362 void WaitableHandleWatchSupport::CommitInvoker()
364 // Check calling context and execute invoker
365 if (Thread::GetCurrentThread() == GetInvokerThread()) {
366 LogPedantic("Calling direct invoker");
368 // Direct invoker call
369 HandleDirectInvoker();
371 LogPedantic("Calling indirect invoker");
373 // Indirect invoker call
374 m_watchersInvoker.Signal();
376 WaitableHandleList waitHandles;
377 waitHandles.push_back(m_watchersInvokerCommit.GetHandle());
378 WaitForMultipleHandles(waitHandles);
380 m_watchersInvokerCommit.Reset();
384 WaitableHandleWatchSupport *WaitableHandleWatchSupport::InheritedContext()
386 // In threaded context, return thread waitable handle watch implementation
387 // In main loop, return main waitable handle watch implementation
388 if (Thread::GetCurrentThread() != NULL) {
389 return Thread::GetCurrentThread();
391 return &MainSingleton::Instance();