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