support thread 31/65531/1
authorBoram Park <boram1288.park@samsung.com>
Wed, 30 Mar 2016 08:18:00 +0000 (17:18 +0900)
committerBoram Park <boram1288.park@samsung.com>
Mon, 11 Apr 2016 10:33:01 +0000 (19:33 +0900)
Change-Id: I8f9b5b7393af5990e46bf51142db3005a430535f

include/tdm_log.h
src/Makefile.am
src/tdm.c
src/tdm_capture.c
src/tdm_display.c
src/tdm_event.c
src/tdm_helper.c
src/tdm_pp.c
src/tdm_private.h
src/tdm_thread.c [new file with mode: 0644]

index 1952e2a..508e655 100644 (file)
@@ -41,6 +41,10 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 extern "C" {
 #endif
 
+#include <time.h>
+#include <sys/syscall.h>
+
+
 /**
  * @file tdm_log.h
  * @brief The header file to print logs in frontend and backend modules
@@ -57,7 +61,6 @@ extern int tdm_debug;
 #ifdef TDM_CONFIG_DLOG
 
 #include <dlog.h>
-#include <time.h>
 
 #ifdef LOG_TAG
 #undef LOG_TAG
@@ -70,8 +73,8 @@ extern int tdm_debug;
                struct timespec ts;     \
                clock_gettime(CLOCK_MONOTONIC, &ts);    \
                LOGD("[%d.%06d] "fmt"\n", (int)ts.tv_sec, (int)ts.tv_nsec / 1000, ##args);      \
-               printf("[TDM_DBG][%d.%06d][%s %d] "fmt"\n", (int)ts.tv_sec,     \
-                       (int)ts.tv_nsec / 1000, __func__, __LINE__, ##args); \
+               printf("[TDM_DBG][%d.%06d][%d][%s %d] "fmt"\n", (int)ts.tv_sec, \
+                       (int)ts.tv_nsec / 1000, (int)syscall(SYS_gettid), __func__, __LINE__, ##args); \
        } while (0);
 
 #define TDM_INFO(fmt, args...) \
@@ -79,8 +82,8 @@ extern int tdm_debug;
                struct timespec ts;     \
                clock_gettime(CLOCK_MONOTONIC, &ts);    \
                LOGI("[%d.%06d] "fmt"\n", (int)ts.tv_sec, (int)ts.tv_nsec / 1000, ##args);      \
-               printf("[TDM_INF][%d.%06d][%s %d] "fmt"\n", (int)ts.tv_sec,     \
-                       (int)ts.tv_nsec / 1000, __func__, __LINE__, ##args); \
+               printf("[TDM_INF][%d.%06d][%d][%s %d] "fmt"\n", (int)ts.tv_sec, \
+                       (int)ts.tv_nsec / 1000, (int)syscall(SYS_gettid), __func__, __LINE__, ##args); \
        } while (0);
 
 #define TDM_WRN(fmt, args...) \
@@ -88,8 +91,8 @@ extern int tdm_debug;
                struct timespec ts;     \
                clock_gettime(CLOCK_MONOTONIC, &ts);    \
                LOGI("[%d.%06d] "fmt"\n", (int)ts.tv_sec, (int)ts.tv_nsec / 1000, ##args);      \
-               printf("[TDM_WRN][%d.%06d][%s %d] "fmt"\n", (int)ts.tv_sec,     \
-                       (int)ts.tv_nsec / 1000, __func__, __LINE__, ##args); \
+               printf("[TDM_WRN][%d.%06d][%d][%s %d] "fmt"\n", (int)ts.tv_sec, \
+                       (int)ts.tv_nsec / 1000, (int)syscall(SYS_gettid), __func__, __LINE__, ##args); \
        } while (0);
 
 #define TDM_ERR(fmt, args...) \
@@ -97,46 +100,45 @@ extern int tdm_debug;
                struct timespec ts;     \
                clock_gettime(CLOCK_MONOTONIC, &ts);    \
                LOGE("[%d.%06d] "fmt"\n", (int)ts.tv_sec, (int)ts.tv_nsec / 1000, ##args);      \
-               printf("[TDM_ERR][%d.%06d][%s %d] "fmt"\n", (int)ts.tv_sec,     \
-                       (int)ts.tv_nsec / 1000, __func__, __LINE__, ##args); \
+               printf("[TDM_ERR][%d.%06d][%d][%s %d] "fmt"\n", (int)ts.tv_sec, \
+                       (int)ts.tv_nsec / 1000, (int)syscall(SYS_gettid), __func__, __LINE__, ##args); \
        } while (0);
 
 #else /* TDM_CONFIG_DLOG */
 
 #include <stdio.h>
-#include <time.h>
 
 #define TDM_DBG(fmt, args...) \
     if (tdm_debug) \
        do { \
                struct timespec ts;     \
                clock_gettime(CLOCK_MONOTONIC, &ts);    \
-               printf("[TDM_DBG][%d.%06d][%s %d] "fmt"\n", (int)ts.tv_sec,     \
-                       (int)ts.tv_nsec / 1000, __func__, __LINE__, ##args); \
+               printf("[TDM_DBG][%d.%06d][%d][%s %d] "fmt"\n", (int)ts.tv_sec, \
+                       (int)ts.tv_nsec / 1000, (int)syscall(SYS_gettid), __func__, __LINE__, ##args); \
        } while (0);
 
 #define TDM_INFO(fmt, args...) \
        do { \
                struct timespec ts;     \
                clock_gettime(CLOCK_MONOTONIC, &ts);    \
-               printf("[TDM_INF][%d.%06d][%s %d] "fmt"\n", (int)ts.tv_sec,     \
-                       (int)ts.tv_nsec / 1000, __func__, __LINE__, ##args); \
+               printf("[TDM_INF][%d.%06d][%d][%s %d] "fmt"\n", (int)ts.tv_sec, \
+                       (int)ts.tv_nsec / 1000, (int)syscall(SYS_gettid), __func__, __LINE__, ##args); \
        } while (0);
 
 #define TDM_WRN(fmt, args...) \
        do { \
                struct timespec ts;     \
                clock_gettime(CLOCK_MONOTONIC, &ts);    \
-               printf("[TDM_WRN][%d.%06d][%s %d] "fmt"\n", (int)ts.tv_sec,     \
-                       (int)ts.tv_nsec / 1000, __func__, __LINE__, ##args); \
+               printf("[TDM_WRN][%d.%06d][%d][%s %d] "fmt"\n", (int)ts.tv_sec, \
+                       (int)ts.tv_nsec / 1000, (int)syscall(SYS_gettid), __func__, __LINE__, ##args); \
        } while (0);
 
 #define TDM_ERR(fmt, args...) \
        do { \
                struct timespec ts;     \
                clock_gettime(CLOCK_MONOTONIC, &ts);    \
-               printf("[TDM_ERR][%d.%06d][%s %d] "fmt"\n", (int)ts.tv_sec,     \
-                       (int)ts.tv_nsec / 1000, __func__, __LINE__, ##args); \
+               printf("[TDM_ERR][%d.%06d][%d][%s %d] "fmt"\n", (int)ts.tv_sec, \
+                       (int)ts.tv_nsec / 1000, (int)syscall(SYS_gettid), __func__, __LINE__, ##args); \
        } while (0);
 
 #endif /* TDM_CONFIG_DLOG */
index 2f994ba..5a2ee06 100644 (file)
@@ -12,6 +12,7 @@ libtdm_la_LIBADD = $(TDM_LIBS) -ldl -lpthread
 libtdm_la_SOURCES = \
        tdm_backend.c \
        tdm_event.c \
+       tdm_thread.c \
        tdm_helper.c \
        tdm_buffer.c \
        tdm_display.c \
index 4c2e9f6..1d279f3 100644 (file)
--- a/src/tdm.c
+++ b/src/tdm.c
@@ -70,6 +70,20 @@ _tdm_display_find_private_output(tdm_private_display *private_display,
        return NULL;
 }
 
+INTERN tdm_private_output *
+tdm_display_find_output_stamp(tdm_private_display *private_display,
+                              unsigned long stamp)
+{
+       tdm_private_output *private_output = NULL;
+
+       LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link) {
+               if (private_output->stamp == stamp)
+                       return private_output;
+       }
+
+       return NULL;
+}
+
 static void
 _tdm_display_destroy_caps_pp(tdm_caps_pp *caps_pp)
 {
@@ -151,6 +165,7 @@ _tdm_display_destroy_private_output(tdm_private_output *private_output)
 
        _tdm_display_destroy_caps_output(&private_output->caps);
 
+       private_output->stamp = 0;
        free(private_output);
 }
 
@@ -362,15 +377,34 @@ failed_update:
        return ret;
 }
 
-static void
-_tdm_output_cb_status(tdm_output *output, tdm_output_conn_status status,
-                      void *user_data)
+INTERN void
+tdm_output_cb_status(tdm_output *output_backend, tdm_output_conn_status status,
+                     void *user_data)
 {
+       tdm_private_display *private_display;
        tdm_private_output *private_output = user_data;
        tdm_value value;
 
        TDM_RETURN_IF_FAIL(private_output);
 
+       private_display = private_output->private_display;
+
+       if (!tdm_thread_in_display_thread(private_display)) {
+               tdm_thread_cb_output_status output_status;
+               tdm_error ret;
+
+               output_status.base.type = TDM_THREAD_CB_OUTPUT_STATUS;
+               output_status.base.length = sizeof output_status;
+               output_status.output_stamp = private_output->stamp;
+               output_status.status = status;
+               output_status.user_data = user_data;
+
+               ret = tdm_thread_send_cb(private_display, &output_status.base);
+               TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
+
+               return;
+       }
+
        value.u32 = status;
        tdm_output_call_change_handler_internal(private_output,
                                                TDM_OUTPUT_CHANGE_CONNECTION,
@@ -393,7 +427,12 @@ _tdm_display_update_output(tdm_private_display *private_display,
                private_output = calloc(1, sizeof(tdm_private_output));
                TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_OUT_OF_MEMORY);
 
+               private_output->stamp = tdm_helper_get_time_in_millis();
+               while (tdm_display_find_output_stamp(private_display, private_output->stamp))
+                       private_output->stamp++;
+
                LIST_ADD(&private_output->link, &private_display->output_list);
+
                private_output->private_display = private_display;
                private_output->output_backend = output_backend;
                private_output->pipe = pipe;
@@ -407,7 +446,7 @@ _tdm_display_update_output(tdm_private_display *private_display,
                if (func_output->output_set_status_handler) {
                        private_output->regist_change_cb = 1;
                        ret = func_output->output_set_status_handler(output_backend,
-                                                                    _tdm_output_cb_status,
+                                                                    tdm_output_cb_status,
                                                                     private_output);
                        if (ret != TDM_ERROR_NONE)
                                goto failed_update;
@@ -450,6 +489,7 @@ _tdm_display_update_internal(tdm_private_display *private_display,
 
        LIST_INITHEAD(&private_display->output_list);
        LIST_INITHEAD(&private_display->pp_list);
+       LIST_INITHEAD(&private_display->capture_list);
 
        if (!only_display) {
                ret = _tdm_display_update_caps_pp(private_display, &private_display->caps_pp);
@@ -506,6 +546,7 @@ tdm_display_update(tdm_display *dpy)
 
 int tdm_debug;
 int tdm_debug_buffer;
+int tdm_debug_thread;
 int tdm_debug_mutex;
 
 static tdm_private_display *g_private_display;
@@ -747,6 +788,10 @@ tdm_display_init(tdm_error *error)
        if (debug && (strstr(debug, "1")))
                tdm_debug_buffer = 1;
 
+       debug = getenv("TDM_DEBUG_THREAD");
+       if (debug && (strstr(debug, "1")))
+               tdm_debug_thread = 1;
+
        debug = getenv("TDM_DEBUG_MUTEX");
        if (debug && (strstr(debug, "1")))
                tdm_debug_mutex = 1;
@@ -766,7 +811,11 @@ tdm_display_init(tdm_error *error)
 
        ret = tdm_event_init(private_display);
        if (ret != TDM_ERROR_NONE)
-               goto failed_load;
+               goto failed_event;
+
+       ret = tdm_thread_init(private_display);
+       if (ret != TDM_ERROR_NONE)
+               goto failed_thread;
 
        ret = _tdm_display_load_module(private_display);
        if (ret != TDM_ERROR_NONE)
@@ -778,7 +827,7 @@ tdm_display_init(tdm_error *error)
        if (ret != TDM_ERROR_NONE)
                goto failed_update;
 
-       tdm_event_create_main_source(private_display);
+       tdm_event_create_backend_source(private_display);
 
        private_display->init_count = 1;
 
@@ -794,6 +843,10 @@ tdm_display_init(tdm_error *error)
 failed_update:
        _tdm_display_unload_module(private_display);
 failed_load:
+       tdm_thread_deinit(private_display);
+failed_thread:
+       tdm_event_deinit(private_display);
+failed_event:
        pthread_mutex_destroy(&private_display->lock);
 failed_mutex_init:
        free(private_display);
@@ -824,9 +877,11 @@ tdm_display_deinit(tdm_display *dpy)
 
        _pthread_mutex_lock(&private_display->lock);
 
+       tdm_thread_deinit(private_display);
+       tdm_event_deinit(private_display);
+
        _tdm_display_destroy_private_display(private_display);
        _tdm_display_unload_module(private_display);
-       tdm_event_deinit(private_display);
 
        tdm_helper_set_fd("TDM_DRM_MASTER_FD", -1);
 
index 1da64d8..56fe148 100644 (file)
@@ -74,9 +74,9 @@ _tdm_capture_check_if_exist(tdm_private_capture *private_capture,
        return TDM_ERROR_NONE;
 }
 
-static void
-_tdm_caputre_cb_done(tdm_capture *capture_backend, tbm_surface_h buffer,
-                     void *user_data)
+INTERN void
+tdm_capture_cb_done(tdm_capture *capture_backend, tbm_surface_h buffer,
+                    void *user_data)
 {
        tdm_private_capture *private_capture = user_data;
        tdm_private_display *private_display = private_capture->private_display;
@@ -85,6 +85,22 @@ _tdm_caputre_cb_done(tdm_capture *capture_backend, tbm_surface_h buffer,
        int lock_after_cb_done = 0;
        int ret;
 
+       if (!tdm_thread_in_display_thread(private_display)) {
+               tdm_thread_cb_capture_done capture_done;
+               tdm_error ret;
+
+               capture_done.base.type = TDM_THREAD_CB_PP_DONE;
+               capture_done.base.length = sizeof capture_done;
+               capture_done.capture_stamp = private_capture->stamp;
+               capture_done.buffer = buffer;
+               capture_done.user_data = user_data;
+
+               ret = tdm_thread_send_cb(private_display, &capture_done.base);
+               TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
+
+               return;
+       }
+
        if (tdm_debug_buffer)
                TDM_INFO("capture(%p) done: %p", private_capture, buffer);
 
@@ -110,6 +126,19 @@ _tdm_caputre_cb_done(tdm_capture *capture_backend, tbm_surface_h buffer,
 }
 
 INTERN tdm_private_capture *
+tdm_capture_find_stamp(tdm_private_display *private_display, unsigned long stamp)
+{
+       tdm_private_capture *private_capture = NULL;
+
+       LIST_FOR_EACH_ENTRY(private_capture, &private_display->capture_list, link) {
+               if (private_capture->stamp == stamp)
+                       return private_capture;
+       }
+
+       return NULL;
+}
+
+INTERN tdm_private_capture *
 tdm_capture_create_output_internal(tdm_private_output *private_output,
                                    tdm_error *error)
 {
@@ -145,7 +174,7 @@ tdm_capture_create_output_internal(tdm_private_output *private_output,
        }
 
        ret = func_capture->capture_set_done_handler(capture_backend,
-                       _tdm_caputre_cb_done, private_capture);
+                       tdm_capture_cb_done, private_capture);
        if (ret != TDM_ERROR_NONE) {
                TDM_ERR("capture(%p) set capture_done_handler failed", private_capture);
                func_capture->capture_destroy(capture_backend);
@@ -154,7 +183,13 @@ tdm_capture_create_output_internal(tdm_private_output *private_output,
                return NULL;
        }
 
+       private_capture->stamp = tdm_helper_get_time_in_millis();
+       while (tdm_capture_find_stamp(private_display, private_capture->stamp))
+               private_capture->stamp++;
+
        LIST_ADD(&private_capture->link, &private_output->capture_list);
+       LIST_ADD(&private_capture->display_link, &private_display->capture_list);
+
        private_capture->target = TDM_CAPTURE_TARGET_OUTPUT;
        private_capture->private_display = private_display;
        private_capture->private_output = private_output;
@@ -203,7 +238,13 @@ tdm_capture_create_layer_internal(tdm_private_layer *private_layer,
                return NULL;
        }
 
-       LIST_ADD(&private_capture->link, &private_output->capture_list);
+       private_capture->stamp = tdm_helper_get_time_in_millis();
+       while (tdm_capture_find_stamp(private_display, private_capture->stamp))
+               private_capture->stamp++;
+
+       LIST_ADD(&private_capture->link, &private_layer->capture_list);
+       LIST_ADD(&private_capture->display_link, &private_display->capture_list);
+
        private_capture->target = TDM_CAPTURE_TARGET_LAYER;
        private_capture->private_display = private_display;
        private_capture->private_output = private_output;
@@ -230,6 +271,7 @@ tdm_capture_destroy_internal(tdm_private_capture *private_capture)
                return;
 
        LIST_DEL(&private_capture->link);
+       LIST_DEL(&private_capture->display_link);
 
        func_capture = &private_capture->private_display->func_capture;
        func_capture->capture_destroy(private_capture->capture_backend);
@@ -258,6 +300,7 @@ tdm_capture_destroy_internal(tdm_private_capture *private_capture)
                }
        }
 
+       private_capture->stamp = 0;
        free(private_capture);
 }
 
index 54e44f6..5ca4b47 100644 (file)
@@ -340,7 +340,10 @@ tdm_display_get_fd(tdm_display *dpy, int *fd)
 
        _pthread_mutex_lock(&private_display->lock);
 
-       *fd = tdm_event_get_fd(private_display);
+       if (private_display->private_thread)
+               *fd = tdm_thread_get_fd(private_display);
+       else
+               *fd = tdm_event_get_fd(private_display);
 
        _pthread_mutex_unlock(&private_display->lock);
 
@@ -350,11 +353,39 @@ tdm_display_get_fd(tdm_display *dpy, int *fd)
 EXTERN tdm_error
 tdm_display_handle_events(tdm_display *dpy)
 {
+       struct pollfd fds;
+       int fd = -1;
+
        DISPLAY_FUNC_ENTRY();
 
+       ret = tdm_display_get_fd(dpy, &fd);
+       TDM_RETURN_VAL_IF_FAIL(fd >= 0, ret);
+
+       fds.events = POLLIN;
+       fds.fd = fd;
+       fds.revents = 0;
+
+       if (tdm_debug_thread)
+               TDM_INFO("fd(%d) polling in", fd);
+
+       while (poll(&fds, 1, -1) < 0) {
+               if (errno == EBUSY)  /* normal case */
+                       continue;
+               else {
+                       TDM_ERR("poll failed: %m");
+                       return TDM_ERROR_OPERATION_FAILED;
+               }
+       }
+
+       if (tdm_debug_thread)
+               TDM_INFO("fd(%d) polling out", fd);
+
        _pthread_mutex_lock(&private_display->lock);
 
-       ret = tdm_event_dispatch(private_display);
+       if (private_display->private_thread)
+               ret = tdm_thread_handle_cb(private_display);
+       else
+               ret = tdm_event_dispatch(private_display);
 
        _pthread_mutex_unlock(&private_display->lock);
 
@@ -708,9 +739,9 @@ tdm_output_get_property(tdm_output *output, unsigned int id, tdm_value *value)
        return ret;
 }
 
-static void
-_tdm_output_cb_vblank(tdm_output *output_backend, unsigned int sequence,
-                      unsigned int tv_sec, unsigned int tv_usec, void *user_data)
+INTERN void
+tdm_output_cb_vblank(tdm_output *output_backend, unsigned int sequence,
+                     unsigned int tv_sec, unsigned int tv_usec, void *user_data)
 {
        tdm_private_vblank_handler *vblank_handler = user_data;
        tdm_private_display *private_display;
@@ -719,6 +750,24 @@ _tdm_output_cb_vblank(tdm_output *output_backend, unsigned int sequence,
 
        private_display = vblank_handler->private_output->private_display;
 
+       if (!tdm_thread_in_display_thread(private_display)) {
+               tdm_thread_cb_output_vblank output_vblank;
+               tdm_error ret;
+
+               output_vblank.base.type = TDM_THREAD_CB_OUTPUT_VBLANK;
+               output_vblank.base.length = sizeof output_vblank;
+               output_vblank.output_stamp = vblank_handler->private_output->stamp;
+               output_vblank.sequence = sequence;
+               output_vblank.tv_sec = tv_sec;
+               output_vblank.tv_usec = tv_usec;
+               output_vblank.user_data = user_data;
+
+               ret = tdm_thread_send_cb(private_display, &output_vblank.base);
+               TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
+
+               return;
+       }
+
        if (vblank_handler->func) {
                _pthread_mutex_unlock(&private_display->lock);
                vblank_handler->func(vblank_handler->private_output, sequence,
@@ -730,9 +779,9 @@ _tdm_output_cb_vblank(tdm_output *output_backend, unsigned int sequence,
        free(vblank_handler);
 }
 
-static void
-_tdm_output_cb_commit(tdm_output *output_backend, unsigned int sequence,
-                      unsigned int tv_sec, unsigned int tv_usec, void *user_data)
+INTERN void
+tdm_output_cb_commit(tdm_output *output_backend, unsigned int sequence,
+                     unsigned int tv_sec, unsigned int tv_usec, void *user_data)
 {
        tdm_private_commit_handler *commit_handler = user_data;
        tdm_private_display *private_display;
@@ -744,6 +793,24 @@ _tdm_output_cb_commit(tdm_output *output_backend, unsigned int sequence,
        private_output = commit_handler->private_output;
        private_display = private_output->private_display;
 
+       if (!tdm_thread_in_display_thread(private_display)) {
+               tdm_thread_cb_output_commit output_commit;
+               tdm_error ret;
+
+               output_commit.base.type = TDM_THREAD_CB_OUTPUT_COMMIT;
+               output_commit.base.length = sizeof output_commit;
+               output_commit.output_stamp = private_output->stamp;
+               output_commit.sequence = sequence;
+               output_commit.tv_sec = tv_sec;
+               output_commit.tv_usec = tv_usec;
+               output_commit.user_data = user_data;
+
+               ret = tdm_thread_send_cb(private_display, &output_commit.base);
+               TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
+
+               return;
+       }
+
        LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
                if (!private_layer->waiting_buffer)
                        continue;
@@ -821,7 +888,7 @@ tdm_output_wait_vblank(tdm_output *output, int interval, int sync,
        if (!private_output->regist_vblank_cb) {
                private_output->regist_vblank_cb = 1;
                ret = func_output->output_set_vblank_handler(private_output->output_backend,
-                               _tdm_output_cb_vblank);
+                               tdm_output_cb_vblank);
        }
 
        _pthread_mutex_unlock(&private_display->lock);
@@ -862,7 +929,7 @@ _tdm_output_commit(tdm_output *output, int sync, tdm_output_commit_handler func,
        if (!private_output->regist_commit_cb) {
                private_output->regist_commit_cb = 1;
                ret = func_output->output_set_commit_handler(private_output->output_backend,
-                               _tdm_output_cb_commit);
+                               tdm_output_cb_commit);
        }
 
        return ret;
index e97f2ac..05cfa60 100644 (file)
@@ -46,7 +46,12 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 struct _tdm_private_event {
        struct wl_display *wl_display;
        struct wl_event_loop *event_loop;
-       tdm_event_source *main_source;
+
+       int backend_fd;
+       tdm_event_source *backend_source;
+
+       struct wl_display *wl_display2;
+       struct wl_event_loop *event_loop2;
 };
 
 typedef struct _tdm_event_source_base
@@ -74,9 +79,16 @@ static tdm_error
 _tdm_event_main_fd_handler(int fd, tdm_event_mask mask, void *user_data)
 {
        tdm_private_display *private_display = (tdm_private_display*)user_data;
+       tdm_private_event *private_event;
        tdm_func_display *func_display;
 
        TDM_RETURN_VAL_IF_FAIL(private_display != NULL, TDM_ERROR_OPERATION_FAILED);
+       TDM_RETURN_VAL_IF_FAIL(private_display->private_event != NULL, TDM_ERROR_OPERATION_FAILED);
+
+       private_event = private_display->private_event;
+
+       if (tdm_debug_thread)
+               TDM_INFO("backend fd(%d) event happens", private_event->backend_fd);
 
        func_display = &private_display->func_display;
        if (!func_display->display_handle_events)
@@ -99,6 +111,8 @@ tdm_event_init(tdm_private_display *private_display)
                return TDM_ERROR_OUT_OF_MEMORY;
        }
 
+       private_event->backend_fd = -1;
+
        private_event->wl_display = wl_display_create();
        if (!private_event->wl_display) {
                TDM_ERR("creating a wayland display failed");
@@ -114,6 +128,22 @@ tdm_event_init(tdm_private_display *private_display)
                return TDM_ERROR_OUT_OF_MEMORY;
        }
 
+       TDM_INFO("event loop fd(%d)", wl_event_loop_get_fd(private_event->event_loop));
+
+       private_event->wl_display2 = wl_display_create();
+       if (!private_event->wl_display2) {
+               TDM_ERR("creating a wayland display2 failed");
+               return TDM_ERROR_OUT_OF_MEMORY;
+       }
+
+       private_event->event_loop2 = wl_display_get_event_loop(private_event->wl_display2);
+       if (!private_event->event_loop2) {
+               TDM_ERR("no event loop2");
+               wl_display_destroy(private_event->wl_display2);
+               private_event->wl_display2 = NULL;
+               return TDM_ERROR_OUT_OF_MEMORY;
+       }
+
        private_display->private_event = private_event;
 
        return TDM_ERROR_NONE;
@@ -125,8 +155,8 @@ tdm_event_deinit(tdm_private_display *private_display)
        if (!private_display->private_event)
                return;
 
-       if (private_display->private_event->main_source)
-               tdm_event_source_remove(private_display->private_event->main_source);
+       if (private_display->private_event->backend_source)
+               tdm_event_source_remove(private_display->private_event->backend_source);
 
        if (private_display->private_event->wl_display)
                wl_display_destroy(private_display->private_event->wl_display);
@@ -136,7 +166,7 @@ tdm_event_deinit(tdm_private_display *private_display)
 }
 
 INTERN void
-tdm_event_create_main_source(tdm_private_display *private_display)
+tdm_event_create_backend_source(tdm_private_display *private_display)
 {
        tdm_private_event *private_event = private_display->private_event;
        tdm_func_display *func_display;
@@ -162,16 +192,18 @@ tdm_event_create_main_source(tdm_private_display *private_display)
                return;
        }
 
-       private_event->main_source =
+       private_event->backend_source =
                tdm_event_add_fd_handler(private_display, fd, TDM_EVENT_READABLE,
                                         _tdm_event_main_fd_handler, private_display,
                                         &ret);
-       if (!private_event->main_source) {
-               TDM_ERR("no main event source");
+       if (!private_event->backend_source) {
+               TDM_ERR("no backend fd(%d) source", fd);
                return;
        }
 
-       TDM_INFO("main event source created");
+       private_event->backend_fd = fd;
+
+       TDM_INFO("backend fd(%d) source created", private_event->backend_fd);
 }
 
 INTERN int
@@ -191,10 +223,15 @@ tdm_event_dispatch(tdm_private_display *private_display)
 
        TDM_RETURN_VAL_IF_FAIL(private_event->event_loop != NULL, TDM_ERROR_OPERATION_FAILED);
 
-       if (wl_event_loop_dispatch(private_event->event_loop, 0) < 0) {
+       if (tdm_debug_thread)
+               TDM_INFO("dispatch");
+
+       /* Don't set timeout to -1. It can make deadblock by two mutex locks.
+        * If need to set -1, use poll() and call tdm_event_dispatch() after
+        * escaping polling.
+        */
+       if (wl_event_loop_dispatch(private_event->event_loop, 0) < 0)
                TDM_ERR("dispatch failed");
-               return TDM_ERROR_OPERATION_FAILED;
-       }
 
        return TDM_ERROR_NONE;
 }
index 311ea6e..534bebc 100644 (file)
@@ -7,6 +7,7 @@
 #include <tbm_surface.h>
 #include <tbm_surface_internal.h>
 #include <string.h>
+#include <time.h>
 
 #include "tdm.h"
 #include "tdm_private.h"
 
 static const char *dump_prefix[2] = {"png", "yuv"};
 
+INTERN unsigned long
+tdm_helper_get_time_in_millis(void)
+{
+       struct timespec tp;
+
+       if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
+               return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
+
+       return 0;
+}
+
 static void
 _tdm_helper_dump_raw(const char *file, void *data1, int size1, void *data2,
                      int size2, void *data3, int size3)
index 683e09f..f5345ad 100644 (file)
@@ -88,9 +88,9 @@ _tdm_pp_check_if_exist(tdm_private_pp *private_pp,
        return TDM_ERROR_NONE;
 }
 
-static void
-_tdm_pp_cb_done(tdm_pp *pp_backend, tbm_surface_h src, tbm_surface_h dst,
-                void *user_data)
+INTERN void
+tdm_pp_cb_done(tdm_pp *pp_backend, tbm_surface_h src, tbm_surface_h dst,
+               void *user_data)
 {
        tdm_private_pp *private_pp = user_data;
        tdm_private_display *private_display = private_pp->private_display;
@@ -99,6 +99,23 @@ _tdm_pp_cb_done(tdm_pp *pp_backend, tbm_surface_h src, tbm_surface_h dst,
        int lock_after_cb_done = 0;
        int ret;
 
+       if (!tdm_thread_in_display_thread(private_display)) {
+               tdm_thread_cb_pp_done pp_done;
+               tdm_error ret;
+
+               pp_done.base.type = TDM_THREAD_CB_PP_DONE;
+               pp_done.base.length = sizeof pp_done;
+               pp_done.pp_stamp = private_pp->stamp;
+               pp_done.src = src;
+               pp_done.dst = dst;
+               pp_done.user_data = user_data;
+
+               ret = tdm_thread_send_cb(private_display, &pp_done.base);
+               TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
+
+               return;
+       }
+
        if (tdm_debug_buffer)
                TDM_INFO("pp(%p) done: src(%p) dst(%p)", private_pp, src, dst);
 
@@ -132,6 +149,19 @@ _tdm_pp_cb_done(tdm_pp *pp_backend, tbm_surface_h src, tbm_surface_h dst,
 }
 
 INTERN tdm_private_pp *
+tdm_pp_find_stamp(tdm_private_display *private_display, unsigned long stamp)
+{
+       tdm_private_pp *private_pp = NULL;
+
+       LIST_FOR_EACH_ENTRY(private_pp, &private_display->pp_list, link) {
+               if (private_pp->stamp == stamp)
+                       return private_pp;
+       }
+
+       return NULL;
+}
+
+INTERN tdm_private_pp *
 tdm_pp_create_internal(tdm_private_display *private_display, tdm_error *error)
 {
        tdm_func_display *func_display;
@@ -166,7 +196,7 @@ tdm_pp_create_internal(tdm_private_display *private_display, tdm_error *error)
                return NULL;
        }
 
-       ret = func_pp->pp_set_done_handler(pp_backend, _tdm_pp_cb_done, private_pp);
+       ret = func_pp->pp_set_done_handler(pp_backend, tdm_pp_cb_done, private_pp);
        if (ret != TDM_ERROR_NONE) {
                TDM_ERR("spp(%p) et pp_done_handler failed", private_pp);
                func_pp->pp_destroy(pp_backend);
@@ -175,6 +205,10 @@ tdm_pp_create_internal(tdm_private_display *private_display, tdm_error *error)
                return NULL;
        }
 
+       private_pp->stamp = tdm_helper_get_time_in_millis();
+       while (tdm_pp_find_stamp(private_display, private_pp->stamp))
+               private_pp->stamp++;
+
        LIST_ADD(&private_pp->link, &private_display->pp_list);
        private_pp->private_display = private_display;
        private_pp->pp_backend = pp_backend;
@@ -255,6 +289,7 @@ tdm_pp_destroy_internal(tdm_private_pp *private_pp)
                }
        }
 
+       private_pp->stamp = 0;
        free(private_pp);
 }
 
index bef8fd0..f0e838b 100644 (file)
@@ -48,6 +48,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include <fcntl.h>
 #include <dlfcn.h>
 #include <dirent.h>
+#include <poll.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
 
 #include <tbm_bufmgr.h>
 #include <tbm_surface_queue.h>
@@ -67,6 +70,7 @@ extern "C" {
 
 extern int tdm_debug_buffer;
 extern int tdm_debug_mutex;
+extern int tdm_debug_thread;
 
 #undef EXTERN
 #undef DEPRECATED
@@ -161,6 +165,7 @@ typedef struct _tdm_private_layer tdm_private_layer;
 typedef struct _tdm_private_pp tdm_private_pp;
 typedef struct _tdm_private_capture tdm_private_capture;
 typedef struct _tdm_private_event tdm_private_event;
+typedef struct _tdm_private_thread tdm_private_thread;
 typedef struct _tdm_private_vblank_handler tdm_private_vblank_handler;
 typedef struct _tdm_private_commit_handler tdm_private_commit_handler;
 typedef struct _tdm_private_change_handler tdm_private_change_handler;
@@ -190,16 +195,22 @@ struct _tdm_private_display {
        /* output, pp list */
        struct list_head output_list;
        struct list_head pp_list;
+       struct list_head capture_list;
 
        void **outputs_ptr;
 
        /* for event handling */
        tdm_private_event *private_event;
+
+       /* for own event thread */
+       tdm_private_thread *private_thread;
 };
 
 struct _tdm_private_output {
        struct list_head link;
 
+       unsigned long stamp;
+
        tdm_private_display *private_display;
 
        tdm_caps_output caps;
@@ -242,6 +253,8 @@ struct _tdm_private_layer {
 struct _tdm_private_pp {
        struct list_head link;
 
+       unsigned long stamp;
+
        tdm_private_display *private_display;
 
        tdm_pp *pp_backend;
@@ -254,6 +267,9 @@ struct _tdm_private_pp {
 
 struct _tdm_private_capture {
        struct list_head link;
+       struct list_head display_link;
+
+       unsigned long stamp;
 
        tdm_capture_target target;
 
@@ -304,6 +320,30 @@ typedef struct _tdm_buffer_info {
        struct list_head link;
 } tdm_buffer_info;
 
+tdm_private_output *
+tdm_display_find_output_stamp(tdm_private_display *private_display,
+                              unsigned long stamp);
+tdm_private_pp *
+tdm_pp_find_stamp(tdm_private_display *private_display, unsigned long stamp);
+tdm_private_capture *
+tdm_capture_find_stamp(tdm_private_display *private_display, unsigned long stamp);
+
+void
+tdm_output_cb_vblank(tdm_output *output_backend, unsigned int sequence,
+                     unsigned int tv_sec, unsigned int tv_usec, void *user_data);
+void
+tdm_output_cb_commit(tdm_output *output_backend, unsigned int sequence,
+                     unsigned int tv_sec, unsigned int tv_usec, void *user_data);
+void
+tdm_output_cb_status(tdm_output *output_backend, tdm_output_conn_status status,
+                     void *user_data);
+void
+tdm_pp_cb_done(tdm_pp *pp_backend, tbm_surface_h src, tbm_surface_h dst,
+               void *user_data);
+void
+tdm_capture_cb_done(tdm_capture *capture_backend, tbm_surface_h buffer,
+                    void *user_data);
+
 void
 tdm_output_call_change_handler_internal(tdm_private_output *private_output,
                                         tdm_output_change_type type,
@@ -337,7 +377,7 @@ tdm_event_init(tdm_private_display *private_display);
 void
 tdm_event_deinit(tdm_private_display *private_display);
 void
-tdm_event_create_main_source(tdm_private_display *private_display);
+tdm_event_create_backend_source(tdm_private_display *private_display);
 int
 tdm_event_get_fd(tdm_private_display *private_display);
 tdm_error
@@ -346,6 +386,74 @@ tdm_error
 tdm_event_add_socket(tdm_private_display *private_display, const char *name);
 
 
+typedef enum {
+       TDM_THREAD_CB_NONE,
+       TDM_THREAD_CB_OUTPUT_COMMIT,
+       TDM_THREAD_CB_OUTPUT_VBLANK,
+       TDM_THREAD_CB_OUTPUT_STATUS,
+       TDM_THREAD_CB_PP_DONE,
+       TDM_THREAD_CB_CAPTURE_DONE,
+} tdm_thread_cb_type;
+
+typedef struct _tdm_thread_cb_base tdm_thread_cb_base;
+typedef struct _tdm_thread_cb_output_vblank tdm_thread_cb_output_commit;
+typedef struct _tdm_thread_cb_output_vblank tdm_thread_cb_output_vblank;
+typedef struct _tdm_thread_cb_output_status tdm_thread_cb_output_status;
+typedef struct _tdm_thread_cb_pp_done tdm_thread_cb_pp_done;
+typedef struct _tdm_thread_cb_capture_done tdm_thread_cb_capture_done;
+
+struct _tdm_thread_cb_base {
+       tdm_thread_cb_type type;
+       unsigned int length;
+};
+
+struct _tdm_thread_cb_output_vblank {
+       tdm_thread_cb_base base;
+       unsigned long output_stamp;
+       unsigned int sequence;
+       unsigned int tv_sec;
+       unsigned int tv_usec;
+       void *user_data;
+};
+
+struct _tdm_thread_cb_output_status {
+       tdm_thread_cb_base base;
+       unsigned long output_stamp;
+       tdm_output_conn_status status;
+       void *user_data;
+};
+
+struct _tdm_thread_cb_pp_done {
+       tdm_thread_cb_base base;
+       unsigned long pp_stamp;
+       tbm_surface_h src;
+       tbm_surface_h dst;
+       void *user_data;
+};
+
+struct _tdm_thread_cb_capture_done {
+       tdm_thread_cb_base base;
+       unsigned long capture_stamp;
+       tbm_surface_h buffer;
+       void *user_data;
+};
+
+tdm_error
+tdm_thread_init(tdm_private_display *private_display);
+void
+tdm_thread_deinit(tdm_private_display *private_display);
+int
+tdm_thread_get_fd(tdm_private_display *private_display);
+tdm_error
+tdm_thread_send_cb(tdm_private_display *private_display, tdm_thread_cb_base *base);
+tdm_error
+tdm_thread_handle_cb(tdm_private_display *private_display);
+int
+tdm_thread_in_display_thread(tdm_private_display *private_display);
+
+unsigned long
+tdm_helper_get_time_in_millis(void);
+
 #define _pthread_mutex_lock(l) \
     do {if (tdm_debug_mutex) TDM_INFO("mutex lock"); pthread_mutex_lock(l);} while (0)
 #define _pthread_mutex_unlock(l) \
diff --git a/src/tdm_thread.c b/src/tdm_thread.c
new file mode 100644 (file)
index 0000000..3d64142
--- /dev/null
@@ -0,0 +1,340 @@
+/**************************************************************************
+
+libtdm
+
+Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
+
+Contact: Eunchul Kim <chulspro.kim@samsung.com>,
+         JinYoung Jeon <jy0.jeon@samsung.com>,
+         Taeheon Kim <th908.kim@samsung.com>,
+         YoungJun Cho <yj44.cho@samsung.com>,
+         SooChan Lim <sc1.lim@samsung.com>,
+         Boram Park <sc1.lim@samsung.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sub license, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/socket.h>
+
+#include "tdm.h"
+#include "tdm_private.h"
+#include "tdm_list.h"
+
+struct _tdm_private_thread {
+       pthread_t event_thread;
+       pthread_mutex_t event_mutex;
+
+       pid_t display_tid;
+       pid_t thread_tid;
+
+       /* 0: read, 1: write */
+       int pipe[2];
+};
+
+static void*
+_tdm_thread_main(void *data)
+{
+       tdm_private_display *private_display = (tdm_private_display*)data;
+       tdm_private_thread *private_thread;
+       int fd;
+       struct pollfd fds;
+       int ret;
+
+       _pthread_mutex_lock(&private_display->lock);
+
+       private_thread = private_display->private_thread;
+       private_thread->thread_tid = syscall(SYS_gettid);
+
+       TDM_INFO("display_tid:%d, thread_tid: %d",
+                private_thread->display_tid, private_thread->thread_tid);
+
+       fd = tdm_event_get_fd(private_display);
+       if (fd < 0) {
+               TDM_ERR("couldn't get fd");
+               goto exit_thread;
+       }
+
+       fds.events = POLLIN;
+       fds.fd = fd;
+       fds.revents = 0;
+
+       _pthread_mutex_unlock(&private_display->lock);
+
+       while (1) {
+
+               if (tdm_debug_thread)
+                       TDM_INFO("fd(%d) polling in", fd);
+
+               ret = poll(&fds, 1, -1);
+
+               if (tdm_debug_thread)
+                       TDM_INFO("fd(%d) polling out", fd);
+
+               if (ret < 0) {
+                       if (errno == EBUSY)  /* normal case */
+                               continue;
+                       else {
+                               TDM_ERR("poll failed: %m");
+                               goto exit_thread;
+                       }
+               }
+
+               if (tdm_debug_thread)
+                       TDM_INFO("thread got events");
+
+               _pthread_mutex_lock(&private_display->lock);
+
+               if (tdm_event_dispatch(private_display) < 0)
+                       TDM_ERR("dispatch error");
+
+               _pthread_mutex_unlock(&private_display->lock);
+       }
+
+exit_thread:
+       pthread_exit(NULL);
+}
+
+INTERN tdm_error
+tdm_thread_init(tdm_private_display *private_display)
+{
+       tdm_private_thread *private_thread;
+       const char *thread;
+
+       if (private_display->private_thread)
+               return TDM_ERROR_NONE;
+
+       /* enable as default */
+       thread = getenv("TDM_THREAD");
+       if (thread && strstr(thread, "0")) {
+               TDM_INFO("not using a TDM event thread");
+               return TDM_ERROR_NONE;
+       }
+
+       private_thread = calloc(1, sizeof *private_thread);
+       if (!private_thread) {
+               TDM_ERR("alloc failed");
+               return TDM_ERROR_OUT_OF_MEMORY;
+       }
+
+       if (pipe(private_thread->pipe) != 0) {
+               TDM_ERR("socketpair failed: %m");
+               free(private_thread);
+               return TDM_ERROR_OPERATION_FAILED;
+       }
+
+       private_thread->display_tid = syscall(SYS_gettid);
+
+       pthread_mutex_init(&private_thread->event_mutex, NULL);
+       pthread_create(&private_thread->event_thread, NULL, _tdm_thread_main,
+                      private_display);
+
+       private_display->private_thread = private_thread;
+
+       TDM_INFO("using a TDM event thread. pipe(%d,%d)",
+                private_thread->pipe[0], private_thread->pipe[1]);
+
+       return TDM_ERROR_NONE;
+}
+
+INTERN void
+tdm_thread_deinit(tdm_private_display *private_display)
+{
+       if (!private_display->private_thread)
+               return;
+
+       pthread_cancel(private_display->private_thread->event_thread);
+       pthread_join(private_display->private_thread->event_thread, NULL);
+       pthread_mutex_destroy(&private_display->private_thread->event_mutex);
+
+       if (private_display->private_thread->pipe[0] >= 0)
+               close(private_display->private_thread->pipe[0]);
+       if (private_display->private_thread->pipe[1] >= 0)
+               close(private_display->private_thread->pipe[1]);
+
+       free(private_display->private_thread);
+       private_display->private_thread = NULL;
+
+       TDM_INFO("Finish a TDM event thread");
+}
+
+INTERN int
+tdm_thread_get_fd(tdm_private_display *private_display)
+{
+       tdm_private_thread *private_thread;
+
+       TDM_RETURN_VAL_IF_FAIL(private_display, -1);
+       TDM_RETURN_VAL_IF_FAIL(private_display->private_thread, -1);
+
+       private_thread = private_display->private_thread;
+
+       return private_thread->pipe[0];
+}
+
+INTERN tdm_error
+tdm_thread_send_cb(tdm_private_display *private_display, tdm_thread_cb_base *base)
+{
+       tdm_private_thread *private_thread;
+       ssize_t len;
+
+       TDM_RETURN_VAL_IF_FAIL(base, TDM_ERROR_INVALID_PARAMETER);
+       TDM_RETURN_VAL_IF_FAIL(private_display, TDM_ERROR_INVALID_PARAMETER);
+       TDM_RETURN_VAL_IF_FAIL(private_display->private_thread, TDM_ERROR_INVALID_PARAMETER);
+
+       private_thread = private_display->private_thread;
+
+       if (tdm_debug_thread)
+               TDM_INFO("fd(%d) type(%d), length(%d)",
+                        private_thread->pipe[1], base->type, base->length);
+
+       len = write(private_thread->pipe[1], base, base->length);
+       if (len != base->length) {
+               TDM_ERR("write failed (%d != %d): %m", len, base->length);
+               return TDM_ERROR_OPERATION_FAILED;
+       }
+
+       return TDM_ERROR_NONE;
+}
+
+INTERN tdm_error
+tdm_thread_handle_cb(tdm_private_display *private_display)
+{
+       tdm_private_thread *private_thread;
+       tdm_thread_cb_base *base;
+       char buffer[1024];
+       int len, i;
+
+       TDM_RETURN_VAL_IF_FAIL(private_display, TDM_ERROR_INVALID_PARAMETER);
+       TDM_RETURN_VAL_IF_FAIL(private_display->private_thread, TDM_ERROR_INVALID_PARAMETER);
+
+       private_thread = private_display->private_thread;
+
+       len = read(private_thread->pipe[0], buffer, sizeof buffer);
+
+       if (tdm_debug_thread)
+               TDM_INFO("fd(%d) read length(%d)", private_thread->pipe[0], len);
+
+       if (len == 0)
+               return TDM_ERROR_NONE;
+
+       if (len < sizeof *base) {
+               TDM_NEVER_GET_HERE();
+               return TDM_ERROR_OPERATION_FAILED;
+       }
+
+       i = 0;
+       while (i < len) {
+               base = (tdm_thread_cb_base*)&buffer[i];
+               if (tdm_debug_thread)
+                       TDM_INFO("type(%d), length(%d)", base->type, base->length);
+               switch (base->type) {
+               case TDM_THREAD_CB_OUTPUT_COMMIT:
+               {
+                       tdm_thread_cb_output_commit *output_commit = (tdm_thread_cb_output_commit*)base;
+                       tdm_output *output_backend =
+                               tdm_display_find_output_stamp(private_display, output_commit->output_stamp);
+                       if (!output_backend) {
+                               TDM_WRN("no output(%ld)", output_commit->output_stamp);
+                               break;
+                       }
+                       tdm_output_cb_commit(output_backend, output_commit->sequence,
+                                            output_commit->tv_sec, output_commit->tv_usec,
+                                            output_commit->user_data);
+                       break;
+               }
+               case TDM_THREAD_CB_OUTPUT_VBLANK:
+               {
+                       tdm_thread_cb_output_vblank *output_vblank = (tdm_thread_cb_output_vblank*)base;
+                       tdm_output *output_backend =
+                               tdm_display_find_output_stamp(private_display, output_vblank->output_stamp);
+                       if (!output_backend) {
+                               TDM_WRN("no output(%ld)", output_vblank->output_stamp);
+                               break;
+                       }
+                       tdm_output_cb_vblank(output_backend, output_vblank->sequence,
+                                            output_vblank->tv_sec, output_vblank->tv_usec,
+                                            output_vblank->user_data);
+                       break;
+               }
+               case TDM_THREAD_CB_OUTPUT_STATUS:
+               {
+                       tdm_thread_cb_output_status *output_status = (tdm_thread_cb_output_status*)base;
+                       tdm_output *output_backend =
+                               tdm_display_find_output_stamp(private_display, output_status->output_stamp);
+                       if (!output_backend) {
+                               TDM_WRN("no output(%ld)", output_status->output_stamp);
+                               break;
+                       }
+                       tdm_output_cb_status(output_backend, output_status->status,
+                                            output_status->user_data);
+                       break;
+               }
+               case TDM_THREAD_CB_PP_DONE:
+               {
+                       tdm_thread_cb_pp_done *pp_done = (tdm_thread_cb_pp_done*)base;
+                       tdm_pp *pp_backend =
+                               tdm_pp_find_stamp(private_display, pp_done->pp_stamp);
+                       if (!pp_backend) {
+                               TDM_WRN("no pp(%ld)", pp_done->pp_stamp);
+                               break;
+                       }
+                       tdm_pp_cb_done(pp_backend, pp_done->src, pp_done->dst, pp_done->user_data);
+                       break;
+               }
+               case TDM_THREAD_CB_CAPTURE_DONE:
+               {
+                       tdm_thread_cb_capture_done *capture_done = (tdm_thread_cb_capture_done*)base;
+                       tdm_capture *capture_backend =
+                               tdm_capture_find_stamp(private_display, capture_done->capture_stamp);
+                       if (!capture_backend) {
+                               TDM_WRN("no capture(%ld)", capture_done->capture_stamp);
+                               break;
+                       }
+                       tdm_capture_cb_done(capture_backend, capture_done->buffer, capture_done->user_data);
+                       break;
+               }
+               default:
+                       break;
+               }
+               i += base->length;
+       }
+
+       return TDM_ERROR_NONE;
+}
+
+INTERN int
+tdm_thread_in_display_thread(tdm_private_display *private_display)
+{
+       tdm_private_thread *private_thread;
+
+       TDM_RETURN_VAL_IF_FAIL(private_display, 1);
+
+       if (!private_display->private_thread)
+               return 1;
+
+       private_thread = private_display->private_thread;
+
+       return (private_thread->display_tid == syscall(SYS_gettid)) ? 1 : 0;
+}