vblank: trace the vblank object creation. 17/165217/4
authorBoram Park <boram1288.park@samsung.com>
Wed, 27 Dec 2017 05:56:48 +0000 (14:56 +0900)
committerBoram Park <boram1288.park@samsung.com>
Thu, 28 Dec 2017 07:38:39 +0000 (16:38 +0900)
We don't allow adding a create handler in sub-thread because tdm_vblank_create()
can be called in both threads and tdm_thread_send_cb supports only one-way
communication now.

Change-Id: I2c2b90cc29348aa9b24f5882369d94435a358e52

include/tdm.h
include/tdm_types.h
src/tdm.c
src/tdm_private.h
src/tdm_thread.c
src/tdm_vblank.c

index 2c0ba6a..9f8ea82 100644 (file)
@@ -1281,6 +1281,28 @@ tdm_error
 tdm_vblank_enable_global_fps(unsigned int enable, unsigned int fps);
 
 /**
+ * @brief Add the vblank create handler.
+ * @param[in] dpy A display object
+ * @param[in] func The user vblank create handler
+ * @param[in] user_data The user data
+ * @details
+ * The user vblank create handler will be called when new vblank object created.
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ */
+tdm_error
+tdm_vblank_add_create_handler(tdm_display *dpy, tdm_vblank_create_handler func, void *user_data);
+
+/**
+ * @brief Remove the vblank create handler.
+ * @param[in] dpy A display object
+ * @param[in] func The user vblank create handler
+ * @param[in] user_data The user data
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ */
+void
+tdm_vblank_remove_create_handler(tdm_display *dpy, tdm_vblank_create_handler func, void *user_data);
+
+/**
  * @brief Create a vblank object
  * @param[in] dpy A display object
  * @param[in] output A output object
index 75cb920..ebb8291 100644 (file)
@@ -261,6 +261,11 @@ typedef void (*tdm_capture_done_handler)(tdm_capture *capture,
                                                                                 tbm_surface_h buffer, void *user_data);
 
 /**
+ * @brief The create handler of a vblank object
+ */
+typedef void (*tdm_vblank_create_handler)(tdm_vblank *vblank, void *user_data);
+
+/**
  * @brief The 'need to validate' handler of an output object
  * @since 2.0.0
  */
index 53f1547..9492336 100644 (file)
--- a/src/tdm.c
+++ b/src/tdm.c
@@ -977,6 +977,10 @@ tdm_display_init(tdm_error *error)
        TDM_DBG("prepare init time: %.3f ms", (stamp2 - stamp1) * 1000.0);
        stamp1 = stamp2;
 
+       ret = tdm_vblank_init(private_display);
+       if (ret != TDM_ERROR_NONE)
+               goto failed_vblank;
+
        ret = tdm_event_loop_init(private_display);
        if (ret != TDM_ERROR_NONE)
                goto failed_event;
@@ -1065,6 +1069,8 @@ failed_load:
        tdm_event_loop_stop(private_display);
        tdm_event_loop_deinit(private_display);
 failed_event:
+       tdm_vblank_deinit(private_display);
+failed_vblank:
        _pthread_mutex_unlock(&private_display->lock);
        pthread_mutex_destroy(&private_display->lock);
 failed_mutex_init:
@@ -1106,6 +1112,7 @@ tdm_display_deinit(tdm_display *dpy)
        _pthread_mutex_unlock(&private_display->lock);
 
        tdm_event_loop_deinit(private_display);
+       tdm_vblank_deinit(private_display);
 
 #ifdef INIT_BUFMGR
        if (private_display->bufmgr)
index b7cb0a3..6d9c95f 100644 (file)
@@ -511,8 +511,14 @@ void
 tdm_capture_cb_done(tdm_capture *capture_backend, tbm_surface_h buffer,
                                        void *user_data);
 tdm_error
+tdm_vblank_init(tdm_display *dpy);
+void
+tdm_vblank_deinit(tdm_display *dpy);
+tdm_error
 tdm_vblank_cb_vblank_SW(tdm_vblank *vblank, double vblank_stamp);
 tdm_error
