tizen beta release
[framework/web/wrt-commons.git] / modules / core / src / waitable_handle_watch_support.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 /*
17  * @file        waitable_handle_watch_support.cpp
18  * @author      Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
19  * @version     1.0
20  * @brief       This file is the implementation file of waitable handle watch support
21  */
22 #include <dpl/waitable_handle_watch_support.h>
23 #include <dpl/thread.h>
24 #include <dpl/main.h>
25 #include <dpl/log/log.h>
26 #include <algorithm>
27 #include <dpl/assert.h>
28
29 namespace DPL
30 {
31 WaitableHandleWatchSupport::WaitableHandleWatchSupport()
32 {
33 }
34
35 WaitableHandleWatchSupport::~WaitableHandleWatchSupport()
36 {
37     // Developer assertions
38     if (!m_watchersMap.empty())
39     {
40         LogPedantic("### Leaked watchers map dump ###");
41
42         for (WaitableHandleWatchersMap::const_iterator iterator = m_watchersMap.begin();
43              iterator != m_watchersMap.end();
44              ++iterator)
45         {
46             LogPedantic("###   Waitable handle: " << iterator->first);
47
48             LogPedantic("###     Read listeners: " << iterator->second.readListenersCount);
49             LogPedantic("###     Write listeners: " << iterator->second.writeListenersCount);
50
51             for (WaitableHandleListenerList::const_iterator listenersIterator = iterator->second.listeners.begin();
52                  listenersIterator != iterator->second.listeners.end();
53                  ++listenersIterator)
54             {
55                 LogPedantic("###       Mode: " << listenersIterator->mode << ". Listener: 0x" << std::hex << listenersIterator->listener);
56             }
57         }
58     }
59
60     Assert(m_watchersMap.empty() == true);
61 }
62
63 WaitableHandle WaitableHandleWatchSupport::WaitableInvokerHandle() const
64 {
65     return m_watchersInvoker.GetHandle();
66 }
67
68 WaitableHandleListEx WaitableHandleWatchSupport::WaitableWatcherHandles() const
69 {
70     // Critical section
71     {
72         RecursiveMutex::ScopedLock lock(&m_watchersMutex);
73
74         WaitableHandleListEx handleList;
75
76         for (WaitableHandleWatchersMap::const_iterator iterator = m_watchersMap.begin();
77              iterator != m_watchersMap.end();
78              ++iterator)
79         {
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));
85
86             if (iterator->second.writeListenersCount > 0)
87                 handleList.push_back(std::make_pair(iterator->first, WaitMode::Write));
88         }
89
90         return handleList;
91     }
92 }
93
94 void WaitableHandleWatchSupport::InvokerFinished()
95 {
96     LogPedantic("Invoker finished called");
97
98     // Reset invoker
99     m_watchersInvoker.Reset();
100
101     // Commit invoke
102     m_watchersInvokerCommit.Signal();
103 }
104
105 void WaitableHandleWatchSupport::HandleWatcher(WaitableHandle waitableHandle, WaitMode::Type mode)
106 {
107     //
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!
112     //
113     LogPedantic("Waitable event occurred");
114
115     // Critical section for other threads
116     {
117         RecursiveMutex::ScopedLock lock(&m_watchersMutex);
118
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;
123
124         for (WaitableHandleWatchersMap::const_iterator trackedWatchersIterator = trackedWatchers.begin();
125              trackedWatchersIterator != trackedWatchers.end();
126              ++trackedWatchersIterator)
127         {
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())
131             {
132                 LogPedantic("Watcher disappeared during watcher handler");
133                 continue;
134             }
135
136             // Is this is a waitable handle that we are searching for ?
137             if (waitableHandle != trackedWatchersIterator->first)
138                 continue;
139
140             // Track watcher listeners list
141             WaitableHandleListenerList trackedListeners = trackedWatchersIterator->second.listeners;
142
143             LogPedantic("Calling waitable event listeners (" << trackedListeners.size() << ")...");
144
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.
148  
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)
153             {
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())
157                 {
158                     LogPedantic("Watcher disappeared during watcher handler");
159                     break;
160                 }
161
162                 // Check if this watcher listener still exists
163                 // If not, go to next tracked watcher listener
164                 bool listenerStillExists = false;
165
166                 for (WaitableHandleListenerList::const_iterator searchListenerIterator = trackedWatchersIterator->second.listeners.begin();
167                      searchListenerIterator != trackedWatchersIterator->second.listeners.end();
168                      ++searchListenerIterator)
169                 {
170                     if (searchListenerIterator->listener == trackedListenersIterator->listener &&
171                         searchListenerIterator->mode == trackedListenersIterator->mode)
172                     {
173                         listenerStillExists = true;
174                         break;
175                     }
176                 }
177
178                 if (!listenerStillExists)
179                 {
180                     LogPedantic("Watcher listener disappeared during watcher handler");
181                     break;
182                 }
183
184                 // Is this is a listener mode that we are searching for ?
185                 if (mode != trackedListenersIterator->mode)
186                     continue;
187
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...");
192             }
193
194             // Now call all those listeners who registered during listener calls
195             // FIXME: Implement! Notice, that scenario may be recursive!
196
197             LogPedantic("Waitable event listeners called");
198
199             // No more waitable events possible - consistency check
200             break;
201         }
202     }
203 }
204
205 void WaitableHandleWatchSupport::AddWaitableHandleWatch(WaitableHandleListener* listener, WaitableHandle waitableHandle, WaitMode::Type mode)
206 {
207     // Enter waitable event list critical section
208     RecursiveMutex::ScopedLock lock(&m_watchersMutex);
209
210     // Find proper list to register into
211     WaitableHandleWatchersMap::iterator mapIterator = m_watchersMap.find(waitableHandle);
212
213     if (mapIterator != m_watchersMap.end())
214     {
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();
218              ++listenersIterator)
219         {
220             // Must not insert same listener-mode pair
221             Assert(listenersIterator->listener != listener || listenersIterator->mode != mode);
222         }
223     }
224
225     LogPedantic("Adding waitable handle watch: " << waitableHandle);
226
227     // Push new waitable event watch
228     if (mapIterator != m_watchersMap.end())
229         mapIterator->second.listeners.push_back(WaitableHandleWatcher(listener, mode));
230     else
231         m_watchersMap[waitableHandle].listeners.push_back(WaitableHandleWatcher(listener, mode));
232
233     // Update counters
234     switch (mode)
235     {
236         case WaitMode::Read:
237             m_watchersMap[waitableHandle].readListenersCount++;
238             break;
239
240         case WaitMode::Write:
241             m_watchersMap[waitableHandle].writeListenersCount++;
242             break;
243
244         default:
245             Assert(0);
246     }
247
248     // Trigger waitable event invoker to commit changes
249     CommitInvoker();
250
251     LogPedantic("Waitable event watch added and invoker signaled");
252 }
253
254 void WaitableHandleWatchSupport::RemoveWaitableHandleWatch(WaitableHandleListener *listener, WaitableHandle waitableHandle, WaitMode::Type mode)
255 {
256     // Enter waitable event list critical section
257     RecursiveMutex::ScopedLock lock(&m_watchersMutex);
258
259     // Find proper list with listener
260     WaitableHandleWatchersMap::iterator mapIterator = m_watchersMap.find(waitableHandle);
261
262     Assert(mapIterator != m_watchersMap.end());
263
264     // Assert if there is such listener and mode
265     WaitableHandleListenerList::iterator listIterator = mapIterator->second.listeners.end();
266
267     for (WaitableHandleListenerList::iterator listenersIterator = mapIterator->second.listeners.begin();
268          listenersIterator != mapIterator->second.listeners.end();
269          ++listenersIterator)
270     {
271         // Check same pair listener-mode
272         if (listenersIterator->listener == listener && listenersIterator->mode == mode)
273         {
274             listIterator = listenersIterator;
275             break;
276         }
277     }
278
279     // Same pair listener-mode must exist
280     Assert(listIterator != mapIterator->second.listeners.end());
281
282     LogPedantic("Removing waitable handle watch: " << waitableHandle);
283   
284     // Remove waitable event watch
285     mapIterator->second.listeners.erase(listIterator);
286
287     // Update counters
288     switch (mode)
289     {
290         case WaitMode::Read:
291             mapIterator->second.readListenersCount--;
292             break;
293
294         case WaitMode::Write:
295             mapIterator->second.writeListenersCount--;
296             break;
297
298         default:
299             Assert(0);
300     }
301
302     // If list is empty, remove it too
303     if (mapIterator->second.listeners.empty())
304         m_watchersMap.erase(mapIterator);
305
306     // Trigger waitable event invoker to commit changes
307     CommitInvoker();
308
309     LogPedantic("Waitable event watch removed and invoker signaled");
310 }
311
312 void WaitableHandleWatchSupport::CommitInvoker()
313 {
314     // Check calling context and execute invoker
315     if (Thread::GetCurrentThread() == GetInvokerThread())
316     {
317         LogPedantic("Calling direct invoker");
318
319         // Direct invoker call
320         HandleDirectInvoker();
321     }
322     else
323     {
324         LogPedantic("Calling indirect invoker");
325
326         // Indirect invoker call
327         m_watchersInvoker.Signal();
328
329         WaitableHandleList waitHandles;
330         waitHandles.push_back(m_watchersInvokerCommit.GetHandle());
331         WaitForMultipleHandles(waitHandles);
332
333         m_watchersInvokerCommit.Reset();
334     }
335 }
336
337 WaitableHandleWatchSupport *WaitableHandleWatchSupport::InheritedContext()
338 {
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();
343     else
344         return &MainSingleton::Instance();
345 }
346 } // namespace DPL