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