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
22 #include <dpl/waitable_handle_watch_support.h>
23 #include <dpl/thread.h>
25 #include <dpl/log/log.h>
27 #include <dpl/assert.h>
31 WaitableHandleWatchSupport::WaitableHandleWatchSupport()
35 WaitableHandleWatchSupport::~WaitableHandleWatchSupport()
37 // Developer assertions
38 if (!m_watchersMap.empty())
40 LogPedantic("### Leaked watchers map dump ###");
42 for (WaitableHandleWatchersMap::const_iterator iterator = m_watchersMap.begin();
43 iterator != m_watchersMap.end();
46 LogPedantic("### Waitable handle: " << iterator->first);
48 LogPedantic("### Read listeners: " << iterator->second.readListenersCount);
49 LogPedantic("### Write listeners: " << iterator->second.writeListenersCount);
51 for (WaitableHandleListenerList::const_iterator listenersIterator = iterator->second.listeners.begin();
52 listenersIterator != iterator->second.listeners.end();
55 LogPedantic("### Mode: " << listenersIterator->mode << ". Listener: 0x" << std::hex << listenersIterator->listener);
60 Assert(m_watchersMap.empty() == true);
63 WaitableHandle WaitableHandleWatchSupport::WaitableInvokerHandle() const
65 return m_watchersInvoker.GetHandle();
68 WaitableHandleListEx WaitableHandleWatchSupport::WaitableWatcherHandles() const
72 RecursiveMutex::ScopedLock lock(&m_watchersMutex);
74 WaitableHandleListEx handleList;
76 for (WaitableHandleWatchersMap::const_iterator iterator = m_watchersMap.begin();
77 iterator != m_watchersMap.end();
80 // Register waitable event id for wait
81 // Check if there are any read listeners and write listeners
82 // and register for both if applicable
83 if (iterator->second.readListenersCount > 0)
84 handleList.push_back(std::make_pair(iterator->first, WaitMode::Read));
86 if (iterator->second.writeListenersCount > 0)
87 handleList.push_back(std::make_pair(iterator->first, WaitMode::Write));
94 void WaitableHandleWatchSupport::InvokerFinished()
96 LogPedantic("Invoker finished called");
99 m_watchersInvoker.Reset();
102 m_watchersInvokerCommit.Signal();
105 void WaitableHandleWatchSupport::HandleWatcher(WaitableHandle waitableHandle, WaitMode::Type mode)
108 // Waitable event occurred
109 // Now call all listeners for that waitable event. It is possible
110 // that some of listeners early disappeared. This is not a problem.
111 // Warning: Listeners and/or watcher may also disappear during dispatching handlers!
113 LogPedantic("Waitable event occurred");
115 // Critical section for other threads
117 RecursiveMutex::ScopedLock lock(&m_watchersMutex);
119 // Notice: We must carefully call watchers here as they may disappear (zero listeners) or be created during each of handler call
120 // All removed listeners are handled correctly. Adding additional listener to the same waitable handle
121 // during handler dispatch sequence is _not_ supported.
122 WaitableHandleWatchersMap trackedWatchers = m_watchersMap;
124 for (WaitableHandleWatchersMap::const_iterator trackedWatchersIterator = trackedWatchers.begin();
125 trackedWatchersIterator != trackedWatchers.end();
126 ++trackedWatchersIterator)
128 // Check if this watcher still exists
129 // If not, go to next tracked watcher
130 if (m_watchersMap.find(trackedWatchersIterator->first) == m_watchersMap.end())
132 LogPedantic("Watcher disappeared during watcher handler");
136 // Is this is a waitable handle that we are searching for ?
137 if (waitableHandle != trackedWatchersIterator->first)
140 // Track watcher listeners list
141 WaitableHandleListenerList trackedListeners = trackedWatchersIterator->second.listeners;
143 LogPedantic("Calling waitable event listeners (" << trackedListeners.size() << ")...");
145 // Notice: We must carefully call listeners here as they may disappear or be created during each of handler call
146 // All removed listeners are handled correctly. Adding additional listener to the same waitable handle
147 // during handler dispatch sequence is should be also handled, as an extremly case.
149 // Call all waitable event listeners who listen for that event
150 for (WaitableHandleListenerList::const_iterator trackedListenersIterator = trackedListeners.begin();
151 trackedListenersIterator != trackedListeners.end();
152 ++trackedListenersIterator)
154 // Check if this watcher still exists
155 // If not, there cannot be another one. Must exit now (after break, we actually exit)
156 if (m_watchersMap.find(trackedWatchersIterator->first) == m_watchersMap.end())
158 LogPedantic("Watcher disappeared during watcher handler");
162 // Check if this watcher listener still exists
163 // If not, go to next tracked watcher listener
164 bool listenerStillExists = false;
166 for (WaitableHandleListenerList::const_iterator searchListenerIterator = trackedWatchersIterator->second.listeners.begin();
167 searchListenerIterator != trackedWatchersIterator->second.listeners.end();
168 ++searchListenerIterator)
170 if (searchListenerIterator->listener == trackedListenersIterator->listener &&
171 searchListenerIterator->mode == trackedListenersIterator->mode)
173 listenerStillExists = true;
178 if (!listenerStillExists)
180 LogPedantic("Watcher listener disappeared during watcher handler");
184 // Is this is a listener mode that we are searching for ?
185 if (mode != trackedListenersIterator->mode)
188 // Call waitable event watch listener
189 LogPedantic("Before tracker listener call...");
190 trackedListenersIterator->listener->OnWaitableHandleEvent(trackedWatchersIterator->first, trackedListenersIterator->mode);
191 LogPedantic("After tracker listener call...");
194 // Now call all those listeners who registered during listener calls
195 // FIXME: Implement! Notice, that scenario may be recursive!
197 LogPedantic("Waitable event listeners called");
199 // No more waitable events possible - consistency check
205 void WaitableHandleWatchSupport::AddWaitableHandleWatch(WaitableHandleListener* listener, WaitableHandle waitableHandle, WaitMode::Type mode)
207 // Enter waitable event list critical section
208 RecursiveMutex::ScopedLock lock(&m_watchersMutex);
210 // Find proper list to register into
211 WaitableHandleWatchersMap::iterator mapIterator = m_watchersMap.find(waitableHandle);
213 if (mapIterator != m_watchersMap.end())
215 // Assert if there is no such listener already that is listening in this mode
216 for (WaitableHandleListenerList::iterator listenersIterator = mapIterator->second.listeners.begin();
217 listenersIterator != mapIterator->second.listeners.end();
220 // Must not insert same listener-mode pair
221 Assert(listenersIterator->listener != listener || listenersIterator->mode != mode);
225 LogPedantic("Adding waitable handle watch: " << waitableHandle);
227 // Push new waitable event watch
228 if (mapIterator != m_watchersMap.end())
229 mapIterator->second.listeners.push_back(WaitableHandleWatcher(listener, mode));
231 m_watchersMap[waitableHandle].listeners.push_back(WaitableHandleWatcher(listener, mode));
237 m_watchersMap[waitableHandle].readListenersCount++;
240 case WaitMode::Write:
241 m_watchersMap[waitableHandle].writeListenersCount++;
248 // Trigger waitable event invoker to commit changes
251 LogPedantic("Waitable event watch added and invoker signaled");
254 void WaitableHandleWatchSupport::RemoveWaitableHandleWatch(WaitableHandleListener *listener, WaitableHandle waitableHandle, WaitMode::Type mode)
256 // Enter waitable event list critical section
257 RecursiveMutex::ScopedLock lock(&m_watchersMutex);
259 // Find proper list with listener
260 WaitableHandleWatchersMap::iterator mapIterator = m_watchersMap.find(waitableHandle);
262 Assert(mapIterator != m_watchersMap.end());
264 // Assert if there is such listener and mode
265 WaitableHandleListenerList::iterator listIterator = mapIterator->second.listeners.end();
267 for (WaitableHandleListenerList::iterator listenersIterator = mapIterator->second.listeners.begin();
268 listenersIterator != mapIterator->second.listeners.end();
271 // Check same pair listener-mode
272 if (listenersIterator->listener == listener && listenersIterator->mode == mode)
274 listIterator = listenersIterator;
279 // Same pair listener-mode must exist
280 Assert(listIterator != mapIterator->second.listeners.end());
282 LogPedantic("Removing waitable handle watch: " << waitableHandle);
284 // Remove waitable event watch
285 mapIterator->second.listeners.erase(listIterator);
291 mapIterator->second.readListenersCount--;
294 case WaitMode::Write:
295 mapIterator->second.writeListenersCount--;
302 // If list is empty, remove it too
303 if (mapIterator->second.listeners.empty())
304 m_watchersMap.erase(mapIterator);
306 // Trigger waitable event invoker to commit changes
309 LogPedantic("Waitable event watch removed and invoker signaled");
312 void WaitableHandleWatchSupport::CommitInvoker()
314 // Check calling context and execute invoker
315 if (Thread::GetCurrentThread() == GetInvokerThread())
317 LogPedantic("Calling direct invoker");
319 // Direct invoker call
320 HandleDirectInvoker();
324 LogPedantic("Calling indirect invoker");
326 // Indirect invoker call
327 m_watchersInvoker.Signal();
329 WaitableHandleList waitHandles;
330 waitHandles.push_back(m_watchersInvokerCommit.GetHandle());
331 WaitForMultipleHandles(waitHandles);
333 m_watchersInvokerCommit.Reset();
337 WaitableHandleWatchSupport *WaitableHandleWatchSupport::InheritedContext()
339 // In threaded context, return thread waitable handle watch implementation
340 // In main loop, return main waitable handle watch implementation
341 if (Thread::GetCurrentThread() != NULL)
342 return Thread::GetCurrentThread();
344 return &MainSingleton::Instance();