From 3b2ea9bbd4f335ed70ccc472414d6edc01e9f28e Mon Sep 17 00:00:00 2001 From: Boram Park Date: Thu, 18 Jan 2018 15:45:39 +0900 Subject: [PATCH] thread: support cb for multi-thread communication Change-Id: Ic59dd29fbc574232ec28e3a34e63533a8bd4d6f8 --- common/tdm_log.c | 7 + include/tdm_log.h | 1 + src/tdm.c | 6 + src/tdm_display.c | 7 +- src/tdm_macro.h | 14 ++ src/tdm_private.h | 3 + src/tdm_private_types.h | 4 + src/tdm_thread.c | 386 +++++++++++++++++++++++++++++++++++++++++++++--- src/tdm_thread.h | 13 ++ 9 files changed, 419 insertions(+), 22 deletions(-) diff --git a/common/tdm_log.c b/common/tdm_log.c index 0bad256..b77e765 100644 --- a/common/tdm_log.c +++ b/common/tdm_log.c @@ -189,3 +189,10 @@ tdm_log_print(int level, const char *fmt, ...) assert(0); #endif } + +EXTERN void +tdm_log_reset(void) +{ + pthread_mutex_trylock(&log_lock); + pthread_mutex_unlock(&log_lock); +} diff --git a/include/tdm_log.h b/include/tdm_log.h index 7ee4d95..02e8b0c 100644 --- a/include/tdm_log.h +++ b/include/tdm_log.h @@ -71,6 +71,7 @@ void tdm_log_set_debug_level(int level); void tdm_log_set_assert_level(int level); void tdm_log_set_path(const char *path); void tdm_log_print(int level, const char *fmt, ...); +void tdm_log_reset(void); extern unsigned int tdm_log_debug_level; diff --git a/src/tdm.c b/src/tdm.c index 69d9ebd..2536479 100644 --- a/src/tdm.c +++ b/src/tdm.c @@ -1120,6 +1120,12 @@ tdm_display_deinit(tdm_display *dpy) TDM_INFO("done"); } +INTERN tdm_private_display * +tdm_display_get(void) +{ + return g_private_display; +} + INTERN int tdm_display_is_valid(tdm_display *dpy) { diff --git a/src/tdm_display.c b/src/tdm_display.c index 5bd7ca6..abf4374 100644 --- a/src/tdm_display.c +++ b/src/tdm_display.c @@ -359,10 +359,13 @@ tdm_display_handle_events(tdm_display *dpy) if (tdm_debug_module & TDM_DEBUG_EVENT) TDM_INFO("fd(%d) polling out", fd); - if (tdm_thread_is_running()) + if (tdm_thread_is_running()) { + _pthread_mutex_lock(&private_display->lock); ret = tdm_thread_handle_cb(private_display->private_loop); - else + _pthread_mutex_unlock(&private_display->lock); + } else { ret = tdm_event_loop_dispatch(private_display); + } return ret; } diff --git a/src/tdm_macro.h b/src/tdm_macro.h index e75220c..77538a3 100644 --- a/src/tdm_macro.h +++ b/src/tdm_macro.h @@ -232,6 +232,20 @@ static struct tdm_type_name tdm_value_type_names[] = { }; TDM_TYPE_NAME_FN(value_type) +static struct tdm_type_name tdm_cb_type_names[] = { + { TDM_THREAD_CB_NONE, "none" }, + { TDM_THREAD_CB_OUTPUT_COMMIT, "output-commit" }, + { TDM_THREAD_CB_OUTPUT_VBLANK, "output-vblank" }, + { TDM_THREAD_CB_OUTPUT_STATUS, "output-status" }, + { TDM_THREAD_CB_OUTPUT_DPMS, "output-dpms" }, + { TDM_THREAD_CB_PP_DONE, "pp-done" }, + { TDM_THREAD_CB_CAPTURE_DONE, "capture-done" }, + { TDM_THREAD_CB_VBLANK_SW, "vblank-sw" }, + { TDM_THREAD_CB_VBLANK_CREATE, "vblank-create" }, + { TDM_THREAD_CB_NEED_VALIDATE, "need-validate" }, +}; +TDM_TYPE_NAME_FN(cb_type) + #define TDM_BIT_NAME_FB(res) \ static inline const char * tdm_##res##_str(int type, char **reply, int *len) \ { \ diff --git a/src/tdm_private.h b/src/tdm_private.h index 30dfb81..f04eebb 100644 --- a/src/tdm_private.h +++ b/src/tdm_private.h @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -83,6 +84,8 @@ extern int tdm_ttrace_output; int tdm_display_is_valid(tdm_display *display); +tdm_private_display * +tdm_display_get(void); int tdm_display_check_module_abi(tdm_private_display *private_display, int abimaj, int abimin); diff --git a/src/tdm_private_types.h b/src/tdm_private_types.h index 6c7d2d5..a4ac11d 100644 --- a/src/tdm_private_types.h +++ b/src/tdm_private_types.h @@ -440,6 +440,7 @@ typedef enum { TDM_THREAD_CB_VBLANK_SW, TDM_THREAD_CB_VBLANK_CREATE, TDM_THREAD_CB_NEED_VALIDATE, + TDM_THREAD_CB_MAX, } tdm_thread_cb_type; typedef struct _tdm_thread_cb_base tdm_thread_cb_base; @@ -456,6 +457,9 @@ typedef struct _tdm_thread_cb_need_validate tdm_thread_cb_need_validate; struct _tdm_thread_cb_base { tdm_thread_cb_type type; unsigned int length; + double object_stamp; + void *data; + unsigned int sync; }; struct _tdm_thread_cb_output_vblank { diff --git a/src/tdm_thread.c b/src/tdm_thread.c index ebac0be..5b7f00e 100644 --- a/src/tdm_thread.c +++ b/src/tdm_thread.c @@ -44,15 +44,56 @@ static tdm_private_thread *keep_private_thread; struct _tdm_private_thread { tdm_private_loop *private_loop; + pthread_cond_t event_cond; pthread_t event_thread; pid_t display_tid; pid_t thread_tid; - /* 0: read, 1: write */ + /* 0: read, 1: write (tdm-thread -> display-thread) */ int pipe[2]; + + /* 0: read, 1: write (tdm-thread <- display-thread) */ + int sub_pipe[2]; + tdm_event_loop_source *sub_event_source; }; +typedef struct _tdm_private_thread_cb { + struct list_head link; + struct list_head call_link; + + void *object; + tdm_thread_cb_type cb_type; + void *cb_data; + tdm_thread_cb func; + void *user_data; + + pid_t owner_tid; + unsigned int called; +} tdm_private_thread_cb; + +static tdm_thread_find_object find_funcs[TDM_THREAD_CB_MAX] = {0, }; +static struct list_head cb_list; + +static void _tdm_thread_free_cb(tdm_private_thread_cb *cb); + +static tdm_error +_tdm_thread_handle_events(int fd, tdm_event_loop_mask mask, void *user_data) +{ + tdm_private_loop *private_loop = user_data; + tdm_error ret; + + TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED); + TDM_RETURN_VAL_IF_FAIL(private_loop != NULL, TDM_ERROR_OPERATION_FAILED); + TDM_RETURN_VAL_IF_FAIL(private_loop->dpy != NULL, TDM_ERROR_OPERATION_FAILED); + + ret = tdm_thread_handle_cb(private_loop); + + TDM_RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret); + + return TDM_ERROR_NONE; +} + static void* _tdm_thread_main(void *data) { @@ -61,6 +102,7 @@ _tdm_thread_main(void *data) int fd; struct pollfd fds; int ret; + tdm_error error; /* Not lock/unlock for the private_thread and private_loop structure * because they won't be destroyed as long as tdm thread is running. @@ -71,6 +113,28 @@ _tdm_thread_main(void *data) TDM_INFO("display_tid:%d, thread_tid: %d", private_thread->display_tid, private_thread->thread_tid); + /* fd SHOULD be the same with sub_pipe[0] to make sure that using + * tdm_thread_get_fd, tdm_thread_send_cb, tdm_thread_handle_cb in + * both threads is fine. Otherwise, assert. + */ + tdm_display_lock(private_loop->dpy); + assert(tdm_thread_get_fd(private_loop) == private_thread->sub_pipe[0]); + + private_thread->sub_event_source = + tdm_event_loop_add_fd_handler(private_loop->dpy, + private_thread->sub_pipe[0], + TDM_EVENT_LOOP_READABLE, + _tdm_thread_handle_events, + private_loop, + &error); + TDM_GOTO_IF_FAIL(error == TDM_ERROR_NONE, exit_thread); + TDM_GOTO_IF_FAIL(private_thread->sub_event_source != NULL, exit_thread); + + pthread_cond_signal(&private_thread->event_cond); + + /* mutex shall be locked by the thread calling pthread_cond_signal() */ + tdm_display_unlock(private_loop->dpy); + fd = tdm_event_loop_get_fd(private_loop->dpy); if (fd < 0) { TDM_ERR("couldn't get fd"); @@ -111,6 +175,7 @@ _tdm_thread_main(void *data) } exit_thread: + tdm_display_unlock(private_loop->dpy); pthread_exit(NULL); } @@ -128,6 +193,8 @@ tdm_thread_init(tdm_private_loop *private_loop) private_display = private_loop->dpy; TDM_RETURN_VAL_IF_FAIL(private_display->private_loop, TDM_ERROR_OPERATION_FAILED); + LIST_INITHEAD(&cb_list); + if (private_loop->private_thread) return TDM_ERROR_NONE; @@ -144,24 +211,49 @@ tdm_thread_init(tdm_private_loop *private_loop) return TDM_ERROR_OUT_OF_MEMORY; } + if (pthread_cond_init(&private_thread->event_cond, NULL)) { + TDM_ERR("pthread_cond_init failed: %m"); + free(private_thread); + return TDM_ERROR_OUT_OF_MEMORY; + } + if (pipe(private_thread->pipe) != 0) { - TDM_ERR("socketpair failed: %m"); + TDM_ERR("pipe failed: %m"); + pthread_cond_destroy(&private_thread->event_cond); free(private_thread); return TDM_ERROR_OPERATION_FAILED; } + if (pipe(private_thread->sub_pipe) != 0) { + TDM_ERR("sub_pipe failed: %m"); + close(private_thread->pipe[0]); + close(private_thread->pipe[1]); + pthread_cond_destroy(&private_thread->event_cond); + free(private_thread); + return TDM_ERROR_OPERATION_FAILED; + } + + keep_private_thread = private_thread; + private_thread->private_loop = private_loop; private_loop->private_thread = private_thread; private_thread->display_tid = syscall(SYS_gettid); + /* pthread_cond_wait atomically release mutex, Upon successful return, + * the mutex shall have been locked and shall be owned by the calling thread + */ + tdm_mutex_locked = 0; pthread_create(&private_thread->event_thread, NULL, _tdm_thread_main, private_thread); - keep_private_thread = private_thread; + /* wait until the tdm thread starts */ + pthread_cond_wait(&private_thread->event_cond, &private_display->lock); + tdm_mutex_locked = 1; - TDM_INFO("using a TDM event thread. pipe(%d,%d)", - private_thread->pipe[0], private_thread->pipe[1]); + TDM_INFO("using a TDM event thread. pipe(%d,%d) sub_pipe(%d,%d)", + private_thread->pipe[0], private_thread->pipe[1], + private_thread->sub_pipe[0], private_thread->sub_pipe[1]); return TDM_ERROR_NONE; } @@ -170,12 +262,17 @@ INTERN void tdm_thread_deinit(tdm_private_loop *private_loop) { tdm_private_display *private_display; + tdm_private_thread_cb *cb = NULL, *hh = NULL; + int i; TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED()); 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); private_display = private_loop->dpy; @@ -186,15 +283,31 @@ tdm_thread_deinit(tdm_private_loop *private_loop) _pthread_mutex_unlock(&private_display->lock); pthread_join(private_loop->private_thread->event_thread, NULL); + tdm_log_reset(); + + LIST_FOR_EACH_ENTRY_SAFE(cb, hh, &cb_list, link) { + _tdm_thread_free_cb(cb); + } + if (private_loop->private_thread->pipe[0] >= 0) close(private_loop->private_thread->pipe[0]); if (private_loop->private_thread->pipe[1] >= 0) close(private_loop->private_thread->pipe[1]); + if (private_loop->private_thread->sub_pipe[0] >= 0) + close(private_loop->private_thread->sub_pipe[0]); + if (private_loop->private_thread->sub_pipe[1] >= 0) + close(private_loop->private_thread->sub_pipe[1]); + + pthread_cond_destroy(&private_loop->private_thread->event_cond); + free(private_loop->private_thread); private_loop->private_thread = NULL; keep_private_thread = NULL; + for (i = 0; i < TDM_THREAD_CB_MAX; i++) + find_funcs[i] = NULL; + TDM_INFO("Finish a TDM event thread"); } @@ -202,6 +315,7 @@ INTERN int tdm_thread_get_fd(tdm_private_loop *private_loop) { tdm_private_thread *private_thread; + int in_main; TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED); TDM_RETURN_VAL_IF_FAIL(private_loop, -1); @@ -209,7 +323,13 @@ tdm_thread_get_fd(tdm_private_loop *private_loop) private_thread = private_loop->private_thread; - return private_thread->pipe[0]; + /* seems like ticky. but easy way to use the same APIs for both threads */ + in_main = tdm_thread_in_display_thread(syscall(SYS_gettid)); + + if (in_main) + return private_thread->pipe[0]; + else + return private_thread->sub_pipe[0]; } INTERN tdm_error @@ -217,6 +337,7 @@ tdm_thread_send_cb(tdm_private_loop *private_loop, tdm_thread_cb_base *base) { tdm_private_thread *private_thread; ssize_t len; + int pipe, in_main; TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED); TDM_RETURN_VAL_IF_FAIL(base, TDM_ERROR_INVALID_PARAMETER); @@ -225,43 +346,58 @@ tdm_thread_send_cb(tdm_private_loop *private_loop, tdm_thread_cb_base *base) private_thread = private_loop->private_thread; + /* seems like ticky. but easy way to use the same APIs for both threads */ + in_main = tdm_thread_in_display_thread(syscall(SYS_gettid)); + + if (in_main) + pipe = private_thread->sub_pipe[1]; + else + pipe = private_thread->pipe[1]; + if (tdm_debug_module & TDM_DEBUG_THREAD) - TDM_INFO("fd(%d) type(%d), length(%d)", - private_thread->pipe[1], base->type, base->length); + TDM_INFO("fd(%d) type(%d), length(%d)", pipe, base->type, base->length); - len = write(private_thread->pipe[1], base, base->length); + len = write(pipe, base, base->length); if (len != base->length) { TDM_ERR("write failed (%d != %d): %m", (int)len, base->length); return TDM_ERROR_OPERATION_FAILED; } + if (tdm_debug_module & TDM_DEBUG_THREAD) + TDM_INFO("[%s] write fd(%d) length(%d)", (in_main) ? "main" : "sub", pipe, len); + return TDM_ERROR_NONE; } INTERN tdm_error tdm_thread_handle_cb(tdm_private_loop *private_loop) { - tdm_private_display *private_display; tdm_private_thread *private_thread; tdm_thread_cb_base *base; char buffer[1024]; unsigned int i; - int len; - - /* DON'T check TDM_MUTEX_IS_LOCKED here */ + int len, pipe, in_main; + TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED); TDM_RETURN_VAL_IF_FAIL(private_loop, TDM_ERROR_INVALID_PARAMETER); TDM_RETURN_VAL_IF_FAIL(private_loop->private_thread, TDM_ERROR_INVALID_PARAMETER); private_thread = private_loop->private_thread; - private_display = private_loop->dpy; + + /* seems like ticky. but easy way to use the same APIs for both threads */ + in_main = tdm_thread_in_display_thread(syscall(SYS_gettid)); + + if (in_main) + pipe = private_thread->pipe[0]; + else + pipe = private_thread->sub_pipe[0]; do { - len = read(private_thread->pipe[0], buffer, sizeof buffer); + len = read(pipe, buffer, sizeof buffer); } while (len < 0 && errno == EINTR); if (tdm_debug_module & TDM_DEBUG_THREAD) - TDM_INFO("fd(%d) read length(%d)", private_thread->pipe[0], len); + TDM_INFO("[%s] read fd(%d) length(%d)", (in_main) ? "main" : "sub", pipe, len); if (len < 0) { TDM_ERR("read failed: errno(%d), len(%d) %m", errno, len); @@ -276,8 +412,6 @@ tdm_thread_handle_cb(tdm_private_loop *private_loop) return TDM_ERROR_OPERATION_FAILED; } - _pthread_mutex_lock(&private_display->lock); - i = 0; while (i < len) { base = (tdm_thread_cb_base*)&buffer[i]; @@ -380,8 +514,6 @@ tdm_thread_handle_cb(tdm_private_loop *private_loop) i += base->length; } - _pthread_mutex_unlock(&private_display->lock); - return TDM_ERROR_NONE; } @@ -403,3 +535,217 @@ tdm_thread_is_running(void) return (keep_private_thread) ? 1 : 0; } + +static void +_tdm_thread_free_cb(tdm_private_thread_cb *cb) +{ + if (tdm_debug_module & TDM_DEBUG_THREAD) + TDM_INFO("cb(%p) removed", cb); + + assert(LIST_IS_EMPTY(&cb->call_link)); + + LIST_DEL(&cb->link); + free(cb); +} + +static tdm_private_thread_cb * +_tdm_thread_find_cb(void *object, tdm_thread_cb_type cb_type, void *cb_data, tdm_thread_cb func, void *user_data, pid_t owner_tid) +{ + tdm_private_thread_cb *cb = NULL; + + LIST_FOR_EACH_ENTRY(cb, &cb_list, link) { + if (cb->object == object && + cb->cb_type == cb_type && + cb->cb_data == cb_data && + cb->func == func && + cb->user_data == user_data && + cb->owner_tid == owner_tid) + return cb; + } + + return NULL; +} + +static void +_tdm_thread_reset_cb(tdm_thread_cb_type cb_type) +{ + tdm_private_thread_cb *cb = NULL; + + LIST_FOR_EACH_ENTRY(cb, &cb_list, link) { + if (cb->cb_type == cb_type) + cb->called = 0; + } +} + +INTERN void +tdm_thread_cb_set_find_func(tdm_thread_cb_type cb_type, tdm_thread_find_object func) +{ + TDM_RETURN_IF_FAIL(cb_type > 0); + + if (func && find_funcs[cb_type]) + TDM_NEVER_GET_HERE(); + + find_funcs[cb_type] = func; +} + +INTERN tdm_error +tdm_thread_cb_add(void *object, tdm_thread_cb_type cb_type, void *cb_data, tdm_thread_cb func, void *user_data) +{ + tdm_private_thread_cb *cb = NULL; + pid_t caller_tid; + + TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED); + TDM_RETURN_VAL_IF_FAIL(object != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(cb_type > 0, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER); + + caller_tid = syscall(SYS_gettid); + + cb = _tdm_thread_find_cb(object, cb_type, cb_data, func, user_data, caller_tid); + if (cb) { + TDM_ERR("can't be added twice with same data"); +#if 1 + assert(0); +#endif + return TDM_ERROR_BAD_REQUEST; + } + + cb = calloc(1, sizeof *cb); + if (!cb) { + TDM_ERR("calloc failed"); + return TDM_ERROR_OUT_OF_MEMORY; + } + + LIST_ADDTAIL(&cb->link, &cb_list); + LIST_INITHEAD(&cb->call_link); + + cb->object = object; + cb->cb_type = cb_type; + cb->cb_data = cb_data; + cb->func = func; + cb->user_data = user_data; + cb->owner_tid = caller_tid; + + if (tdm_debug_module & TDM_DEBUG_THREAD) + TDM_INFO("cb_type(%d) cb(%p) added", cb_type, cb); + + return TDM_ERROR_NONE; +} + +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; + + TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED()); + TDM_RETURN_IF_FAIL(object != NULL); + TDM_RETURN_IF_FAIL(cb_type > 0); + TDM_RETURN_IF_FAIL(func != NULL); + + caller_tid = syscall(SYS_gettid); + + cb = _tdm_thread_find_cb(object, cb_type, cb_data, func, user_data, caller_tid); + if (!cb) + return; + + _tdm_thread_free_cb(cb); +} + +/* when call a callback, we check both cb_base's type and cb_base's data, + * 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_private_display *private_display = tdm_display_get(); + tdm_private_thread_cb *cb = NULL, *hh = NULL; + int handler_in_other_thread = 0; + pid_t caller_tid; + struct list_head call_list; + 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 (!object) { + object = find_funcs[cb_base->type](private_display, cb_base->object_stamp); + if (!object) { + TDM_WRN("%p gone", object); + return TDM_ERROR_NONE; + } + } + + LIST_INITHEAD(&call_list); + + LIST_FOR_EACH_ENTRY_SAFE(cb, hh, &cb_list, link) { + if (cb->called || + cb->object != object || + cb->cb_type != cb_base->type || + cb->cb_data != cb_base->data) + continue; + + if (cb->owner_tid == caller_tid) + LIST_ADDTAIL(&cb->call_link, &call_list); + else + handler_in_other_thread = 1; + } + + if (!LIST_IS_EMPTY(&call_list)) { + LIST_FOR_EACH_ENTRY_SAFE(cb, hh, &call_list, call_link) { + LIST_DELINIT(&cb->call_link); + cb->called = 1; + if (tdm_debug_module & TDM_DEBUG_THREAD) + TDM_INFO("cb_type(%d) cb(%p) called", cb->cb_type, cb); + cb->func(private_display, cb->object, cb_base, cb->user_data); + } + } + + assert(LIST_IS_EMPTY(&call_list)); + + if (!handler_in_other_thread) { + _tdm_thread_reset_cb(cb_base->type); + if (keep_private_thread) { + if (cb_base->sync) { + 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); + 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); + + /* waiting until all cb are done in another thread */ + if (cb_base->sync) { + if (tdm_debug_module & TDM_DEBUG_THREAD) + TDM_INFO("pthread wait"); + + /* pthread_cond_wait atomically release mutex, Upon successful return, + * the mutex shall have been locked and shall be owned by the calling thread + */ + tdm_mutex_locked = 0; + 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); + + return TDM_ERROR_NONE; +} diff --git a/src/tdm_thread.h b/src/tdm_thread.h index c9ef06d..1a91933 100644 --- a/src/tdm_thread.h +++ b/src/tdm_thread.h @@ -57,6 +57,19 @@ tdm_thread_in_display_thread(pid_t tid); int tdm_thread_is_running(void); +typedef void* (*tdm_thread_find_object)(tdm_private_display *private_display, double stamp); +typedef void (*tdm_thread_cb)(tdm_private_display *private_display, void *object, tdm_thread_cb_base *cb_base, void *user_data); + +void +tdm_thread_cb_set_find_func(tdm_thread_cb_type cb_type, tdm_thread_find_object func); +tdm_error +tdm_thread_cb_add(void *object, tdm_thread_cb_type cb_type, void *cb_data, tdm_thread_cb func, void *user_data); +void +tdm_thread_cb_remove(void *object, tdm_thread_cb_type cb_type, void *cb_data, tdm_thread_cb func, void *user_data); +tdm_error +tdm_thread_cb_call(void *object, tdm_thread_cb_base *cb_base); + + #ifdef __cplusplus } #endif -- 2.7.4