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 LogPedantic("### Leaked watchers map dump ###");
43 for (WaitableHandleWatchersMap::const_iterator iterator = m_watchersMap.begin();
44 iterator != m_watchersMap.end();
47 LogPedantic("### Waitable handle: " << iterator->first);
49 LogPedantic("### Read listeners: " << iterator->second.readListenersCount);
50 LogPedantic("### Write listeners: " << iterator->second.writeListenersCount);
52 for (WaitableHandleListenerList::const_iterator listenersIterator = iterator->second.listeners.begin();
53 listenersIterator != iterator->second.listeners.end();
56 LogPedantic("### Mode: " << listenersIterator->mode << ". Listener: 0x" << std::hex << listenersIterator->listener);
61 Assert(m_watchersMap.empty() == true);
64 WaitableHandle WaitableHandleWatchSupport::WaitableInvokerHandle() const
66 return m_watchersInvoker.GetHandle();
69 WaitableHandleListEx WaitableHandleWatchSupport::WaitableWatcherHandles() const
73 RecursiveMutex::ScopedLock lock(&m_watchersMutex);
75 WaitableHandleListEx handleList;
77 for (WaitableHandleWatchersMap::const_iterator iterator = 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, WaitMode::Read));
87 if (iterator->second.writeListenersCount > 0)
88 handleList.push_back(std::make_pair(iterator->first, WaitMode::Write));
95 void WaitableHandleWatchSupport::InvokerFinished()
97 LogPedantic("Invoker finished called");
100 m_watchersInvoker.Reset();
103 m_watchersInvokerCommit.Signal();
106 void WaitableHandleWatchSupport::HandleWatcher(WaitableHandle waitableHandle, WaitMode::Type mode)
109 // Waitable event occurred
110 // Now call all listeners for that waitable event. It is possible
111 // that some of listeners early disappeared. This is not a problem.
112 // Warning: Listeners and/or watcher may also disappear during dispatching handlers!
114 LogPedantic("Waitable event occurred");
116 // Critical section for other threads
118 RecursiveMutex::ScopedLock lock(&m_watchersMutex);
120 // Notice: We must carefully call watchers here as they may disappear (zero listeners) or be created during each of handler call
121 // All removed listeners are handled correctly. Adding additional listener to the same waitable handle
122 // during handler dispatch sequence is _not_ supported.
123 WaitableHandleWatchersMap trackedWatchers = m_watchersMap;
125 for (WaitableHandleWatchersMap::const_iterator trackedWatchersIterator = trackedWatchers.begin();
126 trackedWatchersIterator != trackedWatchers.end();
127 ++trackedWatchersIterator)
129 // Check if this watcher still exists
130 // If not, go to next tracked watcher
131 if (m_watchersMap.find(trackedWatchersIterator->first) == m_watchersMap.end())
133 LogPedantic("Watcher disappeared during watcher handler");
137 // Is this is a waitable handle that we are searching for ?
138 if (waitableHandle != trackedWatchersIterator->first)
141 // Track watcher listeners list
142 WaitableHandleListenerList trackedListeners = trackedWatchersIterator->second.listeners;
144 LogPedantic("Calling waitable event listeners (" << trackedListeners.size() << ")...");
146 // Notice: We must carefully call listeners here as they may disappear or be created during each of handler call
147 // All removed listeners are handled correctly. Adding additional listener to the same waitable handle
148 // during handler dispatch sequence is should be also handled, as an extremly case.
150 // Call all waitable event listeners who listen for that event
151 for (WaitableHandleListenerList::const_iterator trackedListenersIterator = trackedListeners.begin();
152 trackedListenersIterator != trackedListeners.end();
153 ++trackedListenersIterator)
155 // Check if this watcher still exists
156 // If not, there cannot be another one. Must exit now (after break, we actually exit)
157 if (m_watchersMap.find(trackedWatchersIterator->first) == m_watchersMap.end())
159 LogPedantic("Watcher disappeared during watcher handler");
163 // Check if this watcher listener still exists
164 // If not, go to next tracked watcher listener
165 bool listenerStillExists = false;
167 for (WaitableHandleListenerList::const_iterator searchListenerIterator = trackedWatchersIterator->second.listeners.begin();
168 searchListenerIterator != trackedWatchersIterator->second.listeners.end();
169 ++searchListenerIterator)
171 if (searchListenerIterator->listener == trackedListenersIterator->listener &&
172 searchListenerIterator->mode == trackedListenersIterator->mode)
174 listenerStillExists = true;
179 if (!listenerStillExists)
181 LogPedantic("Watcher listener disappeared during watcher handler");
185 // Is this is a listener mode that we are searching for ?
186 if (mode != trackedListenersIterator->mode)
189 // Call waitable event watch listener
190 LogPedantic("Before tracker listener call...");
191 trackedListenersIterator->listener->OnWaitableHandleEvent(trackedWatchersIterator->first, trackedListenersIterator->mode);
192 LogPedantic("After tracker listener call...");
195 // Now call all those listeners who registered during listener calls
196 // FIXME: Implement! Notice, that scenario may be recursive!
198 LogPedantic("Waitable event listeners called");
200 // No more waitable events possible - consistency check
206 void WaitableHandleWatchSupport::AddWaitableHandleWatch(WaitableHandleListener* listener, WaitableHandle waitableHandle, WaitMode::Type mode)
208 // Enter waitable event list critical section
209 RecursiveMutex::ScopedLock lock(&m_watchersMutex);
211 // Find proper list to register into
212 WaitableHandleWatchersMap::iterator mapIterator = m_watchersMap.find(waitableHandle);
214 if (mapIterator != m_watchersMap.end())
216 // Assert if there is no such listener already that is listening in this mode
217 for (WaitableHandleListenerList::iterator listenersIterator = mapIterator->second.listeners.begin();
218 listenersIterator != mapIterator->second.listeners.end();
221 // Must not insert same listener-mode pair
222 Assert(listenersIterator->listener != listener || listenersIterator->mode != mode);
226 LogPedantic("Adding waitable handle watch: " << waitableHandle);
228 // Push new waitable event watch
229 if (mapIterator != m_watchersMap.end())
230 mapIterator->second.listeners.push_back(WaitableHandleWatcher(listener, mode));
232 m_watchersMap[waitableHandle].listeners.push_back(WaitableHandleWatcher(listener, mode));
238 m_watchersMap[waitableHandle].readListenersCount++;
241 case WaitMode::Write:
242 m_watchersMap[waitableHandle].writeListenersCount++;
249 // Trigger waitable event invoker to commit changes
252 LogPedantic("Waitable event watch added and invoker signaled");
255 void WaitableHandleWatchSupport::RemoveWaitableHandleWatch(WaitableHandleListener *listener, WaitableHandle waitableHandle, WaitMode::Type mode)
257 // Enter waitable event list critical section
258 RecursiveMutex::ScopedLock lock(&m_watchersMutex);
260 // Find proper list with listener
261 WaitableHandleWatchersMap::iterator mapIterator = m_watchersMap.find(waitableHandle);
263 Assert(mapIterator != m_watchersMap.end());
265 // Assert if there is such listener and mode
266 WaitableHandleListenerList::iterator listIterator = mapIterator->second.listeners.end();
268 for (WaitableHandleListenerList::iterator listenersIterator = mapIterator->second.listeners.begin();
269 listenersIterator != mapIterator->second.listeners.end();
272 // Check same pair listener-mode
273 if (listenersIterator->listener == listener && listenersIterator->mode == mode)
275 listIterator = listenersIterator;
280 // Same pair listener-mode must exist
281 Assert(listIterator != mapIterator->second.listeners.end());
283 LogPedantic("Removing waitable handle watch: " << waitableHandle);
285 // Remove waitable event watch
286 mapIterator->second.listeners.erase(listIterator);
292 mapIterator->second.readListenersCount--;
295 case WaitMode::Write:
296 mapIterator->second.writeListenersCount--;
303 // If list is empty, remove it too
304 if (mapIterator->second.listeners.empty())
305 m_watchersMap.erase(mapIterator);
307 // Trigger waitable event invoker to commit changes
310 LogPedantic("Waitable event watch removed and invoker signaled");
313 void WaitableHandleWatchSupport::CommitInvoker()
315 // Check calling context and execute invoker
316 if (Thread::GetCurrentThread() == GetInvokerThread())
318 LogPedantic("Calling direct invoker");
320 // Direct invoker call
321 HandleDirectInvoker();
325 LogPedantic("Calling indirect invoker");
327 // Indirect invoker call
328 m_watchersInvoker.Signal();
330 WaitableHandleList waitHandles;
331 waitHandles.push_back(m_watchersInvokerCommit.GetHandle());
332 WaitForMultipleHandles(waitHandles);
334 m_watchersInvokerCommit.Reset();
338 WaitableHandleWatchSupport *WaitableHandleWatchSupport::InheritedContext()
340 // In threaded context, return thread waitable handle watch implementation
341 // In main loop, return main waitable handle watch implementation
342 if (Thread::GetCurrentThread() != NULL)
343 return Thread::GetCurrentThread();
345 return &MainSingleton::Instance();