X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Ftdm_thread.c;h=40d7859ed752a367e8ca2c0abeedbaea3ef1ca51;hb=95af5139e398eba6799b80b503ec2b98d0d9ee16;hp=3811bdc503570e1003bd23325e9014dfde6d815e;hpb=83e01cfd8d96500b77c4fb905bc8d768e425ea16;p=platform%2Fcore%2Fuifw%2Flibtdm.git diff --git a/src/tdm_thread.c b/src/tdm_thread.c index 3811bdc..40d7859 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; @@ -75,7 +77,7 @@ static tdm_thread_find_object find_funcs[TDM_THREAD_CB_MAX] = {0, }; /* 0: for display thread, 1: for tdm thread */ static struct list_head cb_list[2]; -static pthread_mutex_t cb_list_lock; +static pthread_mutex_t cb_list_lock = PTHREAD_MUTEX_INITIALIZER; static void _tdm_thread_free_cb(tdm_private_thread_cb *cb); @@ -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) @@ -201,11 +222,6 @@ tdm_thread_init(tdm_private_loop *private_loop) for (i = 0; i < TDM_THREAD_CB_MAX; i++) find_funcs[i] = NULL; - if (pthread_mutex_init(&cb_list_lock, NULL)) { - TDM_ERR("mutex init failed: %m"); - return TDM_ERROR_OUT_OF_MEMORY; - } - LIST_INITHEAD(&cb_list[0]); LIST_INITHEAD(&cb_list[1]); @@ -274,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; @@ -296,10 +308,14 @@ 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_unlock(&cb_list_lock); tdm_log_reset(); - pthread_mutex_destroy(&cb_list_lock); + 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); @@ -393,6 +409,7 @@ tdm_thread_handle_cb(tdm_private_loop *private_loop) char buffer[1024]; unsigned int i; int len, pipe, in_main; + tdm_error ret = TDM_ERROR_NONE; TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED); TDM_RETURN_VAL_IF_FAIL(private_loop, TDM_ERROR_INVALID_PARAMETER); @@ -434,15 +451,24 @@ tdm_thread_handle_cb(tdm_private_loop *private_loop) if (tdm_debug_module & TDM_DEBUG_THREAD) TDM_INFO("type(%s), length(%d)", tdm_cb_type_str(base->type), base->length); switch (base->type) { + case TDM_THREAD_CB_DISPLAY_OUTPUT_CREATE: + case TDM_THREAD_CB_OUTPUT_DESTROY: case TDM_THREAD_CB_OUTPUT_COMMIT: case TDM_THREAD_CB_OUTPUT_VBLANK: - case TDM_THREAD_CB_OUTPUT_CHANGE: + case TDM_THREAD_CB_OUTPUT_STATUS: + case TDM_THREAD_CB_OUTPUT_DPMS: case TDM_THREAD_CB_PP_DONE: case TDM_THREAD_CB_CAPTURE_DONE: case TDM_THREAD_CB_VBLANK_SW: case TDM_THREAD_CB_VBLANK_CREATE: - case TDM_THREAD_CB_NEED_VALIDATE: - tdm_thread_cb_call(NULL, base); + case TDM_THREAD_CB_HWC_COMMIT: + case TDM_THREAD_CB_VOUTPUT_COMMIT: + /* 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; @@ -469,7 +495,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 @@ -486,7 +512,7 @@ _tdm_thread_free_cb(tdm_private_thread_cb *cb) static tdm_private_thread_cb * _tdm_thread_find_cb(struct list_head *list, void *object, tdm_thread_cb_type cb_type, - void *cb_data, tdm_thread_cb func, void *user_data, pid_t caller_tid) + void *cb_data, tdm_thread_cb func, void *user_data) { tdm_private_thread_cb *cb = NULL; @@ -495,8 +521,7 @@ _tdm_thread_find_cb(struct list_head *list, void *object, tdm_thread_cb_type cb_ cb->cb_type == cb_type && cb->cb_data == cb_data && cb->func == func && - cb->user_data == user_data && - cb->owner_tid == caller_tid) + cb->user_data == user_data) return cb; } @@ -535,7 +560,7 @@ tdm_thread_cb_add(void *object, tdm_thread_cb_type cb_type, void *cb_data, tdm_t else list = &cb_list[1]; - cb = _tdm_thread_find_cb(list, object, cb_type, cb_data, func, user_data, caller_tid); + cb = _tdm_thread_find_cb(list, object, cb_type, cb_data, func, user_data); if (cb) { pthread_mutex_unlock(&cb_list_lock); TDM_ERR("can't be added twice with same data"); @@ -571,7 +596,6 @@ INTERN void tdm_thread_cb_remove(void *object, tdm_thread_cb_type cb_type, void *cb_data, tdm_thread_cb func, void *user_data) { tdm_private_thread_cb *cb; - pid_t caller_tid; struct list_head *list; TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED()); @@ -579,22 +603,18 @@ tdm_thread_cb_remove(void *object, tdm_thread_cb_type cb_type, void *cb_data, td TDM_RETURN_IF_FAIL(cb_type > 0); TDM_RETURN_IF_FAIL(func != NULL); - caller_tid = syscall(SYS_gettid); - pthread_mutex_lock(&cb_list_lock); - if (tdm_thread_in_display_thread(caller_tid)) - list = &cb_list[0]; - else - list = &cb_list[1]; + list = &cb_list[0]; + cb = _tdm_thread_find_cb(list, object, cb_type, cb_data, func, user_data); + if (cb) + _tdm_thread_free_cb(cb); - cb = _tdm_thread_find_cb(list, object, cb_type, cb_data, func, user_data, caller_tid); - if (!cb) { - pthread_mutex_unlock(&cb_list_lock); - return; - } + list = &cb_list[1]; + cb = _tdm_thread_find_cb(list, object, cb_type, cb_data, func, user_data); + if (cb) + _tdm_thread_free_cb(cb); - _tdm_thread_free_cb(cb); pthread_mutex_unlock(&cb_list_lock); } @@ -602,7 +622,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; @@ -610,19 +630,31 @@ tdm_thread_cb_call(void *object, tdm_thread_cb_base *cb_base) pid_t caller_tid; struct list_head *list, *other_list; struct list_head call_list; + static pid_t waiting_tid = 0; tdm_error ret; TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED); TDM_RETURN_VAL_IF_FAIL(cb_base != NULL, TDM_ERROR_INVALID_PARAMETER); TDM_RETURN_VAL_IF_FAIL(cb_base->type > 0, TDM_ERROR_INVALID_PARAMETER); TDM_RETURN_VAL_IF_FAIL(cb_base->length > 0, TDM_ERROR_INVALID_PARAMETER); - TDM_RETURN_VAL_IF_FAIL(cb_base->sync == 0 || cb_base->sync == 1, TDM_ERROR_INVALID_PARAMETER); TDM_RETURN_VAL_IF_FAIL(cb_base->object_stamp > 0, TDM_ERROR_INVALID_PARAMETER); caller_tid = syscall(SYS_gettid); assert(find_funcs[cb_base->type] != NULL); + if (keep_private_thread && keep_private_thread->thread_tid != caller_tid) { + /* A sync-type event from display-thread to tdm-thread can't be handled. + * If sync-type events happen in both threads at the same time, + * it would make a deadlock issue. + */ + assert(cb_base->sync != 1); + } + + 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); + if (!object) { object = find_funcs[cb_base->type](private_display, cb_base->object_stamp); if (!object) { @@ -665,39 +697,65 @@ tdm_thread_cb_call(void *object, tdm_thread_cb_base *cb_base) pthread_mutex_unlock(&cb_list_lock); - assert(LIST_IS_EMPTY(&call_list)); - - LIST_FOR_EACH_ENTRY_SAFE(cb, hh, other_list, link) { - if (cb->object != object || - cb->cb_type != cb_base->type || - cb->cb_data != cb_base->data) - continue; + if (propagation) { + LIST_FOR_EACH_ENTRY_SAFE(cb, hh, other_list, link) { + if (cb->object != object || + cb->cb_type != cb_base->type || + cb->cb_data != cb_base->data) + continue; - handler_in_other_thread = 1; - break; + handler_in_other_thread = 1; + break; + } } if (!handler_in_other_thread) { if (keep_private_thread) { - if (cb_base->sync) { + /* NOTE quick fix + * In case of 'cb_base->sync = 0' and 'waiting_tid != 0', + * probably it means one thread is waiting for signal of + * pthread condition. + */ + if (!cb_base->sync && waiting_tid != 0) { + waiting_tid = 0; 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. */ - ret = tdm_thread_send_cb(private_display->private_loop, cb_base); - TDM_RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, TDM_ERROR_OPERATION_FAILED); + assert(keep_private_thread != NULL); + if (!cb_base->sync) { + 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) { + else { + /* NOTE quick fix + * Sync type event from display-thread(main thread) can't be + * handled. In this way, if we call tdm_thread_send_cb() with + * 'cb_base->sync = 1', then libtdm will eveventually raise + * abort(). Please see commit '4abfab36' for more detail. + */ + cb_base->sync = 0; + ret = tdm_thread_send_cb(private_display->private_loop, cb_base); + TDM_RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, TDM_ERROR_OPERATION_FAILED); + cb_base->sync = 1; + + /* 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"); @@ -705,12 +763,14 @@ tdm_thread_cb_call(void *object, tdm_thread_cb_base *cb_base) * the mutex shall have been locked and shall be owned by the calling thread */ tdm_mutex_locked = 0; + waiting_tid = caller_tid; 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; }