vblank: return TDM_ERROR_TIMEOUT when timeout occurs
authorBoram Park <boram1288.park@samsung.com>
Wed, 3 Jan 2018 11:16:25 +0000 (20:16 +0900)
committerBoram Park <boram1288.park@samsung.com>
Wed, 3 Jan 2018 12:06:32 +0000 (21:06 +0900)
If a vblank callback isn't called in 2000ms, tdm vblank will return
TDM_ERROR_TIMEOUT to client.

Change-Id: Ib5cd14dddd8bef051e01664c52021f57c7099f48

include/tdm_common.h
src/tdm_vblank.c

index 054cb5e..ee86347 100644 (file)
@@ -68,6 +68,7 @@ typedef enum {
        TDM_ERROR_NO_CAPABILITY         = -9, /**< no capability */
        TDM_ERROR_DPMS_OFF              = -10, /**< dpms off */
        TDM_ERROR_OUTPUT_DISCONNECTED   = -11, /**< output disconnected */
+       TDM_ERROR_TIMEOUT               = -12, /**< timeout */
 } tdm_error;
 
 /**
index 4816411..b272a2d 100644 (file)
@@ -125,6 +125,9 @@ typedef struct _tdm_private_vblank {
        /* for SW */
        tdm_event_loop_source *SW_timer;
        struct list_head SW_wait_list;
+
+       /* for timeout */
+       tdm_event_loop_source *timeout_timer;
 } tdm_private_vblank;
 
 struct _tdm_vblank_wait_info {
@@ -161,6 +164,9 @@ static tdm_error _tdm_vblank_wait_SW(tdm_vblank_wait_info *wait_info);
 static void _tdm_vblank_cb_vblank_HW(tdm_output *output, unsigned int sequence,
                                                                         unsigned int tv_sec, unsigned int tv_usec,
                                                                         void *user_data);
+static void _tdm_vblank_timeout_timer_update(tdm_private_vblank *private_vblank, int ms_delay);
+static void _tdm_vblank_get_client_information(tdm_private_vblank *private_vblank,
+                                                                                          pid_t *pid, const char **name);
 
 #if 0
 static void
@@ -302,6 +308,13 @@ _tdm_vblank_free_HW_wait(tdm_private_vblank *private_vblank, tdm_error error, un
 {
        tdm_vblank_wait_info *w = NULL, *ww = NULL;
 
+       if (!LIST_IS_EMPTY(&private_vblank->SW_wait_list))
+               TDM_NEVER_GET_HERE();
+
+       tdm_display_lock(private_vblank->dpy);
+       _tdm_vblank_timeout_timer_update(private_vblank, 0);
+       tdm_display_unlock(private_vblank->dpy);
+
        LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->HW_wait_list, link) {
                LIST_DEL(&w->link);
                _tdm_vblank_valid_list_del(&w->valid_link);
@@ -535,14 +548,20 @@ tdm_vblank_destroy(tdm_vblank *vblank)
        tdm_output_remove_change_handler(private_vblank->output,
                                                                         _tdm_vblank_cb_output_change, private_vblank);
 
-       _tdm_vblank_free_HW_wait(private_vblank, 0, 0);
-
        LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->SW_wait_list, link) {
                LIST_DEL(&w->link);
                _tdm_vblank_valid_list_del(&w->valid_link);
                free(w);
        }
 
+       _tdm_vblank_free_HW_wait(private_vblank, 0, 0);
+
+       if (private_vblank->timeout_timer) {
+               tdm_display_lock(private_vblank->dpy);
+               tdm_event_loop_source_remove(private_vblank->timeout_timer);
+               tdm_display_unlock(private_vblank->dpy);
+       }
+
        VIN("destroyed");
 
        free(private_vblank);
@@ -694,6 +713,84 @@ tdm_vblank_get_enable_fake(tdm_vblank *vblank, unsigned int *enable_fake)
 }
 
 static tdm_error
+_tdm_vblank_timeout_timer_cb(void *user_data)
+{
+       tdm_private_vblank *private_vblank = user_data;
+       tdm_vblank_wait_info *w = NULL, *ww = NULL;
+       tdm_error error = TDM_ERROR_TIMEOUT;
+       pid_t pid;
+       const char *proc_name;
+
+       TDM_RETURN_VAL_IF_FAIL(private_vblank != NULL, TDM_ERROR_OPERATION_FAILED);
+
+       _tdm_vblank_get_client_information(private_vblank, &pid, &proc_name);
+
+       if (!LIST_IS_EMPTY(&private_vblank->HW_wait_list)) {
+
+               VER("HW vblank TIMEOUT!! (pid: %u, name: %s)", pid, proc_name);
+
+               LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->HW_wait_list, link) {
+                       LIST_DEL(&w->link);
+                       _tdm_vblank_valid_list_del(&w->valid_link);
+
+                       tdm_output_remove_vblank_handler_internal(private_vblank->output, _tdm_vblank_cb_vblank_HW, w);
+
+                       if (w->func)
+                               w->func(private_vblank, error, 0, 0, 0, w->user_data);
+
+                       free(w);
+               }
+       }
+
+       if (!LIST_IS_EMPTY(&private_vblank->SW_wait_list)) {
+
+               VER("SW vblank TIMEOUT!! (pid: %u, name: %s)", pid, proc_name);
+
+               LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->SW_wait_list, link) {
+                       LIST_DEL(&w->link);
+                       _tdm_vblank_valid_list_del(&w->valid_link);
+
+                       if (w->func)
+                               w->func(private_vblank, error, 0, 0, 0, w->user_data);
+
+                       free(w);
+               }
+       }
+
+       return TDM_ERROR_NONE;
+}
+
+static void
+_tdm_vblank_timeout_timer_update(tdm_private_vblank *private_vblank, int ms_delay)
+{
+       tdm_error ret;
+
+       if (!private_vblank->timeout_timer) {
+               private_vblank->timeout_timer =
+                       tdm_event_loop_add_timer_handler(private_vblank->dpy,
+                                                                                        _tdm_vblank_timeout_timer_cb,
+                                                                                        private_vblank,
+                                                                                        &ret);
+               if (!private_vblank->timeout_timer) {
+                       VER("couldn't add timer");
+                       return;
+               }
+               VIN("Create Timeout timer");
+       }
+
+       ret = tdm_event_loop_source_timer_update(private_vblank->timeout_timer, ms_delay);
+       if (ret != TDM_ERROR_NONE) {
+               VER("couldn't update timer");
+               return;
+       }
+
+       if (ms_delay != 0)
+               VDB("timeout timer updated");
+       else
+               VDB("timeout timer disabled");
+}
+
+static tdm_error
 _tdm_vblank_sw_timer_update(tdm_private_vblank *private_vblank)
 {
        tdm_vblank_wait_info *first_wait_info = NULL;
@@ -797,6 +894,13 @@ _tdm_vblank_cb_vblank_HW(tdm_output *output, unsigned int sequence,
                VWR("couldn't update sw timer");
        }
 
+       if (!LIST_IS_EMPTY(&private_vblank->SW_wait_list))
+               TDM_NEVER_GET_HERE();
+
+       tdm_display_lock(private_vblank->dpy);
+       _tdm_vblank_timeout_timer_update(private_vblank, 0);
+       tdm_display_unlock(private_vblank->dpy);
+
        LIST_DEL(&wait_info->link);
        _tdm_vblank_valid_list_del(&wait_info->valid_link);
 
@@ -948,6 +1052,11 @@ tdm_vblank_cb_vblank_SW(tdm_vblank *vblank, double vblank_stamp)
                return TDM_ERROR_OPERATION_FAILED;
        }
 
