tizen 2.4 release
[apps/home/settings.git] / setting-storage / src / setting-storage-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-storage-async-worker.h"
23
24 typedef struct {
25         pthread_t tid;
26         int alive;
27
28         async_fn fn; /*'fn' Must be MT-safe */
29         int fn_ret;
30         callback_fn cb;
31         SettingStorageUG *ad;
32
33         Ecore_Idler *worker_idler;
34 } storageUg_worker;
35
36 static GHashTable *storage_worker_hashT;
37
38 void storageUg_thread_testcancel()
39 {
40         int ret;
41
42         pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
43         pthread_testcancel();
44         ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
45         if (0 != ret) {
46                 SETTING_TRACE_ERROR("pthread_setcancelstate() Fail(%d)", ret);
47                 pthread_exit(NULL);
48         }
49 }
50
51 static Eina_Bool _async_worker_idler(void *data)
52 {
53         SETTING_TRACE_BEGIN;
54         SETTING_TRACE("---------------------------------------------thread join BEGIN ");
55         storageUg_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
66
67         SETTING_TRACE("---------------------------------------------thread join END ");
68         SETTING_TRACE_END;
69         return ECORE_CALLBACK_CANCEL;
70 }
71
72 static void *_async_worker_thread(void *data)
73 {
74         int ret;
75         storageUg_worker *worker = data;
76
77         retv_if(NULL == data, NULL);
78
79         ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
80         if (0 != ret) {
81                 SETTING_TRACE_ERROR("pthread_setcancelstate() Fail(%d)", ret);
82                 pthread_exit(NULL);
83         }
84
85         worker->fn_ret = worker->fn(worker->ad);
86
87         storageUG_STOP_POINT;
88
89         worker->worker_idler = ecore_idler_add(_async_worker_idler, worker);
90         if (worker->worker_idler == NULL) {
91                 SETTING_TRACE_ERROR("worker->worker_idler == NULL");
92                 worker->alive = FALSE;
93                 /*----------------------------------- */
94                 /* work around */
95                 /*----------------------------------- */
96                 _async_worker_idler(worker);
97
98         }
99         pthread_exit(NULL);
100 }
101
102 static void _async_worker_hash_free_key(gpointer data)
103 {
104         storageUg_worker *worker = data;
105
106         if (worker->alive) {
107                 pthread_cancel(worker->tid);
108                 pthread_join(worker->tid, NULL);
109         }
110
111         if (worker->worker_idler)
112                 ecore_idler_del(worker->worker_idler);
113
114         free(worker);
115 }
116
117
118 bool storageUg_worker_is_running(void *data)
119 {
120         storageUg_worker *worker = data;
121         SETTING_TRACE("*** worker->alive ------> %d ", worker->alive);
122         return worker->alive;
123 }
124
125 void *storageUg_start_async_worker(async_fn fn, callback_fn cb,
126                                    SettingStorageUG *ad)
127 {
128         int ret;
129         storageUg_worker *worker;
130
131         retv_if(NULL == fn, NULL);
132
133         if (NULL == storage_worker_hashT) {
134                 storage_worker_hashT = g_hash_table_new_full(NULL, NULL,
135                                                              _async_worker_hash_free_key, NULL);
136         }
137
138         worker = calloc(1, sizeof(storageUg_worker));
139         if (NULL == worker) {
140                 SETTING_TRACE_ERROR("calloc() Fail");
141                 return NULL;
142         }
143         worker->fn = fn;
144         worker->cb = cb;
145         worker->ad = ad;
146
147         g_hash_table_add(storage_worker_hashT, worker);
148
149         ret = pthread_create(&worker->tid, NULL, _async_worker_thread, worker);
150         warn_if(ret, "phread_create() Fail(%d)", ret);
151
152         worker->alive = TRUE;
153         return worker;
154 }
155
156 void storageUg_stop_async_worker(void *worker_id)
157 {
158         storageUg_worker *worker = worker_id;
159
160         ret_if(NULL == worker);
161
162         if (g_hash_table_contains(storage_worker_hashT, worker_id))
163                 g_hash_table_remove(storage_worker_hashT, worker_id);
164
165         if (0 == g_hash_table_size(storage_worker_hashT)) {
166                 g_hash_table_destroy(storage_worker_hashT);
167                 storage_worker_hashT = NULL;
168         }
169 }
170
171 void storageUg_stop_async_worker_all(void)
172 {
173         g_hash_table_destroy(storage_worker_hashT);
174         storage_worker_hashT = NULL;
175 }