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 support
23 #include <dpl/waitable_handle_watch_support.h>
24 #include <dpl/thread.h>
26 #include <dpl/log/log.h>
28 #include <dpl/assert.h>
32 WaitableHandleWatchSupport::WaitableHandleWatchSupport()
36 WaitableHandleWatchSupport::~WaitableHandleWatchSupport()
38 // Developer assertions
39 if (!m_watchersMap.empty())
41 LogWarning("### Leaked watchers map dump ###");
43 for (WaitableHandleWatchersMap::const_iterator iterator = m_watchersMap.begin();
44 iterator != m_watchersMap.end();
47 LogWarning("### Waitable handle: " << iterator->first);
49 LogWarning("### Read listeners: " << iterator->second.readListenersCount);
50 LogWarning("### Write listeners: " << iterator->second.writeListenersCount);
52 for (WaitableHandleListenerList::const_iterator listenersIterator = iterator->second.listeners.begin();
53 listenersIterator != iterator->second.listeners.end();
56 LogWarning("### Mode: " << listenersIterator->mode << ". Listener: 0x" << std::hex << listenersIterator->listener);
62 WaitableHandle WaitableHandleWatchSupport::WaitableInvokerHandle() const
64 return m_watchersInvoker.GetHandle();
67 WaitableHandleListEx WaitableHandleWatchSupport::WaitableWatcherHandles() const
71 RecursiveMutex::ScopedLock lock(&m_watchersMutex);
73 WaitableHandleListEx handleList;
75 for (WaitableHandleWatchersMap::const_iterator iterator = m_watchersMap.begin();
76 iterator != m_watchersMap.end();
79 // Register waitable event id for wait
80 // Check if there are any read listeners and write listeners
81 // and register for both if applicable
82 if (iterator->second.readListenersCount > 0)
83 handleList.push_back(std::make_pair(iterator->first, WaitMode::Read));
85 if (iterator->second.writeListenersCount > 0)
86 handleList.push_back(std::make_pair(iterator->first, WaitMode::Write));
93 void WaitableHandleWatchSupport::InvokerFinished()
95 LogPedantic("Invoker finished called");
98 m_watchersInvoker.Reset();
101 m_watchersInvokerCommit.Signal();
104 void WaitableHandleWatchSupport::HandleWatcher(WaitableHandle waitableHandle, WaitMode::Type mode)
107 // Waitable event occurred
108 // Now call all listeners for that waitable event. It is possible
109 // that some of listeners early disappeared. This is not a problem.
110 // Warning: Listeners and/or watcher may also disappear during dispatching handlers!
112 LogPedantic("Waitable event occurred");
114 // Critical section for other threads
116 RecursiveMutex::ScopedLock lock(&m_watchersMutex);
118 // Notice: We must carefully call watchers here as they may disappear (zero listeners) or be created during each of handler call
119 // All removed listeners are handled correctly. Adding additional listener to the same waitable handle
120 // during handler dispatch sequence is _not_ supported.
121 WaitableHandleWatchersMap trackedWatchers = m_watchersMap;
123 for (WaitableHandleWatchersMap::const_iterator trackedWatchersIterator = trackedWatchers.begin();
124 trackedWatchersIterator != trackedWatchers.end();
125 ++trackedWatchersIterator)
127 // Check if this watcher still exists
128 // If not, go to next tracked watcher
129 if (m_watchersMap.find(trackedWatchersIterator->first) == m_watchersMap.end())
131 LogPedantic("Watcher disappeared during watcher handler");
135 // Is this is a waitable handle that we are searching for ?
136 if (waitableHandle != trackedWatchersIterator->first)
139 // Track watcher listeners list
140 WaitableHandleListenerList trackedListeners = trackedWatchersIterator->second.listeners;
142 LogPedantic("Calling waitable event listeners (" << trackedListeners.size() << ")...");
144 // Notice: We must carefully call listeners here as they may disappear or be created during each of handler call
145 // All removed listeners are handled correctly. Adding additional listener to the same waitable handle
146 // during handler dispatch sequence is should be also handled, as an extremly case.
148 // Call all waitable event listeners who listen for that event
149 for (WaitableHandleListenerList::const_iterator trackedListenersIterator = trackedListeners.begin();
150 trackedListenersIterator != trackedListeners.end();
151 ++trackedListenersIterator)
153 // Check if this watcher still exists
154 // If not, there cannot be another one. Must exit now (after break, we actually exit)
155 if (m_watchersMap.find(trackedWatchersIterator->first) == m_watchersMap.end())
157 LogPedantic("Watcher disappeared during watcher handler");
161 // Check if this watcher listener still exists
162 // If not, go to next tracked watcher listener
163 bool listenerStillExists = false;
165 for (WaitableHandleListenerList::const_iterator searchListenerIterator = trackedWatchersIterator->second.listeners.begin();
166 searchListenerIterator != trackedWatchersIterator->second.listeners.end();
167 ++searchListenerIterator)
169 if (searchListenerIterator->listener == trackedListenersIterator->listener &&
170 searchListenerIterator->mode == trackedListenersIterator->mode)
172 listenerStillExists = true;
177 if (!listenerStillExists)
179 LogPedantic("Watcher listener disappeared during watcher handler");
183 // Is this is a listener mode that we are searching for ?
184 if (mode != trackedListenersIterator->mode)
187 // Call waitable event watch listener
188 LogPedantic("Before tracker listener call...");
189 trackedListenersIterator->listener->OnWaitableHandleEvent(trackedWatchersIterator->first, trackedListenersIterator->mode);
190 LogPedantic("After tracker listener call...");
193 // Now call all those listeners who registered during listener calls
194 // FIXME: Implement! Notice, that scenario may be recursive!
196 LogPedantic("Waitable event listeners called");
198 // No more waitable events possible - consistency check
204 void WaitableHandleWatchSupport::AddWaitableHandleWatch(WaitableHandleListener* listener, WaitableHandle waitableHandle, WaitMode::Type mode)
206 // Enter waitable event list critical section
207 RecursiveMutex::ScopedLock lock(&m_watchersMutex);
209 // Find proper list to register into
210 WaitableHandleWatchersMap::iterator mapIterator = m_watchersMap.find(waitableHandle);
212 if (mapIterator != m_watchersMap.end())
214 // Assert if there is no such listener already that is listening in this mode
215 for (WaitableHandleListenerList::iterator listenersIterator = mapIterator->second.listeners.begin();
216 listenersIterator != mapIterator->second.listeners.end();
219 // Must not insert same listener-mode pair
220 Assert(listenersIterator->listener != listener || listenersIterator->mode != mode);
224 LogPedantic("Adding waitable handle watch: " << waitableHandle);
226 // Push new waitable event watch
227 if (mapIterator != m_watchersMap.end())
228 mapIterator->second.listeners.push_back(WaitableHandleWatcher(listener, mode));
230 m_watchersMap[waitableHandle].listeners.push_back(WaitableHandleWatcher(listener, mode));
236 m_watchersMap[waitableHandle].readListenersCount++;
239 case WaitMode::Write:
240 m_watchersMap[waitableHandle].writeListenersCount++;
247 // Trigger waitable event invoker to commit changes
250 LogPedantic("Waitable event watch added and invoker signaled");
253 void WaitableHandleWatchSupport::RemoveWaitableHandleWatch(WaitableHandleListener *listener, WaitableHandle waitableHandle, WaitMode::Type mode)
255 // Enter waitable event list critical section
256 RecursiveMutex::ScopedLock lock(&m_watchersMutex);
258 // Find proper list with listener
259 WaitableHandleWatchersMap::iterator mapIterator = m_watchersMap.find(waitableHandle);
261 Assert(mapIterator != m_watchersMap.end());
263 // Assert if there is such listener and mode
264 WaitableHandleListenerList::iterator listIterator = mapIterator->second.listeners.end();
266 for (WaitableHandleListenerList::iterator listenersIterator = mapIterator->second.listeners.begin();
267 listenersIterator != mapIterator->second.listeners.end();
270 // Check same pair listener-mode
271 if (listenersIterator->listener == listener && listenersIterator->mode == mode)
273 listIterator = listenersIterator;
278 // Same pair listener-mode must exist
279 Assert(listIterator != mapIterator->second.listeners.end());
281 LogPedantic("Removing waitable handle watch: " << waitableHandle);
283 // Remove waitable event watch
284 mapIterator->second.listeners.erase(listIterator);
290 mapIterator->second.readListenersCount--;
293 case WaitMode::Write:
294 mapIterator->second.writeListenersCount--;
301 // If list is empty, remove it too
302 if (mapIterator->second.listeners.empty())
303 m_watchersMap.erase(mapIterator);
305 // Trigger waitable event invoker to commit changes
308 LogPedantic("Waitable event watch removed and invoker signaled");
311 void WaitableHandleWatchSupport::CommitInvoker()
313 // Check calling context and execute invoker
314 if (Thread::GetCurrentThread() == GetInvokerThread())
316 LogPedantic("Calling direct invoker");
318 // Direct invoker call
319 HandleDirectInvoker();
323 LogPedantic("Calling indirect invoker");
325 // Indirect invoker call
326 m_watchersInvoker.Signal();
328 WaitableHandleList waitHandles;
329 waitHandles.push_back(m_watchersInvokerCommit.GetHandle());
330 WaitForMultipleHandles(waitHandles);
332 m_watchersInvokerCommit.Reset();
336 WaitableHandleWatchSupport *WaitableHandleWatchSupport::InheritedContext()
338 // In threaded context, return thread waitable handle watch implementation
339 // In main loop, return main waitable handle watch implementation
340 if (Thread::GetCurrentThread() != NULL)
341 return Thread::GetCurrentThread();
343 return &MainSingleton::Instance();