Add LCOV remarkers to increase line coverage rate
[platform/core/api/maps-service.git] / src / session / command_queue.cpp
1 /* Copyright (c) 2010-2014 Samsung Electronics Co., Ltd. All rights reserved.
2  *
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 #include "command_queue.h"
18 #include "command.h"
19 #include "thread.h"
20
21 session::command_queue *session::command_queue::interface()
22 {
23         if (is_async()) {
24 #ifdef _MAPS_SERVICE_SUPPORTS_ASYNC_QUEUE_
25                 static command_queue_async async_queue;
26                 return &async_queue;
27 #else
28                 static command_queue_sync sync_queue;
29                 return &sync_queue;
30 #endif /* _MAPS_SERVICE_SUPPORTS_ASYNC_QUEUE_ */
31         } else {
32                 static command_queue_sync sync_queue;
33                 return &sync_queue;
34         }
35 }
36
37 /*----------------------------------------------------------------------------*/
38
39 //LCOV_EXCL_START
40 int session::command_queue_sync::push(command *c)
41 {
42         return (c and c->plugin())? c->run() : MAPS_ERROR_INVALID_PARAMETER;
43 }
44
45 session::command* session::command_queue_sync::pop(plugin::plugin_s *p)
46 {
47         return command::empty_ptr();
48 }
49
50 void session::command_queue_sync::process(plugin::plugin_s *p)
51 {
52         /* empty */
53 }
54 //LCOV_EXCL_STOP
55
56 void session::command_queue_sync::clear(plugin::plugin_s *p)
57 {
58         /* empty */
59 }
60
61 /*----------------------------------------------------------------------------*/
62
63 /*
64  * This is the implementation of asynchronous queue.
65  * In order to pass code coverage tests it is blocked.
66  */
67 #ifdef _MAPS_SERVICE_SUPPORTS_ASYNC_QUEUE_
68 int session::command_queue_async::push(command *c)
69 {
70         if (!c || !c->plugin() || !c->plugin()->request_queue)
71                 return MAPS_ERROR_INVALID_PARAMETER;
72
73         queue_autoref(c->plugin()->request_queue);
74         g_async_queue_push(c->plugin()->request_queue, c);
75
76         /* Lazy initialization: run plugin thread if it is not started yet */
77         thread().run(c->plugin());
78
79         return MAPS_ERROR_NONE;
80 }
81
82 session::command *session::command_queue_async::pop(plugin::plugin_s *p)
83 {
84         if (!p || !p->request_queue)
85                 return command::empty_ptr();
86
87         queue_autoref(p->request_queue);
88
89         /* Pops data from the queue . */
90         /* If the queue is empty, blocks for timeout microseconds, or until data
91         *  becomes available. */
92         /* If no data is received before the timeout, NULL is returned. */
93         /* https://developer.gnome.org/glib/stable/glib-Asynchronous-Queues.html#g-async-queue-timeout-pop */
94         command* c =
95                 (command *) g_async_queue_timeout_pop(p->request_queue,
96                                         10 * G_TIME_SPAN_MILLISECOND);
97         return (c) ? c : command::empty_ptr();
98 }
99
100 void session::command_queue_async::process(plugin::plugin_s *p)
101 {
102         if (not p or not p->request_queue)
103                 return;
104
105         queue_autoref(p->request_queue);
106         pop(p)->run();
107 }
108
109 void session::command_queue_async::clear(plugin::plugin_s *p)
110 {
111         if (not p or not p->request_queue)
112                 return;
113
114         queue_autoref(p->request_queue);
115         while (g_async_queue_length(p->request_queue))
116                 pop(p)->destroy();
117 }
118
119
120 /*----------------------------------------------------------------------------*/
121
122 session::command_queue* session::command_queue_view::interface()
123 {
124         static command_queue_view view_queue;
125         return &view_queue;
126 }
127
128 /*static int __dbg_queue_length = 0;*/
129
130 gint session::command_queue_view::iterate(gconstpointer a,
131                                           gconstpointer b,
132                                           gpointer user_data)
133 {
134         /*__dbg_queue_length ++;*/
135
136         /* Extracting command data from params */
137         command *ca = (command *)a;
138         command *cb = (command *)b;
139         command *c_new = (command *)user_data;
140
141         /* Attempting to update existing command with freshier data.
142          * It is decided not to store a number of commands of the same type:
143          * one command is enough */
144         if (c_new) {
145                 if (ca->get_type() == c_new->get_type()) {
146                         ca->merge(c_new);
147                         //c_new->set_merged();
148                 } else if (cb->get_type() == c_new->get_type()) {
149                         cb->merge(c_new);
150                         //c_new->set_merged();
151                 }
152         }
153
154         /* Sorting the commands in the que with their prioirties:
155          * the lower priority, the far the command from the queue front
156          *
157          * https://developer.gnome.org/glib/stable/
158          *      glib-Asynchronous-Queues.html#g-async-queue-sort */
159         const int pa = ca->get_priority();
160         const int pb = cb->get_priority();
161         return (pa < pb ? +1 : pa == pb ? 0 : -1);
162 }
163
164 int session::command_queue_view::push(command *c)
165 {
166         /*g_print("session::command_queue_view::push "
167                         "pushed a command: %p\n", c);*/
168         if (c == command::empty_ptr())
169                 return MAPS_ERROR_NONE;
170
171         if (!c || !c->plugin() || !c->plugin()->request_queue)
172                 return MAPS_ERROR_INVALID_PARAMETER;
173
174
175         queue_autoref(c->plugin()->request_queue);
176
177 #if 0
178         /* ---------------------------------------------- */
179         /* This is the routine without queue modification */
180         const bool _dbg_simple_queue = false;
181         if (_dbg_simple_queue) {
182                 g_async_queue_push(c->plugin()->request_queue, c);
183                 return MAPS_ERROR_NONE;
184         }
185         /* ---------------------------------------------- */
186 #endif
187
188         /* Iterating the queue; sorting it and simultaneously attempting
189          * to update the data of the existing command of the current type.
190          * This approach allows to store only one instance of a command per
191          * given type */
192         /*__dbg_queue_length = 0;*/
193         g_async_queue_sort(c->plugin()->request_queue,
194                             session::command_queue_view::iterate, c);
195         /*g_print("Queue Length: %d\n", __dbg_queue_length);*/
196
197         /* If the command was merged, it is not needed any more.
198          * If the command data was not merged to the existing command instance
199          * of the same type, we should:
200          *   a. add this command to the queue and
201          *   b. sort the queue once again without any attempt to update
202          *  existing commands
203          *
204          * https://developer.gnome.org/glib/stable/
205          *      glib-Asynchronous-Queues.html#g-async-queue-push-sorted */
206         if (c->merged())
207                 delete c;
208         else
209                 g_async_queue_push_sorted(c->plugin()->request_queue, c,
210                                            session::command_queue_view::iterate,
211                                            NULL);
212
213         return MAPS_ERROR_NONE;
214 }
215
216 session::command* session::command_queue_view::pop(plugin::plugin_s *p)
217 {
218         /*g_print("session::command_queue_view::pop\n");*/
219         if (!p || !p->request_queue)
220                 return command::empty_ptr();
221
222         queue_autoref(p->request_queue);
223
224         /*
225          * Pops data from the queue.
226          * If the queue is empty, blocks for timeout microseconds, or until data
227          * becomes available.
228          * If no data is received before the timeout, NULL is returned.
229          * https://developer.gnome.org/glib/stable/glib-Asynchronous-Queues.html#g-async-queue-timeout-pop
230          */
231         command* c =
232                 (command*)g_async_queue_timeout_pop(p->request_queue,
233                                         /*300 * G_TIME_SPAN_MILLISECOND);*/
234                                         /* Small timeout is better for UI */
235                                         10 * G_TIME_SPAN_MILLISECOND);
236         /*if (c)
237                 g_print("session::command_queue_view::pop "
238                         "extracted a command: %p\n", c);*/
239         return (c) ? c : command::empty_ptr();
240 }
241
242 void session::command_queue_view::process(plugin::plugin_s *p)
243 {
244         if (!p || !p->request_queue)
245                 return;
246
247         queue_autoref(p->request_queue);
248         pop(p)->run();
249 }
250
251 void session::command_queue_view::clear(plugin::plugin_s *p)
252 {
253         if (!p || !p->request_queue)
254                 return;
255
256         queue_autoref(p->request_queue);
257         while (g_async_queue_length(p->request_queue))
258                 pop(p)->destroy();
259 }
260
261 #endif /* _MAPS_SERVICE_SUPPORTS_ASYNC_QUEUE_ */