Initialize Tizen 2.3
[framework/web/wrt-commons.git] / modules_mobile / 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
21  * support
22  */
23 #include <stddef.h>
24 #include <dpl/waitable_handle_watch_support.h>
25 #include <dpl/thread.h>
26 #include <dpl/main.h>
27 #include <dpl/log/log.h>
28 #include <algorithm>
29 #include <dpl/assert.h>
30
31 namespace DPL {
32 WaitableHandleWatchSupport::WaitableHandleWatchSupport()
33 {}
34
35 WaitableHandleWatchSupport::~WaitableHandleWatchSupport()
36 {
37     // Developer assertions
38     if (!m_watchersMap.empty()) {
39         LogWarning("### Leaked watchers map dump ###");
40
41         for (WaitableHandleWatchersMap::const_iterator iterator =
42                  m_watchersMap.begin();
43              iterator != m_watchersMap.end();
44              ++iterator)
45         {
46             LogWarning("###   Waitable handle: " << iterator->first);
47
48             LogWarning(
49                 "###     Read listeners: " <<
50                 iterator->second.readListenersCount);
51             LogWarning(
52                 "###     Write listeners: " <<
53                 iterator->second.writeListenersCount);
54
55             for (WaitableHandleListenerList::const_iterator listenersIterator =
56                      iterator->second.listeners.begin();
57                  listenersIterator != iterator->second.listeners.end();
58                  ++listenersIterator)
59             {
60                 LogWarning(
61                     "###       Mode: " << listenersIterator->mode <<
62                     ". Listener: 0x" << std::hex << listenersIterator->listener);
63             }
64         }
65     }
66 }
67
68 WaitableHandle WaitableHandleWatchSupport::WaitableInvokerHandle() const
69 {
70     return m_watchersInvoker.GetHandle();
71 }
72
73 WaitableHandleListEx WaitableHandleWatchSupport::WaitableWatcherHandles() const
74 {
75     // Critical section
76     {
77         RecursiveMutex::ScopedLock lock(&m_watchersMutex);
78
79         WaitableHandleListEx handleList;
80
81         for (WaitableHandleWatchersMap::const_iterator iterator =
82                  m_watchersMap.begin();
83              iterator != m_watchersMap.end();
84              ++iterator)
85         {
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,
91                                                     WaitMode::Read));
92             }
93
94             if (iterator->second.writeListenersCount > 0) {
95                 handleList.push_back(std::make_pair(iterator->first,
96                                                     WaitMode::Write));
97             }
98         }
99
100         return handleList;
101     }
102 }
103
104 void WaitableHandleWatchSupport::InvokerFinished()
105 {
106     LogPedantic("Invoker finished called");
107
108     // Reset invoker
109     m_watchersInvoker.Reset();
110
111     // Commit invoke
112     m_watchersInvokerCommit.Signal();
113 }
114
115 void WaitableHandleWatchSupport::HandleWatcher(WaitableHandle waitableHandle,
116                                                WaitMode::Type mode)
117 {
118     //
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
123     // handlers!
124     //
125     LogPedantic("Waitable event occurred");
126
127     // Critical section for other threads
128     {
129         RecursiveMutex::ScopedLock lock(&m_watchersMutex);
130
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;
137
138         for (WaitableHandleWatchersMap::const_iterator trackedWatchersIterator
139                  = trackedWatchers.begin();
140              trackedWatchersIterator != trackedWatchers.end();
141              ++trackedWatchersIterator)
142         {
143             // Check if this watcher still exists
144             // If not, go to next tracked watcher
145             if (m_watchersMap.find(trackedWatchersIterator->first) ==
146                 m_watchersMap.end())
147             {
148                 LogPedantic("Watcher disappeared during watcher handler");
149                 continue;
150             }
151
152             // Is this is a waitable handle that we are searching for ?
153             if (waitableHandle != trackedWatchersIterator->first) {
154                 continue;
155             }
156
157             // Track watcher listeners list
158             WaitableHandleListenerList trackedListeners =
159                 trackedWatchersIterator->second.listeners;
160
161             LogPedantic(
162                 "Calling waitable event listeners (" <<
163                 trackedListeners.size() << ")...");
164
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.
171
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)
177             {
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) ==
182                     m_watchersMap.end())
183                 {
184                     LogPedantic("Watcher disappeared during watcher handler");
185                     break;
186                 }
187
188                 // Check if this watcher listener still exists
189                 // If not, go to next tracked watcher listener
190                 bool listenerStillExists = false;
191
192                 for (WaitableHandleListenerList::const_iterator
193                      searchListenerIterator =
194                          trackedWatchersIterator->second.listeners.begin();
195                      searchListenerIterator !=
196                      trackedWatchersIterator->second.listeners.end();
197                      ++searchListenerIterator)
198                 {
199                     if (searchListenerIterator->listener ==
200                         trackedListenersIterator->listener &&
201                         searchListenerIterator->mode ==
202                         trackedListenersIterator->mode)
203                     {
204                         listenerStillExists = true;
205                         break;
206                     }
207                 }
208
209                 if (!listenerStillExists) {
210                     LogPedantic(
211                         "Watcher listener disappeared during watcher handler");
212                     break;
213                 }
214
215                 // Is this is a listener mode that we are searching for ?
216                 if (mode != trackedListenersIterator->mode) {
217                     continue;
218                 }
219
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...");
226             }
227
228             // Now call all those listeners who registered during listener calls
229             // FIXME: Implement! Notice, that scenario may be recursive!
230
231             LogPedantic("Waitable event listeners called");
232
233             // No more waitable events possible - consistency check
234             break;
235         }
236     }
237 }
238
239 void WaitableHandleWatchSupport::AddWaitableHandleWatch(
240     WaitableHandleListener* listener,
241     WaitableHandle waitableHandle,
242     WaitMode::Type mode)
243 {
244     // Enter waitable event list critical section
245     RecursiveMutex::ScopedLock lock(&m_watchersMutex);
246
247     // Find proper list to register into
248     WaitableHandleWatchersMap::iterator mapIterator = m_watchersMap.find(
249             waitableHandle);
250
251     if (mapIterator != m_watchersMap.end()) {
252         // Assert if there is no such listener already that is listening in this
253         // mode
254         for (WaitableHandleListenerList::iterator listenersIterator =
255                  mapIterator->second.listeners.begin();
256              listenersIterator != mapIterator->second.listeners.end();
257              ++listenersIterator)
258         {
259             // Must not insert same listener-mode pair
260             Assert(
261                 listenersIterator->listener != listener ||
262                 listenersIterator->mode != mode);
263         }
264     }
265
266     LogPedantic("Adding waitable handle watch: " << waitableHandle);
267
268     // Push new waitable event watch
269     if (mapIterator != m_watchersMap.end()) {
270         mapIterator->second.listeners.push_back(WaitableHandleWatcher(listener,
271                                                                       mode));
272     } else {
273         m_watchersMap[waitableHandle].listeners.push_back(WaitableHandleWatcher(
274                                                               listener, mode));
275     }
276
277     // Update counters
278     switch (mode) {
279     case WaitMode::Read:
280         m_watchersMap[waitableHandle].readListenersCount++;
281         break;
282
283     case WaitMode::Write:
284         m_watchersMap[waitableHandle].writeListenersCount++;
285         break;
286
287     default:
288         Assert(0);
289     }
290
291     // Trigger waitable event invoker to commit changes
292     CommitInvoker();
293
294     LogPedantic("Waitable event watch added and invoker signaled");
295 }
296
297 void WaitableHandleWatchSupport::RemoveWaitableHandleWatch(
298     WaitableHandleListener *listener,
299     WaitableHandle waitableHandle,
300     WaitMode::Type mode)
301 {
302     // Enter waitable event list critical section
303     RecursiveMutex::ScopedLock lock(&m_watchersMutex);
304
305     // Find proper list with listener
306     WaitableHandleWatchersMap::iterator mapIterator = m_watchersMap.find(
307             waitableHandle);
308
309     Assert(mapIterator != m_watchersMap.end());
310
311     // Assert if there is such listener and mode
312     WaitableHandleListenerList::iterator listIterator =
313         mapIterator->second.listeners.end();
314
315     for (WaitableHandleListenerList::iterator listenersIterator =
316              mapIterator->second.listeners.begin();
317          listenersIterator != mapIterator->second.listeners.end();
318          ++listenersIterator)
319     {
320         // Check same pair listener-mode
321         if (listenersIterator->listener == listener &&
322             listenersIterator->mode == mode)
323         {
324             listIterator = listenersIterator;
325             break;
326         }
327     }
328
329     // Same pair listener-mode must exist
330     Assert(listIterator != mapIterator->second.listeners.end());
331
332     LogPedantic("Removing waitable handle watch: " << waitableHandle);
333
334     // Remove waitable event watch
335     mapIterator->second.listeners.erase(listIterator);
336
337     // Update counters
338     switch (mode) {
339     case WaitMode::Read:
340         mapIterator->second.readListenersCount--;
341         break;
342
343     case WaitMode::Write:
344         mapIterator->second.writeListenersCount--;
345         break;
346
347     default:
348         Assert(0);
349     }
350
351     // If list is empty, remove it too
352     if (mapIterator->second.listeners.empty()) {
353         m_watchersMap.erase(mapIterator);
354     }
355
356     // Trigger waitable event invoker to commit changes
357     CommitInvoker();
358
359     LogPedantic("Waitable event watch removed and invoker signaled");
360 }
361
362 void WaitableHandleWatchSupport::CommitInvoker()
363 {
364     // Check calling context and execute invoker
365     if (Thread::GetCurrentThread() == GetInvokerThread()) {
366         LogPedantic("Calling direct invoker");
367
368         // Direct invoker call
369         HandleDirectInvoker();
370     } else {
371         LogPedantic("Calling indirect invoker");
372
373         // Indirect invoker call
374         m_watchersInvoker.Signal();
375
376         WaitableHandleList waitHandles;
377         waitHandles.push_back(m_watchersInvokerCommit.GetHandle());
378         WaitForMultipleHandles(waitHandles);
379
380         m_watchersInvokerCommit.Reset();
381     }
382 }
383
384 WaitableHandleWatchSupport *WaitableHandleWatchSupport::InheritedContext()
385 {
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();
390     } else {
391         return &MainSingleton::Instance();
392     }
393 }
394 } // namespace DPL