+       if (!LIST_IS_EMPTY(&private_vblank->HW_wait_list))
+               TDM_NEVER_GET_HERE();
+
+       _tdm_vblank_timeout_timer_update(private_vblank, 0);
+
        first_wait_info = container_of(private_vblank->SW_wait_list.next, first_wait_info, link);
        TDM_RETURN_VAL_IF_FAIL(first_wait_info != NULL, TDM_ERROR_OPERATION_FAILED);
 
@@ -1148,6 +1257,10 @@ tdm_vblank_wait(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec,
                return ret;
        }
 
+       tdm_display_lock(private_vblank->dpy);
+       _tdm_vblank_timeout_timer_update(private_vblank, 2000);
+       tdm_display_unlock(private_vblank->dpy);
+
        return TDM_ERROR_NONE;
 }
 
@@ -1242,6 +1355,29 @@ tdm_vblank_get_stamp(tdm_vblank *vblank)
        return private_vblank->stamp;
 }
 
+static void
+_tdm_vblank_get_client_information(tdm_private_vblank *private_vblank, pid_t *pid, const char **name)
+{
+       struct wl_client *client;
+
+       if (!private_vblank->resource)
+               goto no_client;
+
+       client = wl_resource_get_client(private_vblank->resource);
+       if (!client)
+               goto no_client;
+
+       wl_client_get_credentials(client, pid, NULL, NULL);
+       *name = tdm_server_get_client_name(*pid);
+
+       return;
+
+no_client:
+       *pid = 0;
+       *name = NULL;
+       return;
+}
+
 INTERN void
 tdm_vblank_get_vblank_list_information(tdm_display *dpy, char *reply, int *len)
 {
@@ -1258,13 +1394,7 @@ tdm_vblank_get_vblank_list_information(tdm_display *dpy, char *reply, int *len)
                const char *proc_name = NULL;
                pid_t pid = 0;
 
-               if (v->resource) {
-                       struct wl_client *client = wl_resource_get_client(v->resource);
-                       if (client) {
-                               wl_client_get_credentials(client, &pid, NULL, NULL);
-                               proc_name = tdm_server_get_client_name(pid);
-                       }
-               }
+               _tdm_vblank_get_client_information(v, &pid, &proc_name);
 
                TDM_SNPRINTF(reply, len, "%-12s %u  %u     %d      %u    %s (pid: %u)\n",
                                         v->name, v->fps, v->ignore_global_fps, v->offset, v->enable_fake,