tizen 2.3.1 release
[framework/web/wearable/wrt-security.git] / commons / 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/log/log.h>
27 #include <algorithm>
28 #include <dpl/assert.h>
29
30 namespace DPL {
31 WaitableHandleWatchSupport::WaitableHandleWatchSupport()
32 {}
33
34 WaitableHandleWatchSupport::~WaitableHandleWatchSupport()
35 {
36     // Developer assertions
37     if (!m_watchersMap.empty()) {
38         LogWarning("### Leaked watchers map dump ###");
39
40         for (WaitableHandleWatchersMap::const_iterator iterator =
41                  m_watchersMap.begin();
42              iterator != m_watchersMap.end();
43              ++iterator)
44         {
45             LogWarning("###   Waitable handle: " << iterator->first);
46
47             LogWarning(
48                 "###     Read listeners: " <<
49                 iterator->second.readListenersCount);
50             LogWarning(
51                 "###     Write listeners: " <<
52                 iterator->second.writeListenersCount);
53
54             for (WaitableHandleListenerList::const_iterator listenersIterator =
55                      iterator->second.listeners.begin();
56                  listenersIterator != iterator->second.listeners.end();
57                  ++listenersIterator)
58             {
59                 LogWarning(
60                     "###       Mode: " << listenersIterator->mode <<
61                     ". Listener: 0x" << std::hex << listenersIterator->listener);
62             }
63         }
64     }
65 }
66
67 WaitableHandle WaitableHandleWatchSupport::WaitableInvokerHandle() const
68 {
69     return m_watchersInvoker.GetHandle();
70 }
71
72 WaitableHandleListEx WaitableHandleWatchSupport::WaitableWatcherHandles() const
73 {
74     // Critical section
75     {
76         std::lock_guard<std::recursive_mutex> lock(m_watchersMutex);
77
78         WaitableHandleListEx handleList;
79
80         for (WaitableHandleWatchersMap::const_iterator iterator =
81                  m_watchersMap.begin();
82              iterator != m_watchersMap.end();
83              ++iterator)
84         {
85             // Register waitable event id for wait
86             // Check if there are any read listeners and write listeners
87             // and register for both if applicable
88             if (iterator->second.readListenersCount > 0) {
89                 handleList.push_back(std::make_pair(iterator->first,
90                                                     WaitMode::Read));
91             }
92
93             if (iterator->second.writeListenersCount > 0) {
94                 handleList.push_back(std::make_pair(iterator->first,
95                                                     WaitMode::Write));
96             }
97         }
98
99         return handleList;
100     }
101 }
102
103 void WaitableHandleWatchSupport::InvokerFinished()
104 {
105     LogPedantic("Invoker finished called");
106
107     // Reset invoker
108     m_watchersInvoker.Reset();
109
110     // Commit invoke
111     m_watchersInvokerCommit.Signal();
112 }
113
114 void WaitableHandleWatchSupport::HandleWatcher(WaitableHandle waitableHandle,
115                                                WaitMode::Type mode)
116 {
117     //
118     // Waitable event occurred
119     // Now call all listeners for that waitable event. It is possible
120     // that some of listeners early disappeared. This is not a problem.
121     // Warning: Listeners and/or watcher may also disappear during dispatching
122     // handlers!
123     //
124     LogPedantic("Waitable event occurred");
125
126     // Critical section for other threads
127     {
128         std::lock_guard<std::recursive_mutex> lock(m_watchersMutex);
129
130         // Notice: We must carefully call watchers here as they may disappear
131         // (zero listeners) or be created during each of handler call
132         //         All removed listeners are handled correctly. Adding
133         // additional listener to the same waitable handle
134         //         during handler dispatch sequence is _not_ supported.
135         WaitableHandleWatchersMap trackedWatchers = m_watchersMap;
136
137         for (WaitableHandleWatchersMap::const_iterator trackedWatchersIterator
138                  = trackedWatchers.begin();
139              trackedWatchersIterator != trackedWatchers.end();
140              ++trackedWatchersIterator)
141         {
142             // Check if this watcher still exists
143             // If not, go to next tracked watcher
144             if (m_watchersMap.find(trackedWatchersIterator->first) ==
145                 m_watchersMap.end())
146             {
147                 LogPedantic("Watcher disappeared during watcher handler");
148                 continue;
149             }
150
151             // Is this is a waitable handle that we are searching for ?
152             if (waitableHandle != trackedWatchersIterator->first) {
153                 continue;
154             }
155
156             // Track watcher listeners list
157             WaitableHandleListenerList trackedListeners =
158                 trackedWatchersIterator->second.listeners;
159
160             LogPedantic(
161                 "Calling waitable event listeners (" <<
162                 trackedListeners.size() << ")...");
163
164             // Notice: We must carefully call listeners here as they may
165             // disappear or be created during each of handler call
166             //         All removed listeners are handled correctly. Adding
167             // additional listener to the same waitable handle
168             //         during handler dispatch sequence is should be also
169             // handled, as an extremly case.
170
171             // Call all waitable event listeners who listen for that event
172             for (WaitableHandleListenerList::const_iterator
173                  trackedListenersIterator = trackedListeners.begin();
174                  trackedListenersIterator != trackedListeners.end();
175                  ++trackedListenersIterator)
176             {
177                 // Check if this watcher still exists
178                 // If not, there cannot be another one. Must exit now (after
179                 // break, we actually exit)
180                 if (m_watchersMap.find(trackedWatchersIterator->first) ==
181                     m_watchersMap.end())
182                 {
183                     LogPedantic("Watcher disappeared during watcher handler");
184                     break;
185                 }
186
187                 // Check if this watcher listener still exists
188                 // If not, go to next tracked watcher listener
189                 bool listenerStillExists = false;
190
191                 for (WaitableHandleListenerList::const_iterator
192                      searchListenerIterator =
193                          trackedWatchersIterator->second.listeners.begin();
194                      searchListenerIterator !=
195                      trackedWatchersIterator->second.listeners.end();
196                      ++searchListenerIterator)
197                 {
198                     if (searchListenerIterator->listener ==
199                         trackedListenersIterator->listener &&
200                         searchListenerIterator->mode ==
201                         trackedListenersIterator->mode)
202                     {
203                         listenerStillExists = true;
204                         break;
205                     }
206                 }
207
208                 if (!listenerStillExists) {
209                     LogPedantic(
210                         "Watcher listener disappeared during watcher handler");
211                     break;
212                 }
213
214                 // Is this is a listener mode that we are searching for ?
215                 if (mode != trackedListenersIterator->mode) {
216                     continue;
217                 }
218
219                 // Call waitable event watch listener
220                 LogPedantic("Before tracker listener call...");
221                 trackedListenersIterator->listener->OnWaitableHandleEvent(
222                     trackedWatchersIterator->first,
223                     trackedListenersIterator->mode);
224                 LogPedantic("After tracker listener call...");
225             }
226
227             // Now call all those listeners who registered during listener calls
228             // FIXME: Implement! Notice, that scenario may be recursive!
229
230             LogPedantic("Waitable event listeners called");
231
232             // No more waitable events possible - consistency check
233             break;
234         }
235     }
236 }
237
238 void WaitableHandleWatchSupport::CommitInvoker()
239 {
240     // Check calling context and execute invoker
241     if (Thread::GetCurrentThread() == GetInvokerThread()) {
242         LogPedantic("Calling direct invoker");
243
244         // Direct invoker call
245         HandleDirectInvoker();
246     } else {
247         LogPedantic("Calling indirect invoker");
248
249         // Indirect invoker call
250         m_watchersInvoker.Signal();
251
252         WaitableHandleList waitHandles;
253         waitHandles.push_back(m_watchersInvokerCommit.GetHandle());
254         WaitForMultipleHandles(waitHandles);
255
256         m_watchersInvokerCommit.Reset();
257     }
258 }
259
260 } // namespace DPL