tizen 2.3.1 release
[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_free_timeout_pending_request(p->queue->hal, p, 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(1, sizeof(struct tcore_pending_type));
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 (pending->queue) {
135                 enum tcore_hal_mode mode = tcore_hal_get_mode(pending->queue->hal);
136                 if ((mode != TCORE_HAL_MODE_AT)
137                                 && (mode != TCORE_HAL_MODE_TRANSPARENT))
138                         if (pending->data)
139                                 free(pending->data);
140         }
141
142         if (pending->timer_src) {
143                 g_source_remove(pending->timer_src);
144         }
145
146         free(pending);
147 }
148
149 unsigned int tcore_pending_get_id(TcorePending *pending)
150 {
151         if (!pending)
152                 return 0;
153
154         return pending->id;
155 }
156
157 TReturn tcore_pending_set_auto_free_status_after_sent(TcorePending *pending,
158                 gboolean flag)
159 {
160         if (!pending)
161                 return TCORE_RETURN_EINVAL;
162
163         pending->flag_auto_free_after_sent = flag;
164
165         return TCORE_RETURN_SUCCESS;
166 }
167
168 gboolean tcore_pending_get_auto_free_status_after_sent(TcorePending *pending)
169 {
170         if (!pending)
171                 return FALSE;
172
173         return pending->flag_auto_free_after_sent;
174 }
175
176 TReturn tcore_pending_set_request_data(TcorePending *pending,
177                 unsigned int data_len, void *data)
178 {
179         if (!pending)
180                 return TCORE_RETURN_EINVAL;
181
182         if (pending->data) {
183                 if (pending->data_len != 0) {
184                         free(pending->data);
185                         pending->data = NULL;
186                 }
187         }
188
189         pending->data_len = data_len;
190         if (pending->data_len > 0) {
191                 pending->data = calloc(data_len, 1);
192                 if (!pending->data)
193                         return TCORE_RETURN_ENOMEM;
194
195                 memcpy(pending->data, data, data_len);
196         }
197         else {
198                 pending->data = data;
199         }
200
201         return TCORE_RETURN_SUCCESS;
202 }
203
204 void *tcore_pending_ref_request_data(TcorePending *pending, unsigned int *data_len)
205 {
206         if (!pending)
207                 return NULL;
208
209         if (data_len)
210                 *data_len = pending->data_len;
211
212         return pending->data;
213 }
214
215 TReturn tcore_pending_set_priority(TcorePending *pending,
216                 enum tcore_pending_priority priority)
217 {
218         if (!pending)
219                 return TCORE_RETURN_EINVAL;
220
221         pending->priority = priority;
222
223         return TCORE_RETURN_SUCCESS;
224 }
225
226 TReturn tcore_pending_get_priority(TcorePending *pending,
227                 enum tcore_pending_priority *result_priority)
228 {
229         if (!pending || !result_priority)
230                 return TCORE_RETURN_EINVAL;
231
232         *result_priority = pending->priority;
233
234         return TCORE_RETURN_SUCCESS;
235 }
236
237 TReturn tcore_pending_start_timer(TcorePending *pending)
238 {
239         /* pending timer */
240         if (pending->timeout > 0 && pending->on_timeout) {
241                 dbg("start pending timer! (%d secs)", pending->timeout);
242                 pending->timer_src = g_timeout_add_seconds(pending->timeout, _on_pending_timeout, pending);
243         }
244         return TCORE_RETURN_SUCCESS;
245 }
246
247 TReturn tcore_pending_set_timeout(TcorePending *pending, unsigned int timeout)
248 {
249         if (!pending)
250                 return TCORE_RETURN_EINVAL;
251
252         pending->timeout = timeout;
253
254         return TCORE_RETURN_SUCCESS;
255 }
256
257 unsigned int  tcore_pending_get_timeout(TcorePending *pending)
258 {
259         if (!pending)
260                 return 0;
261
262         return pending->timeout;
263 }
264
265 TReturn tcore_pending_get_send_status(TcorePending *pending,
266                 gboolean *result_status)
267 {
268         if (!pending || !result_status)
269                 return TCORE_RETURN_EINVAL;
270
271         *result_status = pending->flag_sent;
272
273         return TCORE_RETURN_SUCCESS;
274 }
275
276 TReturn tcore_pending_set_send_callback(TcorePending *pending,
277                 TcorePendingSendCallback func, void *user_data)
278 {
279         if (!pending)
280                 return TCORE_RETURN_EINVAL;
281
282         pending->on_send = func;
283         pending->on_send_user_data = user_data;
284
285         return TCORE_RETURN_SUCCESS;
286 }
287
288 TReturn tcore_pending_set_timeout_callback(TcorePending *pending,
289                 TcorePendingTimeoutCallback func, void *user_data)
290 {
291         if (!pending)
292                 return TCORE_RETURN_EINVAL;
293
294         pending->on_timeout = func;
295         pending->on_timeout_user_data = user_data;
296
297         return TCORE_RETURN_SUCCESS;
298 }
299
300 TReturn tcore_pending_set_response_callback(TcorePending *pending,
301                 TcorePendingResponseCallback func, void *user_data)
302 {
303         if (!pending)
304                 return TCORE_RETURN_EINVAL;
305
306         pending->on_response = func;
307         pending->on_response_user_data = user_data;
308
309         return TCORE_RETURN_SUCCESS;
310 }
311
312 TReturn tcore_pending_emit_send_callback(TcorePending *pending, gboolean result)
313 {
314         if (!pending)
315                 return TCORE_RETURN_EINVAL;
316
317         pending->flag_sent = TRUE;
318
319         if (pending->on_send)
320                 pending->on_send(pending, result, pending->on_send_user_data);
321
322         return TCORE_RETURN_SUCCESS;
323 }
324
325 TReturn tcore_pending_emit_timeout_callback(TcorePending *pending)
326 {
327         if (!pending)
328                 return TCORE_RETURN_EINVAL;
329
330         if (pending->on_timeout)
331                 pending->on_timeout(pending, pending->on_timeout_user_data);
332
333         return TCORE_RETURN_SUCCESS;
334 }
335
336 TReturn tcore_pending_emit_response_callback(TcorePending *pending,
337                 int data_len, const void *data)
338 {
339         if (!pending)
340                 return TCORE_RETURN_EINVAL;
341
342         if (pending->on_response)
343                 pending->on_response(pending, data_len, data,
344                                 pending->on_response_user_data);
345
346         return TCORE_RETURN_SUCCESS;
347 }
348
349 CoreObject *tcore_pending_ref_core_object(TcorePending *pending)
350 {
351         if (!pending)
352                 return NULL;
353
354         return pending->co;
355 }
356
357 TcorePlugin *tcore_pending_ref_plugin(TcorePending *pending)
358 {
359         if (!pending)
360                 return NULL;
361
362         return pending->plugin;
363 }
364
365 TReturn tcore_pending_link_user_request(TcorePending *pending, UserRequest *ur)
366 {
367         if (!pending)
368                 return TCORE_RETURN_EINVAL;
369
370         pending->ur = ur;
371
372         return TCORE_RETURN_SUCCESS;
373 }
374
375 UserRequest *tcore_pending_ref_user_request(TcorePending *pending)
376 {
377         if (!pending)
378                 return NULL;
379
380         return pending->ur;
381 }
382
383 TcoreQueue *tcore_queue_new(TcoreHal *h)
384 {
385         TcoreQueue *queue;
386
387         queue = calloc(1, sizeof(struct tcore_queue_type));
388         if (!queue)
389                 return FALSE;
390
391         queue->hal = h;
392
393         queue->gq = g_queue_new();
394         if (!queue->gq) {
395                 free(queue);
396                 return FALSE;
397         }
398
399         g_queue_init(queue->gq);
400
401         return queue;
402 }
403
404 void tcore_queue_free(TcoreQueue *queue)
405 {
406         if (!queue)
407                 return;
408
409         if (queue->gq)
410                 g_queue_free(queue->gq);
411
412         free(queue);
413 }
414
415 static void _tcore_queue_push_head(TcoreQueue *queue, TcorePending *pending)
416 {
417         int i = -1;
418         TcorePending *tmp;
419
420         do {
421                 i++;
422                 tmp = g_queue_peek_nth(queue->gq, i);
423                 if (!tmp) {
424                         break;
425                 }
426
427                 if (tmp->priority == TCORE_PENDING_PRIORITY_IMMEDIATELY)
428                         continue;
429
430                 break;
431         } while (1);
432
433         g_queue_push_nth(queue->gq, pending, i);
434 }
435
436 TReturn tcore_queue_push(TcoreQueue *queue, TcorePending *pending)
437 {
438         enum tcore_pending_priority priority;
439
440         if (!queue || !pending)
441                 return TCORE_RETURN_EINVAL;
442
443         if (pending->id == 0) {
444                 pending->id = queue->next_id;
445                 queue->next_id++;
446         }
447
448         tcore_pending_get_priority(pending, &priority);
449         switch (priority) {
450                 case TCORE_PENDING_PRIORITY_IMMEDIATELY:
451                 case TCORE_PENDING_PRIORITY_HIGH:
452                         pending->queue = queue;
453                         _tcore_queue_push_head(queue, pending);
454                         break;
455
456                 case TCORE_PENDING_PRIORITY_DEFAULT:
457                 case TCORE_PENDING_PRIORITY_LOW:
458                         pending->queue = queue;
459                         g_queue_push_tail(queue->gq, pending);
460                         break;
461
462                 default:
463                         return TCORE_RETURN_EINVAL;
464                         break;
465         }
466
467         dbg("pending(%p) push to queue(%p). queue length=%d",
468                         (unsigned int)pending, queue, g_queue_get_length(queue->gq));
469
470         return TCORE_RETURN_SUCCESS;
471 }
472
473 TcorePending *tcore_queue_pop(TcoreQueue *queue)
474 {
475         if (!queue)
476                 return NULL;
477
478         return g_queue_pop_head(queue->gq);
479 }
480
481 TcorePending *tcore_queue_pop_by_pending(TcoreQueue *queue, TcorePending *pending)
482 {
483         TcorePending *tmp;
484         int i = 0;
485
486         if (!queue)
487                 return NULL;
488
489         do {
490                 tmp = g_queue_peek_nth(queue->gq, i);
491                 if (!tmp)
492                         return NULL;
493
494                 if (tmp == pending) {
495                         g_queue_pop_nth(queue->gq, i);
496                         return tmp;
497                 }
498
499                 i++;
500         } while(1);
501
502         return NULL;
503 }
504
505 TcorePending *tcore_queue_pop_timeout_pending(TcoreQueue *queue)
506 {
507         int i = 0;
508         TcorePending *pending = NULL;
509         time_t cur_time = 0;
510
511         time(&cur_time);
512
513         do {
514                 pending = g_queue_peek_nth(queue->gq, i);
515                 if (!pending)
516                         return NULL;
517
518                 if (cur_time - pending->timestamp >= (int)pending->timeout) {
519                         pending = g_queue_pop_nth(queue->gq, i);
520                         break;
521                 }
522
523                 i++;
524         } while (pending != NULL);
525
526         return pending;
527 }
528
529 TcorePending *tcore_queue_ref_head(TcoreQueue *queue)
530 {
531         if (!queue)
532                 return NULL;
533
534         return g_queue_peek_head(queue->gq);
535 }
536
537 TcorePending *tcore_queue_ref_tail(TcoreQueue *queue)
538 {
539         if (!queue)
540                 return NULL;
541
542         return g_queue_peek_tail(queue->gq);
543 }
544
545
546 static TcorePending *_tcore_queue_search_full(TcoreQueue *queue, unsigned int id,
547                 enum tcore_request_command command, enum search_field field, gboolean flag_pop)
548 {
549         TcorePending *pending = NULL;
550         int i = 0;
551         UserRequest *ur;
552
553         if (!queue)
554                 return NULL;
555
556         do {
557                 pending = g_queue_peek_nth(queue->gq, i);
558                 if (!pending)
559                         return NULL;
560
561                 if ((field & 0xF0) == 0x10) {
562                         /* search option is wait pending */
563                         if (pending->flag_sent) {
564                                 i++;
565                                 continue;
566                         }
567                 }
568                 else if ((field & 0xF0) == 0x20) {
569                         /* search option is sent pending */
570                         if (pending->flag_sent == FALSE) {
571                                 i++;
572                                 continue;
573                         }
574                 }
575
576                 if ((field & 0x0F) == SEARCH_FIELD_ID_ALL) {
577                         if (pending->id == id) {
578                                 if (flag_pop == TRUE) {
579                                         pending = g_queue_pop_nth(queue->gq, i);
580                                 }
581                                 break;
582                         }
583                 }
584                 else if ((field & 0x0F) == SEARCH_FIELD_COMMAND_ALL) {
585                         ur = tcore_pending_ref_user_request(pending);
586                         if (tcore_user_request_get_command(ur) == command) {
587                                 if (flag_pop == TRUE) {
588                                         pending = g_queue_pop_nth(queue->gq, i);
589                                 }
590                                 break;
591                         }
592                 }
593
594                 i++;
595         } while (pending != NULL);
596
597         return pending;
598 }
599
600 TcorePending *tcore_queue_search_by_command(TcoreQueue *queue,
601                 enum tcore_request_command command, gboolean flag_sent)
602 {
603         if (flag_sent)
604                 return _tcore_queue_search_full(queue, 0, command, SEARCH_FIELD_COMMAND_SENT, FALSE);
605
606         return _tcore_queue_search_full(queue, 0, command, SEARCH_FIELD_COMMAND_WAIT, FALSE);
607 }
608
609 TcorePending *tcore_queue_pop_by_id(TcoreQueue *queue, unsigned int id)
610 {
611         if (!queue)
612                 return NULL;
613
614         return _tcore_queue_search_full(queue, id, 0, SEARCH_FIELD_ID_ALL, TRUE);
615 }
616
617 TcorePending *tcore_queue_ref_pending_by_id(TcoreQueue *queue, unsigned int id)
618 {
619         if (!queue)
620                 return NULL;
621
622         return _tcore_queue_search_full(queue, id, 0, SEARCH_FIELD_ID_ALL, FALSE);
623 }
624
625 TcorePending *tcore_queue_ref_next_pending(TcoreQueue *queue)
626 {
627         TcorePending *pending = NULL;
628         int i = 0;
629
630         if (!queue)
631                 return NULL;
632
633         do {
634                 pending = g_queue_peek_nth(queue->gq, i);
635                 if (!pending) {
636                         return NULL;
637                 }
638
639                 /* skip already sent immediately pending */
640                 if (pending->priority == TCORE_PENDING_PRIORITY_IMMEDIATELY) {
641                         if (pending->flag_sent == FALSE) {
642                                 break;
643                         }
644
645                         i++;
646                         continue;
647                 }
648                 else {
649                         break;
650                 }
651         } while (pending != NULL);
652
653         if (pending->flag_sent == TRUE) {
654                 dbg("pending(0x%x) is waiting state.", (unsigned int)pending);
655                 return NULL;
656         }
657
658         return pending;
659 }
660
661 unsigned int tcore_queue_get_length(TcoreQueue *queue)
662 {
663         if (!queue)
664                 return 0;
665
666         return g_queue_get_length(queue->gq);
667 }
668
669 unsigned int tcore_queue_get_normal_length(TcoreQueue *queue)
670 {
671         TcorePending *pending;
672         int i = 0;
673
674         if (!queue)
675                 return 0;
676
677         do {
678                 pending = g_queue_peek_nth(queue->gq, i);
679                 if (!pending) {
680                         break;
681                 }
682
683                 if (pending->priority == TCORE_PENDING_PRIORITY_IMMEDIATELY) {
684                         i++;
685                         continue;
686                 }
687
688                 break;
689         } while (1);
690
691         return g_queue_get_length(queue->gq) - i;
692 }
693
694 TcoreHal *tcore_queue_ref_hal(TcoreQueue *queue)
695 {
696         if (!queue)
697                 return NULL;
698
699         return queue->hal;
700 }
701
702 TReturn tcore_queue_cancel_pending_by_command(TcoreQueue *queue, enum tcore_request_command command)
703 {
704         TcorePending *pending;
705
706         if (!queue)
707                 return TCORE_RETURN_EINVAL;
708
709         while (1) {
710                 pending = _tcore_queue_search_full(queue, 0, command, SEARCH_FIELD_COMMAND_ALL, FALSE);
711                 if (!pending)
712                         break;
713
714                 dbg("pending(0x%x) cancel", (unsigned int)pending);
715
716                 if (queue->hal) {
717                         dbg("hal %p", queue->hal);
718                         tcore_hal_dispatch_response_data(queue->hal, pending->id, 0, NULL);
719                 }
720                 else {
721                         dbg("no hal");
722                         pending = tcore_queue_pop_by_pending(queue, pending);
723                         tcore_pending_emit_response_callback(pending, 0, NULL);
724                         tcore_user_request_unref(tcore_pending_ref_user_request(pending));
725                         tcore_pending_free(pending);
726                 }
727         }
728
729         return TCORE_RETURN_SUCCESS;
730 }