2 * Copyright 2012 Samsung Electronics Co., Ltd
4 * Licensed under the Flora License, Version 1.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.tizenopensource.org/license
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.
20 #include <linux/unistd.h>
22 #include <vconf-keys.h>
24 #include "gl-thread-util.h"
25 #include "gl-ui-util.h"
28 #include "gl-db-handler.h"
30 #include "gl-progressbar.h"
31 #include "gl-strings.h"
33 #define GALLERY_MAGIC_MAIN_CONTEXT (0x1983cdaf)
34 #define GALLERY_MAGIC_DETAIL_LIST_ITEM (0x1977abcd)
35 #define GALLERY_MAGIC_PIPE_DATA (0x0716ffcc)
37 #define GALLERY_MAGIC unsigned int __magic
38 #define GALLERY_MAGIC_SET(d, m) (d)->__magic = (m)
39 #define GALLERY_MAGIC_CHECK(d, m) ((d) && ((d)->__magic == (m)))
45 int state; /* 0: operation is over; 1: operation is in process */
47 } gl_thread_pipe_data;
51 _gl_thread_gettid(void)
53 return syscall(__NR_gettid);
56 static int _gl_thread_operate_medias(void *data)
58 GL_CHECK_VAL(data, -1);
59 gl_appdata *ad = (gl_appdata *)data;
62 switch (ad->maininfo.medias_op_type) {
63 case GL_MEDIA_OP_DELETE:
65 ret = gl_del_selected(data);
67 case GL_MEDIA_OP_MOVE:
69 ret = gl_move_selected(data);
72 gl_dbgE("Unknow media operation mode!");
77 gl_dbgE("Operation failed!");
85 _gl_thread_update_view(void *data)
87 GL_CHECK_VAL(data, -1);
88 gl_appdata *ad = (gl_appdata *)data;
90 switch (ad->maininfo.medias_op_type) {
91 case GL_MEDIA_OP_DELETE:
93 gl_update_del_view(data);
95 case GL_MEDIA_OP_MOVE:
97 gl_update_move_view(data);
100 gl_dbgE("Unknow media operation mode!");
108 _gl_thread_data_thread(void *data)
111 gl_appdata *ad = (gl_appdata *)data;
114 gl_dbg("@@@@@@@@@@ :::: Child thread ID = %d :::: @@@@@@@@@@", _gl_thread_gettid());
115 //Different thread, need to initialize libmedia-info.
118 /* Media movement/deleting operation */
119 _gl_thread_operate_medias(data);
121 /* send finish signal */
122 gl_thread_pipe_data pipe_data;
123 memset(&pipe_data, 0x00, sizeof(gl_thread_pipe_data));
124 GALLERY_MAGIC_SET(&pipe_data, GALLERY_MAGIC_PIPE_DATA);
127 gl_thread_get_cancel_state(ad, &cancel_flag);
129 ecore_pipe_write(ad->pbarinfo.sync_pipe, &pipe_data, sizeof(gl_thread_pipe_data));
131 gl_dbg("@@@@@@@@@@ :::: Child thread done :::: @@@@@@@@@@");
136 static Eina_Bool _gl_thread_del_pbar_idler_cb(void *data)
138 gl_dbg("Delete progressbar...");
139 GL_CHECK_CANCEL(data);
140 gl_appdata *ad = (gl_appdata *)data;
141 /* Reset pb_cancel */
142 gl_thread_set_cancel_state(ad, GL_PB_CANCEL_NONE);
143 /* Operation done, destroy progressbar */
147 gl_thread_destroy_lock(ad);
149 if (ad->pbarinfo.del_pbar_idler) {
150 ecore_idler_del(ad->pbarinfo.del_pbar_idler);
151 ad->pbarinfo.del_pbar_idler = NULL;
153 return ECORE_CALLBACK_CANCEL;
157 _gl_thread_pipe_cb(void *data, void *buffer, unsigned int nbyte)
159 gl_dbg(":::::::::: Main thread ID = %d ::::::::::", _gl_thread_gettid());
162 gl_appdata *ad = (gl_appdata *)data;
163 gl_thread_pipe_data *p_pipe_data = (gl_thread_pipe_data *) buffer;
164 gl_dbg("Pipe state is %d", p_pipe_data->state);
166 if (!GALLERY_MAGIC_CHECK(p_pipe_data, GALLERY_MAGIC_PIPE_DATA)) {
167 gl_dbgE("##### :: Check p_pipe_data Magic failed :: #####");
171 int cancel_flag = false;
172 gl_thread_get_cancel_state(ad, &cancel_flag);
174 if (p_pipe_data->popup_op)
176 if (p_pipe_data->state)
178 /* Check cancel_flag */
179 if (cancel_flag != GL_PB_CANCEL_NORMAL) {
180 gl_dbgE("Failed to kill thread, try again!");
181 gl_thread_emit_next_signal(ad);
184 char msg[GL_FILE_PATH_LEN_MAX] = { 0, };
185 gl_item *cur_gitem = NULL;
186 /* Get selected media */
187 gl_db_get_item_by_index(ad, p_pipe_data->finished_cnt, true, &cur_gitem);
189 GL_CHECK(cur_gitem->item);
190 GL_CHECK(cur_gitem->item->display_name);
192 if (p_pipe_data->popup_op == GL_POPUP_OP_SAME_ALBUM)
194 snprintf(msg, sizeof(msg), "Cannot move %s to the same album!",
195 cur_gitem->item->display_name);
197 else if (p_pipe_data->popup_op == GL_POPUP_OP_DUPLICATED_NAME)
199 snprintf(msg, sizeof(msg), "%s is duplicated, rename it!",
200 cur_gitem->item->display_name);
202 else if (p_pipe_data->popup_op == GL_POPUP_OP_PROTECTED_FILE)
204 snprintf(msg, sizeof(msg), "Cannot removed protected file %s!",
205 cur_gitem->item->display_name);
207 gl_dbg("Popup description: %s", msg);
208 gl_popup_create_popup(ad, GL_POPUP_NOBUT_MOV_DEL, msg);
210 else if (ad->popupinfo.popup)
213 * If p_pipe_data->state is equal to 0,
214 * it means thread should be destoryed.
216 evas_object_del(ad->popupinfo.popup);
217 ad->popupinfo.popup = NULL;
221 /* Update progressbar state */
222 int all_cnt = gl_db_selected_list_count(ad);
224 if (p_pipe_data->state) {
225 /* Check cancel_flag */
226 if (cancel_flag != GL_PB_CANCEL_NORMAL) {
227 gl_dbgE("Failed to kill thread, try again!");
228 gl_thread_emit_next_signal(ad);
231 /* 1. Moving/deleting is in porcess */
232 gl_pb_refresh_thread_pbar(ad, p_pipe_data->finished_cnt, all_cnt);
233 gl_dbg("@@@ finished/all = %d/%d, updating progressbar @@@",
234 p_pipe_data->finished_cnt, all_cnt);
235 /* Emit signal to notice child thread handle next media */
236 gl_dbg("Emit next signal...");
237 gl_thread_emit_next_signal(ad);
239 /* 2. Moving/deleting is over, show finished count */
240 gl_dbg("@@@ finished: %d, updating progressbar @@@",
241 ad->pbarinfo.finished_cnt);
242 gl_pb_refresh_thread_pbar(ad, ad->pbarinfo.finished_cnt,
243 ad->pbarinfo.finished_cnt);
244 ad->pbarinfo.finished_cnt = 0;
245 gl_dbg("@@@@@@@ :::: Pipe close && Update view :::: @@@@@@@");
246 int cancel_flag = false;
247 bool b_reset = false;
248 gl_thread_get_cancel_state(ad, &cancel_flag);
249 if (cancel_flag == GL_PB_CANCEL_RESET) {
250 /* Set medias_op_type none to stop refreshing view*/
251 ad->maininfo.medias_op_type = GL_MEDIA_OP_NONE;
252 gl_dbgW("Cancel error case, set reset state!");
256 /* Use idler to delete progressbar to refresh status totally */
257 if (ad->pbarinfo.del_pbar_idler) {
258 ecore_idler_del(ad->pbarinfo.del_pbar_idler);
259 ad->pbarinfo.del_pbar_idler = NULL;
261 Ecore_Idler *idler= NULL;
262 idler = ecore_idler_add(_gl_thread_del_pbar_idler_cb, ad);
263 ad->pbarinfo.del_pbar_idler = idler;
265 int mmc_state = ad->maininfo.mmc_state;
266 int op_type = ad->maininfo.medias_op_type;
267 gl_dbg("MMC state: %d, OP type: %d.", mmc_state, op_type);
268 /* Operate medias related to MMC while moving medias */
269 if (mmc_state == GL_MMC_STATE_REMOVED_MOVING) {
270 ad->maininfo.mmc_state = GL_MMC_STATE_REMOVED;
273 * Albums: Move/Delete.
275 * Case 1: Source folder does exist, update view.
276 * Case 2: Source folder is MMC, and it vanished.
278 gl_cluster *cur_album = ad->albuminfo.current_album;
279 if (cur_album && cur_album->cluster &&
280 cur_album->cluster->type == MINFO_MMC) {
281 gl_dbgW("MMC removed, change to albums view!");
282 gl_pop_to_ctrlbar_ly(ad, true);
284 _gl_thread_update_view(ad);
287 /* Operated files on MMC, reset MMC state */
288 if (mmc_state == GL_MMC_STATE_ADDED_MOVING)
289 ad->maininfo.mmc_state = GL_MMC_STATE_ADDED;
290 else if (mmc_state == GL_MMC_STATE_ADDING_MOVING)
291 ad->maininfo.mmc_state = GL_MMC_STATE_ADDED;
293 _gl_thread_update_view(ad);
296 /* Free Ecore_Pipe object created */
297 if (ad->pbarinfo.sync_pipe) {
298 ecore_pipe_del(ad->pbarinfo.sync_pipe);
299 ad->pbarinfo.sync_pipe = NULL;
303 /* Free selected list */
304 gl_db_selected_list_finalize(ad);
305 gl_dbgW("Thread cancellation is over, reset gallery!");
306 /* Continue remake gallery */
307 gallery_reset_app(ad, ad->albuminfo.aul_album_id);
309 /* Set medias_op_type none to stop refreshing view*/
310 ad->maininfo.medias_op_type = GL_MEDIA_OP_NONE;
315 /*******************************************************
316 ** Prototype : gl_thread_emit_next_signal
317 ** Description : Emit signal to notice child thread handle next media.
318 ** Input : void *data
325 ** 1.Date : 2011/06/10
327 ** Modification : Created function
329 *********************************************************/
331 gl_thread_emit_next_signal(void *data)
333 GL_CHECK_VAL(data, -1);
334 gl_appdata *ad = (gl_appdata *)data;
336 pthread_mutex_lock(&(ad->pbarinfo.refresh_lock));
337 gl_dbg("refresh_flag: %d.", ad->pbarinfo.refresh_flag);
338 if (ad->pbarinfo.refresh_flag == 0)
340 ad->pbarinfo.refresh_flag = 1;
341 pthread_cond_signal(&(ad->pbarinfo.refresh_cond));
343 pthread_mutex_unlock(&(ad->pbarinfo.refresh_lock));
348 /*******************************************************
349 ** Prototype : gl_thread_wait_next_signal
350 ** Description : Wait start signal to handle next media.
351 ** Input : void *data
358 ** 1.Date : 2011/06/10
360 ** Modification : Created function
362 *********************************************************/
364 gl_thread_wait_next_signal(void *data)
366 GL_CHECK_VAL(data, -1);
367 gl_appdata *ad = (gl_appdata *)data;
369 pthread_mutex_lock(&(ad->pbarinfo.refresh_lock));
370 gl_dbg("refresh_flag: %d.", ad->pbarinfo.refresh_flag);
371 while (ad->pbarinfo.refresh_flag == 0)
373 gl_dbg("Thread waiting...");
374 pthread_cond_wait(&(ad->pbarinfo.refresh_cond), &(ad->pbarinfo.refresh_lock));
376 ad->pbarinfo.refresh_flag = 0;
377 pthread_mutex_unlock(&(ad->pbarinfo.refresh_lock));
382 /*******************************************************
383 ** Prototype : gl_thread_set_cancel_state
384 ** Description : Set the value of cancel flag.
385 ** Input : void *data
393 ** 1.Date : 2011/06/10
395 ** Modification : Created function
397 *********************************************************/
399 gl_thread_set_cancel_state(void *data, int val)
401 GL_CHECK_VAL(data, -1);
402 gl_appdata *ad = (gl_appdata *)data;
404 pthread_mutex_lock(&(ad->pbarinfo.pbar_lock));
405 ad->pbarinfo.pbar_cancel = val;
406 pthread_mutex_unlock(&(ad->pbarinfo.pbar_lock));
411 /*******************************************************
412 ** Prototype : gl_thread_get_cancel_state
413 ** Description : Get the value of cancel flag.
414 ** Input : void *data
421 ** 1.Date : 2011/06/10
423 ** Modification : Created function
425 *********************************************************/
427 gl_thread_get_cancel_state(void *data, int *val)
429 GL_CHECK_VAL(val, -1);
430 gl_appdata *ad = (gl_appdata *)data;
432 pthread_mutex_lock(&(ad->pbarinfo.pbar_lock));
433 *val = ad->pbarinfo.pbar_cancel;
434 pthread_mutex_unlock(&(ad->pbarinfo.pbar_lock));
440 /*******************************************************
441 ** Prototype : gl_thread_write_pipe
442 ** Description : Write date to pipe in order to make progressbar refreshed
443 ** Input : void *data
444 ** Input : int finished_cnt
445 ** Input : int popup_op
452 ** 1.Date : 2011/06/10
454 ** Modification : Created function
456 *********************************************************/
458 gl_thread_write_pipe(void *data, int finished_cnt, int popup_op)
461 gl_appdata *ad = (gl_appdata *)data;
462 int cancel_flag = false;
464 gl_dbg("Wait next signal...");
465 gl_thread_wait_next_signal(ad);
467 gl_thread_pipe_data pipe_data;
468 memset(&pipe_data, 0x00, sizeof(gl_thread_pipe_data));
469 GALLERY_MAGIC_SET(&pipe_data, GALLERY_MAGIC_PIPE_DATA);
472 pipe_data.finished_cnt = finished_cnt;
473 pipe_data.popup_op = popup_op;
475 gl_thread_get_cancel_state(ad, &cancel_flag);
477 if (cancel_flag == GL_PB_CANCEL_BUTTON ||
478 cancel_flag == GL_PB_CANCEL_MMC ||
479 cancel_flag == GL_PB_CANCEL_ERROR ||
480 cancel_flag == GL_PB_CANCEL_RESET)
482 //send cancel signal through pipe
483 pipe_data.finished_cnt = -1;
486 ecore_pipe_write(ad->pbarinfo.sync_pipe, &pipe_data, sizeof(gl_thread_pipe_data));
487 //exit the child thread
488 if (cancel_flag == GL_PB_CANCEL_BUTTON)
490 gl_dbg("Cancel button tapped, child thread exit!");
492 else if (cancel_flag == GL_PB_CANCEL_MMC)
494 gl_dbg("MMC removed, child thread exit!");
496 else if (cancel_flag == GL_PB_CANCEL_ERROR)
498 gl_dbg("Error happened, child thread exit!");
500 else if (cancel_flag == GL_PB_CANCEL_RESET) {
501 gl_dbg("Reset gallery, child thread exit!");
504 pthread_exit((void *)1);
508 gl_dbg("Writing pipe...");
509 ecore_pipe_write(ad->pbarinfo.sync_pipe, &pipe_data, sizeof(gl_thread_pipe_data));
513 /*******************************************************
514 ** Prototype : gl_thread_gen_data_thread
515 ** Description : Create child thread for moving or deleting medias
516 ** Input : void *data
523 ** 1.Date : 2011/06/10
525 ** Modification : Created function
527 *********************************************************/
529 gl_thread_gen_data_thread(void *data)
531 GL_CHECK_VAL(data, -1);
532 gl_appdata *ad = (gl_appdata *)data;
537 gl_dbg("Creating child thread.");
538 //add pipe for update progressbar status
539 ad->pbarinfo.sync_pipe = ecore_pipe_add(_gl_thread_pipe_cb, ad);
540 //initialize thread attributes
541 ret = pthread_attr_init(&attr);
544 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
547 //create child thread
548 ret = pthread_create(&tid, &attr, _gl_thread_data_thread, ad);
551 gl_dbgE("[Error] ##### :: pthread_create failed :: #####");
552 pthread_attr_destroy(&attr);
558 gl_dbg("\n\n[Done] @@@@@@@@@@ :::: pthread_create successfull :::: @@@@@@@@@@\n");
559 pthread_attr_destroy(&attr);
564 /*******************************************************
565 ** Prototype : gl_thread_destroy_lock
566 ** Description : Destroy mutex lock.
567 ** Input : void *data
574 ** 1.Date : 2011/06/10
576 ** Modification : Created function
578 *********************************************************/
580 gl_thread_destroy_lock(void *data)
582 GL_CHECK_VAL(data, -1);
583 gl_appdata *ad = (gl_appdata *)data;
584 gl_dbg("@@@@@@@@@@ :::: Destroy MUTEX :::: @@@@@@@@@@");
587 * The variable below was accessed without holding a guarding lock.
588 * In a multithreaded environment, this can lead to a race condition.
589 * Add lock to prevent from RC.
591 pthread_mutex_lock(&(ad->pbarinfo.refresh_lock));
592 ad->pbarinfo.refresh_flag = 0;
593 pthread_mutex_unlock(&(ad->pbarinfo.refresh_lock));
595 pthread_cond_destroy(&(ad->pbarinfo.refresh_cond));
596 pthread_mutex_destroy(&(ad->pbarinfo.pbar_lock));
597 pthread_mutex_destroy(&(ad->pbarinfo.refresh_lock));
602 /*******************************************************
603 ** Prototype : gl_thread_init_lock
604 ** Description : Initialize mutex lock
605 ** Input : void *data
612 ** 1.Date : 2011/06/10
614 ** Modification : Created function
616 *********************************************************/
618 gl_thread_init_lock(void *data)
620 GL_CHECK_VAL(data, -1);
621 gl_appdata *ad = (gl_appdata *)data;
622 gl_dbg("@@@@@@@@@@ :::: Initialize MUTEX :::: @@@@@@@@@@");
624 pthread_mutex_init(&(ad->pbarinfo.pbar_lock), NULL);
625 pthread_mutex_init(&(ad->pbarinfo.refresh_lock), NULL);
626 pthread_cond_init(&(ad->pbarinfo.refresh_cond), NULL);
629 * The variable below was accessed without holding a guarding lock.
630 * In a multithreaded environment, this can lead to a race condition.
631 * Add lock to prevent from RC.
633 pthread_mutex_lock(&(ad->pbarinfo.refresh_lock));
634 ad->pbarinfo.refresh_flag = 0;
635 pthread_mutex_unlock(&(ad->pbarinfo.refresh_lock));