83704b48c8b38d39d401f1e2e122e6455966ad59
[framework/telephony/libtcore.git] / src / queue.c
1 /*
2  * libtcore
3  *
4  * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Ja-young Gu <jygu@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <pthread.h>
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <time.h>
27
28 #include <glib.h>
29
30 #include "tcore.h"
31 #include "plugin.h"
32 #include "queue.h"
33 #include "hal.h"
34 #include "user_request.h"
35 #include "core_object.h"
36
37
38 struct tcore_queue_type {
39         TcoreHal *hal;
40         GQueue *gq;
41         unsigned int next_id;
42 };
43
44 struct tcore_pending_type {
45         unsigned int id;
46
47         TcorePendingSendCallback on_send;
48         void *on_send_user_data;
49         TcorePendingTimeoutCallback on_timeout;
50         void *on_timeout_user_data;
51         TcorePendingResponseCallback on_response;
52         void *on_response_user_data;
53
54         enum tcore_pending_priority priority;
55         void *data;
56         unsigned int data_len;
57
58         gboolean enable;
59         unsigned int timeout;
60         time_t timestamp;
61         gboolean flag_sent;
62         gboolean flag_received_response;
63         gboolean flag_auto_free_after_sent;
64
65         guint timer_src;
66
67         UserRequest *ur;
68         TcorePlugin *plugin;
69         CoreObject *co;
70         TcoreQueue *queue;
71 };
72
73 enum search_field {
74         SEARCH_FIELD_ID_ALL = 0x01,
75         SEARCH_FIELD_ID_WAIT = 0x11,
76         SEARCH_FIELD_ID_SENT = 0x21,
77         SEARCH_FIELD_COMMAND_ALL = 0x02,
78         SEARCH_FIELD_COMMAND_WAIT = 0x12,
79         SEARCH_FIELD_COMMAND_SENT = 0x22,
80 };
81
82 static gboolean _on_pending_timeout(gpointer user_data)
83 {
84         TcorePending *p = user_data;
85
86         dbg("pending timeout!!");
87
88         if (!p)
89                 return FALSE;
90
91         tcore_pending_emit_timeout_callback(p);
92
93         p->on_response = NULL;
94         tcore_hal_dispatch_response_data(p->queue->hal, p->id, 0, NULL);
95
96         return FALSE;
97 }
98
99 TcorePending *tcore_pending_new(CoreObject *co, unsigned int id)
100 {
101         TcorePending *p;
102
103         p = calloc(sizeof(struct tcore_pending_type), 1);
104         if (!p)
105                 return NULL;
106
107         p->id = id;
108         time(&p->timestamp);
109
110         p->on_send = NULL;
111         p->on_send_user_data = NULL;
112         p->on_response = NULL;
113         p->on_response_user_data = NULL;
114         p->on_timeout = NULL;
115         p->on_timeout_user_data = NULL;
116         p->data = NULL;
117         p->data_len = 0;
118         p->timeout = 0;
119         p->priority = TCORE_PENDING_PRIORITY_DEFAULT;
120         p->flag_sent = FALSE;
121         p->co = co;
122         p->plugin = tcore_object_ref_plugin(co);
123
124         return p;
125 }
126
127 void tcore_pending_free(TcorePending *pending)
128 {
129         if (!pending)
130                 return;
131
132         dbg("pending(0x%x) free, id=0x%x", (unsigned int)pending, pending->id);
133
134         if ((tcore_hal_get_mode(pending->queue->hal) != TCORE_HAL_MODE_AT) 
135                 && (tcore_hal_get_mode(pending->queue->hal) != TCORE_HAL_MODE_TRANSPARENT)) 
136         {
137                 if (pending->data)
138                         free(pending->data);
139         }
140
141         if (pending->timer_src) {
142                 g_source_remove(pending->timer_src);
143         }
144
145         free(pending);
146 }
147
148 unsigned int tcore_pending_get_id(TcorePending *pending)
149 {
150         if (!pending)
151                 return 0;
152
153         return pending->id;
154 }
155
156 TReturn tcore_pending_set_auto_free_status_after_sent(TcorePending *pending,
157                 gboolean flag)
158 {
159         if (!pending)
160                 return TCORE_RETURN_EINVAL;
161
162         pending->flag_auto_free_after_sent = flag;
163
164         return TCORE_RETURN_SUCCESS;
165 }
166
167 gboolean tcore_pending_get_auto_free_status_after_sent(TcorePending *pending)
168 {
169         if (!pending)
170                 return FALSE;
171
172         return pending->flag_auto_free_after_sent;
173 }
174
175 TReturn tcore_pending_set_request_data(TcorePending *pending,
176                 unsigned int data_len, void *data)
177 {
178         if (!pending)
179                 return TCORE_RETURN_EINVAL;
180
181         if (pending->data) {
182                 if (pending->data_len != 0) {
183                         free(pending->data);
184                         pending->data = NULL;
185                 }
186         }
187
188         pending->data_len = data_len;
189         if (pending->data_len > 0) {
190                 pending->data = calloc(data_len, 1);
191                 if (!pending->data)
192                         return TCORE_RETURN_ENOMEM;
193
194                 memcpy(pending->data, data, data_len);
195         }
196         else {
197                 pending->data = data;
198         }
199
200         return TCORE_RETURN_SUCCESS;
201 }
202
203 void *tcore_pending_ref_request_data(TcorePending *pending, unsigned int *data_len)
204 {
205         if (!pending)
206                 return NULL;
207
208         if (data_len)
209                 *data_len = pending->data_len;
210
211         return pending->data;
212 }
213
214 TReturn tcore_pending_set_priority(TcorePending *pending,
215                 enum tcore_pending_priority priority)
216 {
217         if (!pending)
218                 return TCORE_RETURN_EINVAL;
219
220         pending->priority = priority;
221
222         return TCORE_RETURN_SUCCESS;
223 }
224
225 TReturn tcore_pending_get_priority(TcorePending *pending,
226                 enum tcore_pending_priority *result_priority)
227 {
228         if (!pending || !result_priority)
229                 return TCORE_RETURN_EINVAL;
230
231         *result_priority = pending->priority;
232
233         return TCORE_RETURN_SUCCESS;
234 }
235
236 TReturn tcore_pending_set_timeout(TcorePending *pending, unsigned int timeout)
237 {
238         if (!pending)
239                 return TCORE_RETURN_EINVAL;
240
241         pending->timeout = timeout;
242
243         return TCORE_RETURN_SUCCESS;
244 }
245
246 TReturn tcore_pending_get_send_status(TcorePending *pending,
247                 gboolean *result_status)
248 {
249         if (!pending || !result_status)
250                 return TCORE_RETURN_EINVAL;
251
252         *result_status = pending->flag_sent;
253
254         return TCORE_RETURN_SUCCESS;
255 }
256
257 TReturn tcore_pending_set_send_callback(TcorePending *pending,
258                 TcorePendingSendCallback func, void *user_data)
259 {
260         if (!pending)
261                 return TCORE_RETURN_EINVAL;
262
263         pending->on_send = func;
264         pending->on_send_user_data = user_data;
265
266         return TCORE_RETURN_SUCCESS;
267 }
268
269 TReturn tcore_pending_set_timeout_callback(TcorePending *pending,
270                 TcorePendingTimeoutCallback func, void *user_data)
271 {
272         if (!pending)
273                 return TCORE_RETURN_EINVAL;
274
275         pending->on_timeout = func;
276         pending->on_timeout_user_data = user_data;
277
278         return TCORE_RETURN_SUCCESS;
279 }
280
281 TReturn tcore_pending_set_response_callback(TcorePending *pending,
282                 TcorePendingResponseCallback func, void *user_data)
283 {
284         if (!pending)
285                 return TCORE_RETURN_EINVAL;
286
287         pending->on_response = func;
288         pending->on_response_user_data = user_data;
289
290         return TCORE_RETURN_SUCCESS;
291 }
292
293 TReturn tcore_pending_emit_send_callback(TcorePending *pending, gboolean result)
294 {
295         if (!pending)
296                 return TCORE_RETURN_EINVAL;
297
298         pending->flag_sent = TRUE;
299
300         if (pending->on_send)
301                 pending->on_send(pending, result, pending->on_send_user_data);
302
303         if (result == TRUE) {
304                 if (pending->flag_auto_free_after_sent == FALSE && pending->timeout > 0) {
305                         /* timer */
306                         dbg("start pending timer! (%d secs)", pending->timeout);
307                         pending->timer_src = g_timeout_add_seconds(pending->timeout, _on_pending_timeout, pending);
308                 }
309         }
310
311         return TCORE_RETURN_SUCCESS;
312 }
313
314 TReturn tcore_pending_emit_timeout_callback(TcorePending *pending)
315 {
316         if (!pending)
317                 return TCORE_RETURN_EINVAL;
318
319         if (pending->on_timeout)
320                 pending->on_timeout(pending, pending->on_timeout_user_data);
321
322         return TCORE_RETURN_SUCCESS;
323 }
324
325 TReturn tcore_pending_emit_response_callback(TcorePending *pending,
326                 int data_len, const void *data)
327 {
328         if (!pending)
329                 return TCORE_RETURN_EINVAL;
330
331         if (pending->on_response)
332                 pending->on_response(pending, data_len, data,
333                                 pending->on_response_user_data);
334
335         return TCORE_RETURN_SUCCESS;
336 }
337
338 CoreObject *tcore_pending_ref_core_object(TcorePending *pending)
339 {
340         if (!pending)
341                 return NULL;
342
343         return pending->co;
344 }
345
346 TcorePlugin *tcore_pending_ref_plugin(TcorePending *pending)
347 {
348         if (!pending)
349                 return NULL;
350
351         return pending->plugin;
352 }
353
354 TReturn tcore_pending_link_user_request(TcorePending *pending, UserRequest *ur)
355 {
356         if (!pending)
357                 return TCORE_RETURN_EINVAL;
358
359         pending->ur = ur;
360
361         return TCORE_RETURN_SUCCESS;
362 }
363
364 UserRequest *tcore_pending_ref_user_request(TcorePending *pending)
365 {
366         if (!pending)
367                 return NULL;
368
369         return pending->ur;
370 }
371
372 TcoreQueue *tcore_queue_new(TcoreHal *h)
373 {
374         TcoreQueue *queue;
375
376         queue = calloc(sizeof(struct tcore_queue_type), 1);
377         if (!queue)
378                 return FALSE;
379
380         queue->hal = h;
381
382         queue->gq = g_queue_new();
383         if (!queue->gq) {
384                 free(queue);
385                 return FALSE;
386         }
387
388         g_queue_init(queue->gq);
389
390         return queue;
391 }
392
393 void tcore_queue_free(TcoreQueue *queue)
394 {
395         if (!queue)
396                 return;
397
398         if (queue->gq)
399                 g_queue_free(queue->gq);
400
401         free(queue);
402 }
403
404 static void _tcore_queue_push_head(TcoreQueue *queue, TcorePending *pending)
405 {
406         int i = -1;
407         TcorePending *tmp;
408
409         do {
410                 i++;
411                 tmp = g_queue_peek_nth(queue->gq, i);
412                 if (!tmp) {
413                         break;
414                 }
415
416                 if (tmp->priority == TCORE_PENDING_PRIORITY_IMMEDIATELY)
417                         continue;
418
419                 break;
420         } while (1);
421
422         g_queue_push_nth(queue->gq, pending, i);
423 }
424
425 TReturn tcore_queue_push(TcoreQueue *queue, TcorePending *pending)
426 {
427         enum tcore_pending_priority priority;
428
429         if (!queue || !pending)
430                 return TCORE_RETURN_EINVAL;
431
432         if (pending->id == 0) {
433                 pending->id = queue->next_id;
434                 queue->next_id++;
435         }
436
437         tcore_pending_get_priority(pending, &priority);
438         switch (priority) {
439                 case TCORE_PENDING_PRIORITY_IMMEDIATELY:
440                 case TCORE_PENDING_PRIORITY_HIGH:
441                         pending->queue = queue;
442                         _tcore_queue_push_head(queue, pending);
443                         break;
444
445                 case TCORE_PENDING_PRIORITY_DEFAULT:
446                 case TCORE_PENDING_PRIORITY_LOW:
447                         pending->queue = queue;
448                         g_queue_push_tail(queue->gq, pending);
449                         break;
450
451                 default:
452                         return TCORE_RETURN_EINVAL;
453                         break;
454         }
455
456         dbg("pending(0x%x) push to queue. queue length=%d",
457                         (unsigned int)pending, g_queue_get_length(queue->gq));
458
459         return TCORE_RETURN_SUCCESS;
460 }
461
462 TcorePending *tcore_queue_pop(TcoreQueue *queue)
463 {
464         if (!queue)
465                 return NULL;
466
467         return g_queue_pop_head(queue->gq);
468 }
469
470 TcorePending *tcore_queue_pop_by_pending(TcoreQueue *queue, TcorePending *pending)
471 {
472         TcorePending *tmp;
473         int i = 0;
474
475         if (!queue)
476                 return NULL;
477
478         do {
479                 tmp = g_queue_peek_nth(queue->gq, i);
480                 if (!tmp)
481                         return NULL;
482
483                 if (tmp == pending) {
484                         g_queue_pop_nth(queue->gq, i);
485                         return tmp;
486                 }
487
488                 i++;
489         } while(1);
490
491         return NULL;
492 }
493
494 TcorePending *tcore_queue_pop_timeout_pending(TcoreQueue *queue)
495 {
496         int i = 0;
497         TcorePending *pending = NULL;
498         time_t cur_time = 0;
499
500         time(&cur_time);
501
502         do {
503                 pending = g_queue_peek_nth(queue->gq, i);
504                 if (!pending)
505                         return NULL;
506
507                 if (cur_time - pending->timestamp >= (int)pending->timeout) {
508                         pending = g_queue_pop_nth(queue->gq, i);
509                         break;
510                 }
511
512                 i++;
513         } while (pending != NULL);
514
515         return pending;
516 }
517
518 TcorePending *tcore_queue_ref_head(TcoreQueue *queue)
519 {
520         if (!queue)
521                 return NULL;
522
523         return g_queue_peek_head(queue->gq);
524 }
525
526 TcorePending *tcore_queue_ref_tail(TcoreQueue *queue)
527 {
528         if (!queue)
529                 return NULL;
530
531         return g_queue_peek_tail(queue->gq);
532 }
533
534
535 static TcorePending *_tcore_queue_search_full(TcoreQueue *queue, unsigned int id,
536                 enum tcore_request_command command, enum search_field field, gboolean flag_pop)
537 {
538         TcorePending *pending = NULL;
539         int i = 0;
540         UserRequest *ur;
541
542         if (!queue)
543                 return NULL;
544
545         do {
546                 pending = g_queue_peek_nth(queue->gq, i);
547                 if (!pending)
548                         return NULL;
549
550                 if ((field & 0xF0) == 0x10) {
551                         /* search option is wait pending */
552                         if (pending->flag_sent) {
553                                 i++;
554                                 continue;
555                         }
556                 }
557                 else if ((field & 0xF0) == 0x20) {
558                         /* search option is sent pending */
559                         if (pending->flag_sent == FALSE) {
560                                 i++;
561                                 continue;
562                         }
563                 }
564
565                 if ((field & 0x0F) == SEARCH_FIELD_ID_ALL) {
566                         if (pending->id == id) {
567                                 if (flag_pop == TRUE) {
568                                         pending = g_queue_pop_nth(queue->gq, i);
569                                 }
570                                 break;
571                         }
572                 }
573                 else if ((field & 0x0F) == SEARCH_FIELD_COMMAND_ALL) {
574                         ur = tcore_pending_ref_user_request(pending);
575                         if (tcore_user_request_get_command(ur) == command) {
576                                 if (flag_pop == TRUE) {
577                                         pending = g_queue_pop_nth(queue->gq, i);
578                                 }
579                                 break;
580                         }
581                 }
582
583                 i++;
584         } while (pending != NULL);
585
586         return pending;
587 }
588
589 TcorePending *tcore_queue_search_by_command(TcoreQueue *queue,
590                 enum tcore_request_command command, gboolean flag_sent)
591 {
592         if (flag_sent)
593                 return _tcore_queue_search_full(queue, 0, command, SEARCH_FIELD_COMMAND_SENT, FALSE);
594
595         return _tcore_queue_search_full(queue, 0, command, SEARCH_FIELD_COMMAND_WAIT, FALSE);
596 }
597
598 TcorePending *tcore_queue_pop_by_id(TcoreQueue *queue, unsigned int id)
599 {
600         if (!queue)
601                 return NULL;
602
603         return _tcore_queue_search_full(queue, id, 0, SEARCH_FIELD_ID_ALL, TRUE);
604 }
605
606 TcorePending *tcore_queue_ref_pending_by_id(TcoreQueue *queue, unsigned int id)
607 {
608         if (!queue)
609                 return NULL;
610
611         return _tcore_queue_search_full(queue, id, 0, SEARCH_FIELD_ID_ALL, FALSE);
612 }
613
614 TcorePending *tcore_queue_ref_next_pending(TcoreQueue *queue)
615 {
616         TcorePending *pending = NULL;
617         int i = 0;
618
619         if (!queue)
620                 return NULL;
621
622         do {
623                 pending = g_queue_peek_nth(queue->gq, i);
624                 if (!pending) {
625                         return NULL;
626                 }
627
628                 /* skip already sent immediately pending */
629                 if (pending->priority == TCORE_PENDING_PRIORITY_IMMEDIATELY) {
630                         if (pending->flag_sent == FALSE) {
631                                 break;
632                         }
633
634                         i++;
635                         continue;
636                 }
637                 else {
638                         break;
639                 }
640
641                 i++;
642         } while (pending != NULL);
643
644         if (pending->flag_sent == TRUE) {
645                 dbg("pending(0x%x) is waiting state.", (unsigned int)pending);
646                 return NULL;
647         }
648
649         return pending;
650 }
651
652 unsigned int tcore_queue_get_length(TcoreQueue *queue)
653 {
654         if (!queue)
655                 return 0;
656
657         return g_queue_get_length(queue->gq);
658 }
659
660 TcoreHal *tcore_queue_ref_hal(TcoreQueue *queue)
661 {
662         if (!queue)
663                 return NULL;
664
665         return queue->hal;
666 }
667
668 TReturn tcore_queue_cancel_pending_by_command(TcoreQueue *queue, enum tcore_request_command command)
669 {
670         TcorePending *pending;
671
672         if (!queue)
673                 return TCORE_RETURN_EINVAL;
674
675         while (1) {
676                 pending = _tcore_queue_search_full(queue, 0, command, SEARCH_FIELD_COMMAND_ALL, FALSE);
677                 if (!pending)
678                         break;
679
680                 dbg("pending(0x%x) cancel", pending);
681
682                 if (queue->hal) {
683                         tcore_hal_dispatch_response_data(queue->hal, pending->id, 0, NULL);
684                 }
685                 else {
686                         pending = tcore_queue_pop_by_pending(queue, pending);
687                         tcore_pending_emit_response_callback(pending, 0, NULL);
688                         tcore_user_request_unref(tcore_pending_ref_user_request(pending));
689                         tcore_pending_free(pending);
690                 }
691         }
692
693         return TCORE_RETURN_SUCCESS;
694 }