Initialize Tizen 2.3
[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
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/wrt_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         WrtLogW("### Leaked watchers map dump ###");
40
41         for (WaitableHandleWatchersMap::const_iterator iterator =
42                  m_watchersMap.begin();
43              iterator != m_watchersMap.end();
44              ++iterator)
45         {
46             WrtLogW("###   Waitable handle: %i", iterator->first);
47
48             WrtLogW("###     Read listeners: %u", iterator->second.readListenersCount);
49             WrtLogW("###     Write listeners: %u", iterator->second.writeListenersCount);
50
51             for (WaitableHandleListenerList::const_iterator listenersIterator =
52                      iterator->second.listeners.begin();
53                  listenersIterator != iterator->second.listeners.end();
54                  ++listenersIterator)
55             {
56                 WrtLogW("###       Mode: %i. Listener: %p",
57                         listenersIterator->mode, listenersIterator->listener);
58             }
59         }
60     }
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         std::lock_guard<std::recursive_mutex> lock(m_watchersMutex);
73
74         WaitableHandleListEx handleList;
75
76         for (WaitableHandleWatchersMap::const_iterator iterator =
77                  m_watchersMap.begin();
78              iterator != m_watchersMap.end();
79              ++iterator)
80         {
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,
86                                                     WaitMode::Read));
87             }
88
89             if (iterator->second.writeListenersCount > 0) {
90                 handleList.push_back(std::make_pair(iterator->first,
91                                                     WaitMode::Write));
92             }
93         }
94
95         return handleList;
96     }
97 }
98
99 void WaitableHandleWatchSupport::InvokerFinished()
100 {
101     WrtLogD("Invoker finished called");
102
103     // Reset invoker
104     m_watchersInvoker.Reset();
105
106     // Commit invoke
107     m_watchersInvokerCommit.Signal();
108 }
109
110 void WaitableHandleWatchSupport::HandleWatcher(WaitableHandle waitableHandle,
111                                                WaitMode::Type mode)
112 {
113     //
114     // Waitable event occurred
115     // Now call all listeners for that waitable event. It is possible
116     // that some of listeners early disappeared. This is not a problem.
117     // Warning: Listeners and/or watcher may also disappear during dispatching
118     // handlers!
119     //
120     WrtLogD("Waitable event occurred");
121
122     // Critical section for other threads
123     {
124         std::lock_guard<std::recursive_mutex> lock(m_watchersMutex);
125
126         // Notice: We must carefully call watchers here as they may disappear
127         // (zero listeners) or be created during each of handler call
128         //         All removed listeners are handled correctly. Adding
129         // additional listener to the same waitable handle
130         //         during handler dispatch sequence is _not_ supported.
131         WaitableHandleWatchersMap trackedWatchers = m_watchersMap;
132
133         for (WaitableHandleWatchersMap::const_iterator trackedWatchersIterator
134                  = trackedWatchers.begin();
135              trackedWatchersIterator != trackedWatchers.end();
136              ++trackedWatchersIterator)
137         {
138             // Check if this watcher still exists
139             // If not, go to next tracked watcher
140             if (m_watchersMap.find(trackedWatchersIterator->first) ==
141                 m_watchersMap.end())
142             {
143                 WrtLogD("Watcher disappeared during watcher handler");
144                 continue;
145             }
146
147             // Is this is a waitable handle that we are searching for ?
148             if (waitableHandle != trackedWatchersIterator->first) {
149                 continue;
150             }
151
152             // Track watcher listeners list
153             WaitableHandleListenerList trackedListeners =
154                 trackedWatchersIterator->second.listeners;
155
156             WrtLogD("Calling waitable event listeners (%u)...",
157                     trackedListeners.size());
158
159             // Notice: We must carefully call listeners here as they may
160             // disappear or be created during each of handler call
161             //         All removed listeners are handled correctly. Adding
162             // additional listener to the same waitable handle
163             //         during handler dispatch sequence is should be also
164             // handled, as an extremly case.
165
166             // Call all waitable event listeners who listen for that event
167             for (WaitableHandleListenerList::const_iterator
168                  trackedListenersIterator = trackedListeners.begin();
169                  trackedListenersIterator != trackedListeners.end();
170                  ++trackedListenersIterator)
171             {
172                 // Check if this watcher still exists
173                 // If not, there cannot be another one. Must exit now (after
174                 // break, we actually exit)
175                 if (m_watchersMap.find(trackedWatchersIterator->first) ==
176                     m_watchersMap.end())
177                 {
178                     WrtLogD("Watcher disappeared during watcher handler");
179                     break;
180                 }
181
182                 // Check if this watcher listener still exists
183                 // If not, go to next tracked watcher listener
184                 bool listenerStillExists = false;
185
186                 for (WaitableHandleListenerList::const_iterator
187                      searchListenerIterator =
188                          trackedWatchersIterator->second.listeners.begin();
189                      searchListenerIterator !=
190                      trackedWatchersIterator->second.listeners.end();
191                      ++searchListenerIterator)
192                 {
193                     if (searchListenerIterator->listener ==
194                         trackedListenersIterator->listener &&
195                         searchListenerIterator->mode ==
196                         trackedListenersIterator->mode)
197                     {
198                         listenerStillExists = true;
199                         break;
200                     }
201                 }
202
203                 if (!listenerStillExists) {
204                     WrtLogD("Watcher listener disappeared during watcher handler");
205                     break;
206                 }
207
208                 // Is this is a listener mode that we are searching for ?
209                 if (mode != trackedListenersIterator->mode) {
210                     continue;
211                 }
212
213                 // Call waitable event watch listener
214                 WrtLogD("Before tracker listener call...");
215                 trackedListenersIterator->listener->OnWaitableHandleEvent(
216                     trackedWatchersIterator->first,
217                     trackedListenersIterator->mode);
218                 WrtLogD("After tracker listener call...");
219             }
220
221             // Now call all those listeners who registered during listener calls
222             // FIXME: Implement! Notice, that scenario may be recursive!
223
224             WrtLogD("Waitable event listeners called");
225
226             // No more waitable events possible - consistency check
227             break;
228         }
229     }
230 }
231
232 void WaitableHandleWatchSupport::AddWaitableHandleWatch(
233     WaitableHandleListener* listener,
234     WaitableHandle waitableHandle,
235     WaitMode::Type mode)
236 {
237     // Enter waitable event list critical section
238     std::lock_guard<std::recursive_mutex> lock(m_watchersMutex);
239
240     // Find proper list to register into
241     WaitableHandleWatchersMap::iterator mapIterator = m_watchersMap.find(
242             waitableHandle);
243
244     if (mapIterator != m_watchersMap.end()) {
245         // Assert if there is no such listener already that is listening in this
246         // mode
247         for (WaitableHandleListenerList::iterator listenersIterator =
248                  mapIterator->second.listeners.begin();
249              listenersIterator != mapIterator->second.listeners.end();
250              ++listenersIterator)
251         {
252             // Must not insert same listener-mode pair
253             Assert(
254                 listenersIterator->listener != listener ||
255                 listenersIterator->mode != mode);
256         }
257     }
258
259     WrtLogD("Adding waitable handle watch: %i", waitableHandle);
260
261     // Push new waitable event watch
262     if (mapIterator != m_watchersMap.end()) {
263         mapIterator->second.listeners.push_back(WaitableHandleWatcher(listener,
264                                                                       mode));
265     } else {
266         m_watchersMap[waitableHandle].listeners.push_back(WaitableHandleWatcher(
267                                                               listener, mode));
268     }
269
270     // Update counters
271     switch (mode) {
272     case WaitMode::Read:
273         m_watchersMap[waitableHandle].readListenersCount++;
274         break;
275
276     case WaitMode::Write:
277         m_watchersMap[waitableHandle].writeListenersCount++;
278         break;
279
280     default:
281         Assert(0);
282     }
283
284     // Trigger waitable event invoker to commit changes
285     CommitInvoker();
286
287     WrtLogD("Waitable event watch added and invoker signaled");
288 }
289
290 void WaitableHandleWatchSupport::RemoveWaitableHandleWatch(
291     WaitableHandleListener *listener,
292     WaitableHandle waitableHandle,
293     WaitMode::Type mode)
294 {
295     // Enter waitable event list critical section
296     std::lock_guard<std::recursive_mutex> lock(m_watchersMutex);
297
298     // Find proper list with listener
299     WaitableHandleWatchersMap::iterator mapIterator = m_watchersMap.find(
300             waitableHandle);
301
302     Assert(mapIterator != m_watchersMap.end());
303
304     // Assert if there is such listener and mode
305     WaitableHandleListenerList::iterator listIterator =
306         mapIterator->second.listeners.end();
307
308     for (WaitableHandleListenerList::iterator listenersIterator =
309              mapIterator->second.listeners.begin();
310          listenersIterator != mapIterator->second.listeners.end();
311          ++listenersIterator)
312     {
313         // Check same pair listener-mode
314         if (listenersIterator->listener == listener &&
315             listenersIterator->mode == mode)
316         {
317             listIterator = listenersIterator;
318             break;
319         }
320     }
321
322     // Same pair listener-mode must exist
323     Assert(listIterator != mapIterator->second.listeners.end());
324
325     WrtLogD("Removing waitable handle watch: %i", waitableHandle);
326
327     // Remove waitable event watch
328     mapIterator->second.listeners.erase(listIterator);
329
330     // Update counters
331     switch (mode) {
332     case WaitMode::Read:
333         mapIterator->second.readListenersCount--;
334         break;
335
336     case WaitMode::Write:
337         mapIterator->second.writeListenersCount--;
338         break;
339
340     default:
341         Assert(0);
342     }
343
344     // If list is empty, remove it too
345     if (mapIterator->second.listeners.empty()) {
346         m_watchersMap.erase(mapIterator);
347     }
348
349     // Trigger waitable event invoker to commit changes
350     CommitInvoker();
351
352     WrtLogD("Waitable event watch removed and invoker signaled");
353 }
354
355 void WaitableHandleWatchSupport::CommitInvoker()
356 {
357     // Check calling context and execute invoker
358     if (Thread::GetCurrentThread() == GetInvokerThread()) {
359         WrtLogD("Calling direct invoker");
360
361         // Direct invoker call
362         HandleDirectInvoker();
363     } else {
364         WrtLogD("Calling indirect invoker");
365
366         // Indirect invoker call
367         m_watchersInvoker.Signal();
368
369         WaitableHandleList waitHandles;
370         waitHandles.push_back(m_watchersInvokerCommit.GetHandle());
371         WaitForMultipleHandles(waitHandles);
372
373         m_watchersInvokerCommit.Reset();
374     }
375 }
376
377 WaitableHandleWatchSupport *WaitableHandleWatchSupport::InheritedContext()
378 {
379     // In threaded context, return thread waitable handle watch implementation
380     // In main loop, return main waitable handle watch implementation
381     if (Thread::GetCurrentThread() != NULL) {
382         return Thread::GetCurrentThread();
383     } else {
384         return &MainSingleton::Instance();
385     }
386 }
387 } // namespace DPL