+tdm_vblank_cb_vblank_create(tdm_vblank *vblank, double vblank_stamp);
+tdm_error
 tdm_vblank_set_add_front(tdm_vblank *vblank, unsigned int add_front);
 tdm_error
 tdm_vblank_set_resource(tdm_vblank *vblank, struct wl_resource *resource);
@@ -587,6 +593,7 @@ typedef enum {
        TDM_THREAD_CB_PP_DONE,
        TDM_THREAD_CB_CAPTURE_DONE,
        TDM_THREAD_CB_VBLANK_SW,
+       TDM_THREAD_CB_VBLANK_CREATE,
        TDM_THREAD_CB_NEED_VALIDATE,
 } tdm_thread_cb_type;
 
@@ -598,6 +605,7 @@ typedef struct _tdm_thread_cb_output_dpms tdm_thread_cb_output_dpms;
 typedef struct _tdm_thread_cb_pp_done tdm_thread_cb_pp_done;
 typedef struct _tdm_thread_cb_capture_done tdm_thread_cb_capture_done;
 typedef struct _tdm_thread_cb_vblank_sw tdm_thread_cb_vblank_sw;
+typedef struct _tdm_thread_cb_vblank_create tdm_thread_cb_vblank_create;
 typedef struct _tdm_thread_cb_need_validate tdm_thread_cb_need_validate;
 
 struct _tdm_thread_cb_base {
@@ -648,6 +656,11 @@ struct _tdm_thread_cb_vblank_sw {
        double vblank_stamp;
 };
 
+struct _tdm_thread_cb_vblank_create {
+       tdm_thread_cb_base base;
+       double vblank_stamp;
+};
+
 struct _tdm_thread_cb_need_validate {
        tdm_thread_cb_base base;
        tdm_private_output *o;
index ed5d049..a775690 100644 (file)
@@ -360,6 +360,11 @@ tdm_thread_handle_cb(tdm_private_loop *private_loop)
                        tdm_vblank_cb_vblank_SW(NULL, vblank_sw->vblank_stamp);
                        break;
                }
+               case TDM_THREAD_CB_VBLANK_CREATE: {
+                       tdm_thread_cb_vblank_create *vblank_create = (tdm_thread_cb_vblank_create*)base;
+                       tdm_vblank_cb_vblank_create(NULL, vblank_create->vblank_stamp);
+                       break;
+               }
                case TDM_THREAD_CB_NEED_VALIDATE: {
                        tdm_thread_cb_need_validate *ev = (tdm_thread_cb_need_validate*)base;
                        tdm_output_cb_need_validate(ev->o);
index 24dd991..bb62f42 100644 (file)
@@ -40,6 +40,7 @@
 #include "tdm.h"
 #include "tdm_private.h"
 #include "tdm_list.h"
+#include "tdm_macro.h"
 
 /* CAUTION:
  * Basically tdm vblank doesn't care about thread things.
@@ -108,6 +109,7 @@ typedef struct _tdm_private_vblank {
        int offset;
        unsigned int enable_fake;
        unsigned int ignore_global_fps;
+       unsigned int in_create_handler;
 
        double vblank_gap;
        unsigned int quotient;
@@ -146,12 +148,20 @@ struct _tdm_vblank_wait_info {
        unsigned int target_seq;
 };
 
+typedef struct _tdm_vblank_create_handler_info {
+       struct list_head link;
+
+       tdm_vblank_create_handler func;
+       void *user_data;
+} tdm_vblank_create_handler_info;
+
 /* valid_vblank_list and valid_wait_list should be protected by valid_list_lock because
  * tdm_vblank can be used in multi-thread.
  */
 static pthread_mutex_t valid_list_lock;
 static struct list_head valid_vblank_list;
 static struct list_head valid_wait_list;
+static struct list_head create_handler_list;
 static unsigned int vblank_list_inited;
 static unsigned int vblank_global_fps;
 static double stamp = 0;
@@ -479,6 +489,143 @@ tdm_vblank_enable_global_fps(unsigned int enable, unsigned int fps)
        return TDM_ERROR_NONE;
 }
 
+INTERN tdm_error
+tdm_vblank_cb_vblank_create(tdm_vblank *vblank, double vblank_stamp)
+{
+       tdm_private_vblank *private_vblank;
+       tdm_vblank_create_handler_info *ch_info = NULL, *hh = NULL;
+
+       TDM_RETURN_VAL_IF_FAIL(vblank || vblank_stamp > 0, TDM_ERROR_INVALID_PARAMETER);
+
+       if (vblank)
+               private_vblank = vblank;
+       else {
+               private_vblank = _tdm_vblank_find(vblank_stamp);
+               if (!private_vblank) {
+                       TDM_DBG("can't find vblank(%.0f) from valid_list", vblank_stamp);
+                       return TDM_ERROR_NONE;
+               }
+       }
+
+       if (!tdm_thread_in_display_thread(syscall(SYS_gettid))) {
+               tdm_thread_cb_vblank_create vblank_create;
+               tdm_private_display *private_display = private_vblank->dpy;
+               tdm_error ret;
+
+               vblank_create.base.type = TDM_THREAD_CB_VBLANK_CREATE;
+               vblank_create.base.length = sizeof vblank_create;
+               vblank_create.vblank_stamp = private_vblank->stamp;
+
+               ret = tdm_thread_send_cb(private_display->private_loop, &vblank_create.base);
+               TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
+
+               return TDM_ERROR_NONE;
+       }
+
+       LIST_FOR_EACH_ENTRY_SAFE(ch_info, hh, &create_handler_list, link) {
+               private_vblank->in_create_handler = 1;
+               ch_info->func(private_vblank, ch_info->user_data);
+               private_vblank->in_create_handler = 0;
+       }
+
+       return TDM_ERROR_NONE;
+}
+
+EXTERN tdm_error
+tdm_vblank_add_create_handler(tdm_display *dpy, tdm_vblank_create_handler func, void *user_data)
+{
+       tdm_vblank_create_handler_info *ch_info;
+
+       TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
+
+       /* we don't allow adding a create handler in sub-thread because tdm_vblank_create()
+        * can be called in both threads and tdm_thread_send_cb supports only one-way
+        * communication now.
+        */
+       if (!tdm_thread_in_display_thread(syscall(SYS_gettid))) {
+               TDM_ERR("add_create_handler should be called in main thread");
+               return TDM_ERROR_BAD_REQUEST;
+       }
+
+       ch_info = calloc(1, sizeof *ch_info);
+       TDM_RETURN_VAL_IF_FAIL(ch_info != NULL, TDM_ERROR_OUT_OF_MEMORY);
+
+       ch_info->func = func;
+       ch_info->user_data = user_data;
+
+       LIST_ADDTAIL(&ch_info->link, &create_handler_list);
+
+       return TDM_ERROR_NONE;
+}
+
+EXTERN void
+tdm_vblank_remove_create_handler(tdm_display *dpy, tdm_vblank_create_handler func, void *user_data)
+{
+       tdm_vblank_create_handler_info *ch_info = NULL, *hh = NULL;
+
+       /* we don't allow adding a create handler in sub-thread because tdm_vblank_create()
+        * can be called in both threads and tdm_thread_send_cb supports only one-way
+        * communication now.
+        */
+       if (!tdm_thread_in_display_thread(syscall(SYS_gettid))) {
+               TDM_ERR("remove_create_handler should be called in main thread");
+               return;
+       }
+
+       LIST_FOR_EACH_ENTRY_SAFE(ch_info, hh, &create_handler_list, link) {
+               if (ch_info->func != func && ch_info->user_data != user_data)
+                       continue;
+
+               LIST_DEL(&ch_info->link);
+               free(ch_info);
+               return;
+       }
+}
+
+INTERN tdm_error
+tdm_vblank_init(tdm_display *dpy)
+{
+       if (vblank_list_inited)
+               return TDM_ERROR_NONE;
+
+       if (pthread_mutex_init(&valid_list_lock, NULL)) {
+               TDM_ERR("mutex init failed: %m");
+               return TDM_ERROR_OUT_OF_MEMORY;
+       }
+
+       LIST_INITHEAD(&valid_vblank_list);
+       LIST_INITHEAD(&valid_wait_list);
+       LIST_INITHEAD(&create_handler_list);
+
+       vblank_list_inited = 1;
+
+       return TDM_ERROR_NONE;
+}
+
+INTERN void
+tdm_vblank_deinit(tdm_display *dpy)
+{
+       tdm_vblank_create_handler_info *ch_info = NULL, *hh = NULL;
+
+       if (!vblank_list_inited)
+               return;
+
+       if (!LIST_IS_EMPTY(&valid_vblank_list))
+               TDM_NEVER_GET_HERE();
+
+       if (!LIST_IS_EMPTY(&valid_wait_list))
+               TDM_NEVER_GET_HERE();
+
+       LIST_FOR_EACH_ENTRY_SAFE(ch_info, hh, &create_handler_list, link) {
+               LIST_DEL(&ch_info->link);
+               free(ch_info);
+       }
+
+       pthread_mutex_destroy(&valid_list_lock);
+
+       vblank_list_inited = 0;
+}
+
 EXTERN tdm_vblank *
 tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error)
 {
@@ -491,20 +638,6 @@ tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error)
        if (error)
                *error = TDM_ERROR_NONE;
 
