2 * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <signal.h> // pthread_kill
19 #include <errno.h> // ESRCH
22 #include <download-provider-log.h>
23 #include <download-provider-pthread.h>
25 #include <download-provider-db-defs.h>
26 #include <download-provider-db.h>
27 #include <download-provider-queue.h>
28 #include <download-provider-network.h>
29 #include <download-provider-notify.h>
30 #include <download-provider-client.h>
31 #include <download-provider-client-manager.h>
32 #include <download-provider-plugin-download-agent.h>
34 static pthread_mutex_t g_dp_queue_manager_mutex = PTHREAD_MUTEX_INITIALIZER;
35 static pthread_cond_t g_dp_queue_manager_cond = PTHREAD_COND_INITIALIZER;
36 static pthread_t g_dp_queue_manager_tid = 0;
38 static dp_queue_fmt *g_dp_queue_network_all = NULL;
39 static dp_queue_fmt *g_dp_queue_network_wifi = NULL;
40 static dp_queue_fmt *g_dp_queue_network_data_network = NULL;
41 static dp_queue_fmt *g_dp_queue_network_wifi_direct = NULL;
43 static dp_queue_fmt **__dp_queue_manager_get_queue(int network)
47 //TRACE_DEBUG("network all");
48 return &g_dp_queue_network_all;
50 //TRACE_DEBUG("network wifi only");
51 return &g_dp_queue_network_wifi;
52 case DP_NETWORK_DATA_NETWORK:
53 //TRACE_DEBUG("network data network only");
54 return &g_dp_queue_network_data_network;
55 case DP_NETWORK_WIFI_DIRECT:
56 //TRACE_DEBUG("network wifi-direct");
57 return &g_dp_queue_network_wifi_direct;
63 int dp_queue_manager_push_queue(void *slot, void *request)
65 dp_request_fmt *requestp = request;
66 if (slot == NULL || request == NULL) {
67 TRACE_DEBUG("check address client:%p request:%p id:%d", slot,
68 request, (request == NULL ? 0 : requestp->id));
71 dp_queue_fmt **queue = __dp_queue_manager_get_queue(requestp->network_type);
72 if (requestp->state != DP_STATE_QUEUED) {
73 TRACE_ERROR("check id:%d state:%s", requestp->id, dp_print_state(requestp->state));
76 if (dp_queue_push(queue, slot, request) < 0) {
77 TRACE_ERROR("failed to push to queue id:%d", requestp->id);
83 void dp_queue_manager_clear_queue(void *request)
85 dp_request_fmt *requestp = request;
86 if (request == NULL) {
87 TRACE_DEBUG("check address request:%p id:%d",
88 request, (request == NULL ? 0 : requestp->id));
91 dp_queue_fmt **queue = __dp_queue_manager_get_queue(requestp->network_type);
92 dp_queue_clear(queue, request);
95 // if return negative, queue-manager try again.
96 static int __dp_queue_manager_try_download(dp_client_slots_fmt *slot, dp_request_fmt *request)
98 int errorcode = DP_ERROR_NONE;
101 if (slot == NULL || request == NULL) {
102 TRACE_DEBUG("check address client:%p request:%p id:%d", slot,
103 request, (request == NULL ? 0 : request->id));
104 // return 0 to ignore this call.
108 if (request->state != DP_STATE_QUEUED) {
109 TRACE_ERROR("check id %d state:%d", request->id, request->state);
115 request->startcount++;
116 request->access_time = (int)time(NULL);
118 if (dp_db_replace_property(slot->client.dbhandle, request->id,
119 DP_TABLE_LOGGING, DP_DB_COL_STARTCOUNT,
120 (void *)&request->startcount, 0, 0, &errorcode) < 0) {
121 TRACE_ERROR("failed to set startcount");
125 errorcode = DP_ERROR_NONE;
127 if (dp_is_alive_download(request->agent_id) > 0)
128 errorcode = dp_resume_agent_download(request->agent_id);
130 // call agent start function
131 errorcode = dp_start_agent_download(slot, request);
133 if (errorcode == DP_ERROR_NONE) {
134 request->state = DP_STATE_CONNECTING;
135 } else if (errorcode == DP_ERROR_TOO_MANY_DOWNLOADS ||
136 errorcode == DP_ERROR_DISK_BUSY ||
137 errorcode == DP_ERROR_OUT_OF_MEMORY) {
138 TRACE_ERROR("push queue id:%d error:%s", request->id, dp_print_errorcode(errorcode));
140 request->state = DP_STATE_QUEUED;
141 result = -1; // try again.
142 } else if (errorcode == DP_ERROR_INVALID_STATE) { // by resume
143 // ignore this request
145 TRACE_ERROR("failed to resume id:%d", request->id);
146 request->agent_id = -1; // workaround. da_agent will an object for this agent_id later
147 } else if (errorcode != DP_ERROR_NONE) {
148 request->state = DP_STATE_FAILED;
151 request->error = errorcode;
153 if (result == 0) { // it's not for retrying
154 int sqlerror = DP_ERROR_NONE;
155 if (dp_db_update_logging(slot->client.dbhandle, request->id,
156 request->state, request->error, &sqlerror) < 0) {
157 TRACE_ERROR("logging failure id:%d error:%d", request->id, sqlerror);
159 if (errorcode != DP_ERROR_NONE && request->state_cb == 1) { // announce state
161 TRACE_ERROR("notify id:%d error:%s", request->id, dp_print_errorcode(errorcode));
162 if (dp_notify_feedback(slot->client.notify, slot,
163 request->id, request->state, request->error, 0) < 0) {
164 TRACE_ERROR("disable state callback by IO_ERROR id:%d", request->id);
165 request->state_cb = 0;
174 static int __dp_queue_manager_check_queue(dp_queue_fmt **queue)
176 dp_client_slots_fmt *slot = NULL;
177 dp_request_fmt *request = NULL;
178 while (dp_queue_pop(queue, (void *)&slot, (void *)&request) == 0) { // pop a request from queue.
179 TRACE_DEBUG("queue-manager pop a request");
180 if (slot == NULL || request == NULL) {
181 TRACE_DEBUG("queue error client:%p request:%p id:%d", slot, request, (request == NULL ? 0 : request->id));
185 CLIENT_MUTEX_LOCK(&slot->mutex);
187 TRACE_DEBUG("queue info slot:%p request:%p id:%d", slot, request, (request == NULL ? 0 : request->id));
189 int errorcode = DP_ERROR_NONE;
190 int download_state = DP_STATE_NONE;
191 if (slot != NULL && request != NULL &&
192 dp_db_get_property_int(slot->client.dbhandle, request->id, DP_TABLE_LOGGING, DP_DB_COL_STATE, &download_state, &errorcode) < 0) {
193 TRACE_ERROR("deny checking id:%d db state:%s memory:%s", request->id, dp_print_state(download_state), dp_print_state(request->state));
194 errorcode = DP_ERROR_ID_NOT_FOUND;
197 if (download_state == DP_STATE_QUEUED && __dp_queue_manager_try_download(slot, request) < 0) {
198 // if failed to start, push at the tail of queue. try again.
199 if (dp_queue_push(queue, slot, request) < 0) {
200 TRACE_ERROR("failed to push to queue id:%d", request->id);
201 int errorcode = DP_ERROR_NONE;
202 if (dp_db_update_logging(slot->client.dbhandle, request->id, DP_STATE_FAILED, DP_ERROR_QUEUE_FULL, &errorcode) < 0)
203 TRACE_ERROR("failed to update log id:%d", request->id);
204 request->state = DP_STATE_FAILED;
205 request->error = DP_ERROR_QUEUE_FULL;
207 CLIENT_MUTEX_UNLOCK(&slot->mutex);
208 return -1; // return negative for taking a break
211 CLIENT_MUTEX_UNLOCK(&slot->mutex);
219 static void *__dp_queue_manager(void *arg)
221 pthread_cond_init(&g_dp_queue_manager_cond, NULL);
223 if (dp_init_agent() != DP_ERROR_NONE) {
224 TRACE_ERROR("failed to init agent");
225 pthread_cond_destroy(&g_dp_queue_manager_cond);
232 if (g_dp_queue_manager_tid <= 0) {
233 TRACE_INFO("queue-manager is closed by other thread");
237 // check wifi_direct first
238 if (dp_network_is_wifi_direct() == 1 && __dp_queue_manager_check_queue(&g_dp_queue_network_wifi_direct) < 0) {
239 TRACE_ERROR("download-agent is busy, try again after 15 seconds");
240 } else { // enter here if disable wifi-direct or download-agent is available
241 int network_status = dp_network_get_status();
242 if (network_status != DP_NETWORK_OFF) {
243 TRACE_INFO("queue-manager try to check queue network:%d", network_status);
244 if (g_dp_queue_network_all != NULL && __dp_queue_manager_check_queue(&g_dp_queue_network_all) < 0) {
245 TRACE_ERROR("download-agent is busy, try again after 15 seconds");
247 dp_queue_fmt **queue = __dp_queue_manager_get_queue(network_status);
248 if (__dp_queue_manager_check_queue(queue) < 0)
249 TRACE_ERROR("download-agent is busy, try again after 15 seconds");
256 gettimeofday(&now, NULL);
257 ts.tv_sec = now.tv_sec + 5;
258 ts.tv_nsec = now.tv_usec * 1000;
259 CLIENT_MUTEX_LOCK(&g_dp_queue_manager_mutex);
260 pthread_cond_timedwait(&g_dp_queue_manager_cond, &g_dp_queue_manager_mutex, &ts);
261 CLIENT_MUTEX_UNLOCK(&g_dp_queue_manager_mutex);
262 } while (g_dp_queue_manager_tid > 0);
264 TRACE_INFO("queue-manager's working is done");
266 dp_queue_clear_all(&g_dp_queue_network_all);
267 pthread_cond_destroy(&g_dp_queue_manager_cond);
272 static int __dp_queue_manager_start()
274 if (g_dp_queue_manager_tid == 0 ||
275 pthread_kill(g_dp_queue_manager_tid, 0) == ESRCH) {
276 TRACE_DEBUG("try to create queue-manager");
277 if (pthread_create(&g_dp_queue_manager_tid, NULL,
278 __dp_queue_manager, NULL) != 0) {
279 TRACE_ERROR("failed to create queue-manager");
286 void dp_queue_manager_wake_up()
288 if (g_dp_queue_manager_tid > 0 &&
289 pthread_kill(g_dp_queue_manager_tid, 0) != ESRCH) {
290 int locked = CLIENT_MUTEX_TRYLOCK(&g_dp_queue_manager_mutex);
291 if (locked == 0 || locked == EBUSY) {
292 pthread_cond_signal(&g_dp_queue_manager_cond);
293 CLIENT_MUTEX_UNLOCK(&g_dp_queue_manager_mutex);
296 __dp_queue_manager_start();
300 void dp_queue_manager_kill()
302 if (g_dp_queue_manager_tid > 0 &&
303 pthread_kill(g_dp_queue_manager_tid, 0) != ESRCH) {
304 //send signal to queue thread
307 tid = g_dp_queue_manager_tid;
308 CLIENT_MUTEX_LOCK(&g_dp_queue_manager_mutex);
309 g_dp_queue_manager_tid = 0;
310 pthread_cond_signal(&g_dp_queue_manager_cond);
311 CLIENT_MUTEX_UNLOCK(&g_dp_queue_manager_mutex);
312 pthread_join(tid, &status);