X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Ftdm_thread.c;h=6ca28f2e0a76536ac4d8ff3fbb5e2847b9f1fe24;hb=e304b438166ecfce08fec402ffe1b9b855e54644;hp=6e891d7ea6e8b3f65c75dd184e719307873e039c;hpb=758bfd1906831fa520a2e26e795169c0d431570c;p=platform%2Fcore%2Fuifw%2Flibtdm.git diff --git a/src/tdm_thread.c b/src/tdm_thread.c index 6e891d7..6ca28f2 100644 --- a/src/tdm_thread.c +++ b/src/tdm_thread.c @@ -9,7 +9,7 @@ * Taeheon Kim , * YoungJun Cho , * SooChan Lim , - * Boram Park + * Boram Park * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the @@ -46,6 +46,8 @@ struct _tdm_private_thread { pthread_cond_t event_cond; pthread_t event_thread; + unsigned int event_thread_exit; + unsigned int event_thread_joined; pid_t display_tid; pid_t thread_tid; @@ -152,6 +154,9 @@ _tdm_thread_main(void *data) TDM_INFO("server flush"); tdm_event_loop_flush(private_loop->dpy); + if (private_thread->event_thread_exit) + break; + if (tdm_debug_module & TDM_DEBUG_EVENT) TDM_INFO("fd(%d) polling in", fd); @@ -181,6 +186,22 @@ exit_thread: pthread_exit(NULL); } +static tdm_error +_tdm_thread_exit(tdm_private_loop *private_loop) +{ + tdm_thread_cb_base cb_base; + tdm_error ret; + + memset(&cb_base, 0, sizeof cb_base); + cb_base.type = TDM_THREAD_CB_EXIT; + cb_base.length = sizeof cb_base; + + ret = tdm_thread_send_cb(private_loop, &cb_base); + TDM_RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret); + + return ret; +} + /* NOTE: tdm thread doesn't care about multi-thread. */ INTERN tdm_error tdm_thread_init(tdm_private_loop *private_loop) @@ -269,20 +290,16 @@ tdm_thread_deinit(tdm_private_loop *private_loop) { tdm_private_display *private_display; tdm_private_thread_cb *cb = NULL, *hh = NULL; - int i; + tdm_error ret; TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED()); - for (i = 0; i < TDM_THREAD_CB_MAX; i++) - find_funcs[i] = NULL; - if (!private_loop->private_thread) return; - if (private_loop->private_thread->sub_event_source) - tdm_event_loop_source_remove(private_loop->private_thread->sub_event_source); - - pthread_cancel(private_loop->private_thread->event_thread); + ret = _tdm_thread_exit(private_loop); + if (ret != TDM_ERROR_NONE) + pthread_cancel(private_loop->private_thread->event_thread); private_display = private_loop->dpy; @@ -291,11 +308,15 @@ tdm_thread_deinit(tdm_private_loop *private_loop) */ _pthread_mutex_unlock(&private_display->lock); pthread_join(private_loop->private_thread->event_thread, NULL); + private_loop->private_thread->event_thread_joined = 1; + TDM_INFO("Joined a TDM event thread"); - pthread_mutex_trylock(&cb_list_lock); pthread_mutex_unlock(&cb_list_lock); tdm_log_reset(); + if (private_loop->private_thread->sub_event_source) + tdm_event_loop_source_remove(private_loop->private_thread->sub_event_source); + LIST_FOR_EACH_ENTRY_SAFE(cb, hh, &cb_list[0], link) { _tdm_thread_free_cb(cb); } @@ -439,9 +460,13 @@ tdm_thread_handle_cb(tdm_private_loop *private_loop) case TDM_THREAD_CB_VBLANK_SW: case TDM_THREAD_CB_VBLANK_CREATE: case TDM_THREAD_CB_NEED_VALIDATE: - ret = tdm_thread_cb_call(NULL, base); + /* this event comes from other thread. so we don't need to propagate this to other thread */ + ret = tdm_thread_cb_call(NULL, base, 0); TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); break; + case TDM_THREAD_CB_EXIT: + private_thread->event_thread_exit = 1; + break; default: break; } @@ -467,7 +492,7 @@ tdm_thread_is_running(void) { /* DON'T check TDM_MUTEX_IS_LOCKED here */ - return (keep_private_thread) ? 1 : 0; + return (keep_private_thread && !keep_private_thread->event_thread_joined) ? 1 : 0; } static void @@ -594,7 +619,7 @@ tdm_thread_cb_remove(void *object, tdm_thread_cb_type cb_type, void *cb_data, td * because a callback is added with cb_type and cb_data. */ INTERN tdm_error -tdm_thread_cb_call(void *object, tdm_thread_cb_base *cb_base) +tdm_thread_cb_call(void *object, tdm_thread_cb_base *cb_base, unsigned int propagation) { tdm_private_display *private_display = tdm_display_get(); tdm_private_thread_cb *cb = NULL, *hh = NULL; @@ -603,7 +628,6 @@ tdm_thread_cb_call(void *object, tdm_thread_cb_base *cb_base) struct list_head *list, *other_list; struct list_head call_list; static pid_t waiting_tid = 0; - static tdm_thread_cb_type waiting_cb_type = TDM_THREAD_CB_NONE; tdm_error ret; TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED); @@ -616,12 +640,15 @@ tdm_thread_cb_call(void *object, tdm_thread_cb_base *cb_base) assert(find_funcs[cb_base->type] != NULL); - /* handling only output-status as sync */ - if (cb_base->type == TDM_THREAD_CB_OUTPUT_STATUS) { - TDM_RETURN_VAL_IF_FAIL(cb_base->sync == 1, TDM_ERROR_INVALID_PARAMETER); - } else { - TDM_RETURN_VAL_IF_FAIL(cb_base->sync == 0, TDM_ERROR_INVALID_PARAMETER); - } + if (tdm_debug_module & TDM_DEBUG_THREAD) + TDM_INFO("'%s' thread_cb (sync:%d, propagation:%d) ------", + tdm_cb_type_str(cb_base->type), cb_base->sync, propagation); + + /* handling only output-status as sync. below logic can't handle two sync-type events */ + if (cb_base->type == TDM_THREAD_CB_OUTPUT_STATUS) + assert(cb_base->sync == 1); + else + assert(cb_base->sync == 0); if (!object) { object = find_funcs[cb_base->type](private_display, cb_base->object_stamp); @@ -665,9 +692,7 @@ tdm_thread_cb_call(void *object, tdm_thread_cb_base *cb_base) pthread_mutex_unlock(&cb_list_lock); - assert(LIST_IS_EMPTY(&call_list)); - - if (waiting_tid == 0 || waiting_cb_type != cb_base->type) { + if (propagation) { LIST_FOR_EACH_ENTRY_SAFE(cb, hh, other_list, link) { if (cb->object != object || cb->cb_type != cb_base->type || @@ -681,27 +706,34 @@ tdm_thread_cb_call(void *object, tdm_thread_cb_base *cb_base) if (!handler_in_other_thread) { if (keep_private_thread) { - if (cb_base->sync) { + if (cb_base->sync && waiting_tid != 0) { waiting_tid = 0; - waiting_cb_type = TDM_THREAD_CB_NONE; pthread_cond_signal(&keep_private_thread->event_cond); if (tdm_debug_module & TDM_DEBUG_THREAD) TDM_INFO("pthread broadcase"); } } if (tdm_debug_module & TDM_DEBUG_THREAD) - TDM_INFO("'%s' thread_cb done(sync:%d)", tdm_cb_type_str(cb_base->type), cb_base->sync); + TDM_INFO("'%s' thread_cb (sync:%d, propagation:%d) ------...", + tdm_cb_type_str(cb_base->type), cb_base->sync, propagation); return TDM_ERROR_NONE; } /* Once we reach here, it means that keep_private_thread is not NULL. * Just make the crash. Avoiding it is not going to help us. */ + assert(keep_private_thread != NULL); + ret = tdm_thread_send_cb(private_display->private_loop, cb_base); TDM_RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, TDM_ERROR_OPERATION_FAILED); /* waiting until all cb are done in another thread */ if (cb_base->sync) { + /* if waiting_tid is not 0, it means there are two sync-type events at the same time. + * and it would make deadlock issue. + */ + assert(waiting_tid == 0); + if (tdm_debug_module & TDM_DEBUG_THREAD) TDM_INFO("pthread wait"); @@ -710,14 +742,13 @@ tdm_thread_cb_call(void *object, tdm_thread_cb_base *cb_base) */ tdm_mutex_locked = 0; waiting_tid = caller_tid; - waiting_cb_type = cb_base->type; - pthread_cond_wait(&keep_private_thread->event_cond, &private_display->lock); tdm_mutex_locked = 1; } if (tdm_debug_module & TDM_DEBUG_THREAD) - TDM_INFO("'%s' thread_cb done(sync:%d)", tdm_cb_type_str(cb_base->type), cb_base->sync); + TDM_INFO("'%s' thread_cb (sync:%d, propagation:%d) ------...", + tdm_cb_type_str(cb_base->type), cb_base->sync, propagation); return TDM_ERROR_NONE; }