-       if (!vblank_list_inited) {
-               if (pthread_mutex_init(&valid_list_lock, NULL)) {
-                       /* LCOV_EXCL_START */
-                       TDM_ERR("mutex init failed: %m");
-                       if (error)
-                               *error = TDM_ERROR_OPERATION_FAILED;
-                       return NULL;
-                       /* LCOV_EXCL_STOP */
-               }
-               LIST_INITHEAD(&valid_vblank_list);
-               LIST_INITHEAD(&valid_wait_list);
-               vblank_list_inited = 1;
-       }
-
        private_vblank = calloc(1, sizeof * private_vblank);
        if (!private_vblank) {
                /* LCOV_EXCL_START */
@@ -537,6 +670,10 @@ tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error)
        VIN("created. vrefresh(%d) connection(%d)",
                private_vblank->vrefresh, private_vblank->connection);
 
+       tdm_display_lock(private_vblank->dpy);
+       tdm_vblank_cb_vblank_create(NULL, private_vblank->stamp);
+       tdm_display_unlock(private_vblank->dpy);
+
        return (tdm_vblank *)private_vblank;
 }
 
@@ -548,6 +685,11 @@ tdm_vblank_destroy(tdm_vblank *vblank)
 
        TDM_RETURN_IF_FAIL(tdm_vblank_is_valid(vblank));
 
+       if (private_vblank->in_create_handler) {
+               TDM_ERR("NOT allowed to be called in a create handler");
+               return;
+       }
+
        _tdm_vblank_valid_list_del(&private_vblank->valid_link);
 
        if (private_vblank->SW_timer) {
@@ -1085,6 +1227,11 @@ tdm_vblank_wait(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec,
        TDM_RETURN_VAL_IF_FAIL(tdm_vblank_is_valid(vblank), TDM_ERROR_INVALID_PARAMETER);
        TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
 
+       if (private_vblank->in_create_handler) {
+               TDM_ERR("NOT allowed to be called in a create handler");
+               return TDM_ERROR_BAD_REQUEST;
+       }
+
        if (private_vblank->owner_tid != syscall(SYS_gettid)) {
                TDM_ERR("SHOULD be called in the owner thread(%d)", (int)private_vblank->owner_tid);
                return TDM_ERROR_BAD_REQUEST;