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