tizen 2.3 release
[apps/home/settings.git] / setting-appmgr / src / setting-appmgr-async-worker.c
1 /*
2  * setting
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19 #include <glib.h>
20 #include <pthread.h>
21
22 #include "setting-appmgr-async-worker.h"
23
24 typedef struct
25 {
26         pthread_t tid;
27         int alive;
28
29         async_fn fn; //'fn' Must be MT-safe
30         int fn_ret;
31         callback_fn cb;
32         SettingAppMgrUG *ad;
33
34         Ecore_Idler *worker_idler;
35 }appmgrUg_worker;
36
37 static GHashTable *async_worker_hashT;
38
39 void appmgrUg_thread_testcancel()
40 {
41         int ret;
42
43         pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
44         pthread_testcancel();
45         ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
46         if (0 != ret)
47         {
48                 SETTING_TRACE_ERROR("pthread_setcancelstate() Fail(%d)", ret);
49                 pthread_exit(NULL);
50         }
51 }
52
53 static Eina_Bool _async_worker_idler(void *data)
54 {
55         appmgrUg_worker *worker = data;
56
57         retv_if(NULL == data, ECORE_CALLBACK_CANCEL);
58
59         pthread_join(worker->tid, NULL);
60         worker->alive = FALSE;
61
62         if (worker->cb)
63                 worker->cb(worker->fn_ret, worker->ad);
64
65         g_hash_table_remove(async_worker_hashT, worker);
66
67         return ECORE_CALLBACK_CANCEL;
68 }
69
70 static void* _async_worker_thread(void *data)
71 {
72         int ret;
73         appmgrUg_worker *worker = data;
74
75         retv_if(NULL == data, NULL);
76
77         ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
78         if (0 != ret)
79         {
80                 SETTING_TRACE_ERROR("pthread_setcancelstate() Fail(%d)", ret);
81                 pthread_exit(NULL);
82         }
83
84         worker->fn_ret = worker->fn(worker->ad);
85
86         APPMGRUG_STOP_POINT;
87
88         worker->worker_idler = ecore_idler_add(_async_worker_idler, worker);
89
90         pthread_exit(NULL);
91 }
92
93 static void _async_worker_hash_free_key(gpointer data)
94 {
95         appmgrUg_worker *worker = data;
96
97         if (worker->alive)
98         {
99                 pthread_cancel(worker->tid);
100                 pthread_join(worker->tid, NULL);
101         }
102
103         if (worker->worker_idler)
104                 ecore_idler_del(worker->worker_idler);
105
106         free(worker);
107 }
108
109 void* appmgrUg_start_async_worker(async_fn fn, callback_fn cb,
110                 SettingAppMgrUG *ad)
111 {
112         int ret;
113         appmgrUg_worker *worker;
114
115         retv_if(NULL == fn, NULL);
116
117         if (NULL == async_worker_hashT)
118         {
119                 async_worker_hashT = g_hash_table_new_full(NULL, NULL,
120                                 _async_worker_hash_free_key, NULL);
121         }
122
123         worker = calloc(1, sizeof(appmgrUg_worker));
124         if (NULL == worker)
125         {
126                 SETTING_TRACE_ERROR("calloc() Fail");
127                 return NULL;
128         }
129         worker->fn = fn;
130         worker->cb = cb;
131         worker->ad = ad;
132
133         g_hash_table_add(async_worker_hashT, worker);
134
135         ret = pthread_create(&worker->tid, NULL, _async_worker_thread, worker);
136         warn_if(ret, "phread_create() Fail(%d)", ret);
137
138         worker->alive = TRUE;
139         return worker;
140 }
141
142 void appmgrUg_stop_async_worker(void *worker_id)
143 {
144         appmgrUg_worker *worker = worker_id;
145
146         ret_if(NULL == worker);
147
148         if (g_hash_table_contains(async_worker_hashT, worker_id))
149                 g_hash_table_remove(async_worker_hashT, worker_id);
150
151         if (0 == g_hash_table_size(async_worker_hashT))
152         {
153                 g_hash_table_destroy(async_worker_hashT);
154                 async_worker_hashT = NULL;
155         }
156 }
157
158 void appmgrUg_stop_async_worker_all(void)
159 {
160         g_hash_table_destroy(async_worker_hashT);
161         async_worker_hashT = NULL;
162 }