client: add mutex lock 87/168787/1
authorBoram Park <boram1288.park@samsung.com>
Tue, 30 Jan 2018 01:35:36 +0000 (10:35 +0900)
committerBoram Park <boram1288.park@samsung.com>
Wed, 31 Jan 2018 03:35:22 +0000 (12:35 +0900)
Change-Id: I2c2cb6f7a06b67dcacfd6e1bcf502877ead20dc5

client/tdm_client.c

index 81806d4..51e5c5e 100644 (file)
@@ -55,6 +55,8 @@
 typedef struct _tdm_private_client_vblank tdm_private_client_vblank;
 
 typedef struct _tdm_private_client {
+       pthread_mutex_t lock;
+
        struct wl_display *display;
        struct wl_event_queue *queue;
        struct wl_registry *registry;
@@ -115,6 +117,7 @@ typedef struct _tdm_client_output_handler_info {
        void *user_data;
 
        struct list_head link;
+       struct list_head call_link;
 } tdm_client_output_handler_info;
 
 typedef struct _tdm_client_wait_info {
@@ -128,6 +131,7 @@ typedef struct _tdm_client_wait_info {
        int need_free;
 
        struct list_head link;
+       struct list_head call_link;
 } tdm_client_wait_info;
 
 static void
@@ -153,35 +157,50 @@ _tdm_client_vblank_cb_done(void *data, struct wl_tdm_vblank *wl_tdm_vblank,
                                                   uint32_t tv_usec, uint32_t error)
 {
        tdm_private_client_vblank *private_vblank = data;
-       tdm_client_wait_info *w = NULL, *ww = NULL;
+       tdm_private_client *private_client;
+       tdm_client_wait_info *w = NULL, *wait_info = NULL;
 
        TDM_RETURN_IF_FAIL(private_vblank != NULL);
 
+       private_client = private_vblank->private_output->private_client;
+
        private_vblank->last_time = TDM_TIME(tv_sec, tv_usec);
 
        TDM_DBG("vblank(%p) req_id(%u) sequence(%u) time(%.6f)",
                        private_vblank, req_id, sequence, TDM_TIME(tv_sec, tv_usec));
 
-       LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->wait_list, link) {
+       LIST_FOR_EACH_ENTRY(w, &private_vblank->wait_list, link) {
                if (w->req_id != req_id)
                        continue;
 
-               if (private_vblank->enable_ttrace)
-                       TDM_TRACE_ASYNC_END((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
+               wait_info = w;
+               break;
+       }
+
+       if (!wait_info) {
+               TDM_ERR("no wait infomation for req_id(%d)", req_id);
+               return;
+       }
 
-               if (w->req_time >= private_vblank->last_time)
-                       TDM_WRN("'req(%.6f) < last(%.6f)' failed", w->req_time, private_vblank->last_time);
+       if (private_vblank->enable_ttrace)
+               TDM_TRACE_ASYNC_END((int)wait_info->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp);
 
-               if (w->func)
-                       w->func(private_vblank, error, sequence, tv_sec, tv_usec, w->user_data);
+       if (wait_info->req_time >= private_vblank->last_time)
+               TDM_WRN("'req(%.6f) < last(%.6f)' failed. error(%d)", wait_info->req_time, private_vblank->last_time, error);
 
-               if (w->need_free) {
-                       LIST_DEL(&w->link);
-                       free(w);
-               } else
-                       w->need_free = 1;
-               return;
+       if (wait_info->need_free)
+               LIST_DEL(&wait_info->link);
+
+       if (wait_info->func) {
+               pthread_mutex_unlock(&private_client->lock);
+               wait_info->func(private_vblank, error, sequence, tv_sec, tv_usec, wait_info->user_data);
+               pthread_mutex_lock(&private_client->lock);
        }
+
+       if (wait_info->need_free)
+               free(w);
+       else
+               wait_info->need_free = 1;
 }
 /* LCOV_EXCL_STOP */
 
@@ -257,11 +276,15 @@ static void
 _tdm_client_output_cb_connection(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value, uint32_t error)
 {
        tdm_private_client_output *private_output = (tdm_private_client_output*)data;
-       tdm_client_output_handler_info *h = NULL;
+       tdm_private_client *private_client;
+       tdm_client_output_handler_info *h = NULL, *hh = NULL;
        tdm_value v;
+       struct list_head call_list;
 
        TDM_RETURN_IF_FAIL(private_output != NULL);
 
+       private_client = private_output->private_client;
+
        if (private_output->connection == value)
                return;
 
@@ -275,22 +298,34 @@ _tdm_client_output_cb_connection(void *data, struct wl_tdm_output *wl_tdm_output
                        wl_proxy_get_id((struct wl_proxy*)private_output->output),
                        value);
 
-       v.u32 = value;
+       LIST_INITHEAD(&call_list);
+
        LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
+               LIST_ADDTAIL(&h->call_link, &call_list);
+       }
+
+       v.u32 = value;
+       pthread_mutex_unlock(&private_client->lock);
+       LIST_FOR_EACH_ENTRY_SAFE(h, hh, &call_list, call_link) {
                if (h->func)
                        h->func(private_output, TDM_OUTPUT_CHANGE_CONNECTION, v, h->user_data);
        }
+       pthread_mutex_lock(&private_client->lock);
 }
 
 static void
 _tdm_client_output_cb_dpms(void *data, struct wl_tdm_output *wl_tdm_output, uint32_t value, uint32_t error)
 {
        tdm_private_client_output *private_output = (tdm_private_client_output*)data;
-       tdm_client_output_handler_info *h = NULL;
+       tdm_private_client *private_client;
+       tdm_client_output_handler_info *h = NULL, *hh = NULL;
        tdm_value v;
+       struct list_head call_list;
 
        TDM_RETURN_IF_FAIL(private_output != NULL);
 
+       private_client = private_output->private_client;
+
        /* If value is extended value, we handle it as DPMS on in client side
         * The extended DPMS value is valid only in server side.
         * Or, need to export to client side also?
@@ -311,11 +346,19 @@ _tdm_client_output_cb_dpms(void *data, struct wl_tdm_output *wl_tdm_output, uint
                        wl_proxy_get_id((struct wl_proxy*)private_output->output),
                        value);
 
-       v.u32 = value;
+       LIST_INITHEAD(&call_list);
+
        LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
+               LIST_ADDTAIL(&h->call_link, &call_list);
+       }
+
+       v.u32 = value;
+       pthread_mutex_unlock(&private_client->lock);
+       LIST_FOR_EACH_ENTRY_SAFE(h, hh, &call_list, call_link) {
                if (h->func)
                        h->func(private_output, TDM_OUTPUT_CHANGE_DPMS, v, h->user_data);
        }
+       pthread_mutex_lock(&private_client->lock);
 }
 
 static const struct wl_tdm_output_listener tdm_client_output_listener = {
@@ -369,6 +412,14 @@ tdm_client_create(tdm_error *error)
                /* LCOV_EXCL_STOP */
        }
 
+       if (pthread_mutex_init(&private_client->lock, NULL)) {
+               TDM_ERR("mutex init failed: %m");
+               free(private_client);
+               if (error)
+                       *error = TDM_ERROR_OUT_OF_MEMORY;
+               return NULL;
+       }
+
        LIST_INITHEAD(&private_client->output_list);
 
        private_client->display = wl_display_connect("tdm-socket");
@@ -407,6 +458,8 @@ tdm_client_destroy(tdm_client *client)
        if (!private_client)
                return;
 
+       pthread_mutex_lock(&private_client->lock);
+
        if (private_client->temp_vblank)
                tdm_client_vblank_destroy(private_client->temp_vblank);
 
@@ -423,6 +476,9 @@ tdm_client_destroy(tdm_client *client)
        if (private_client->display)
                wl_display_disconnect(private_client->display);
 
+       pthread_mutex_unlock(&private_client->lock);
+       pthread_mutex_destroy(&private_client->lock);
+
        free(private_client);
 }
 
@@ -436,7 +492,12 @@ tdm_client_get_fd(tdm_client *client, int *fd)
 
        private_client = (tdm_private_client*)client;
 
+       pthread_mutex_lock(&private_client->lock);
+
        *fd = wl_display_get_fd(private_client->display);
+
+       pthread_mutex_unlock(&private_client->lock);
+
        if (*fd < 0)
                return TDM_ERROR_OPERATION_FAILED;
 
@@ -453,6 +514,8 @@ tdm_client_handle_events(tdm_client *client)
        /* LCOV_EXCL_START */
        private_client = (tdm_private_client*)client;
 
+       pthread_mutex_lock(&private_client->lock);
+
        if (private_client->enable_ttrace)
                TDM_TRACE_ASYNC_BEGIN((int)private_client->stamp, "TDM_Client_Events:%u", (unsigned int)private_client->stamp);
 
@@ -461,6 +524,8 @@ tdm_client_handle_events(tdm_client *client)
        if (private_client->enable_ttrace)
                TDM_TRACE_ASYNC_END((int)private_client->stamp, "TDM_Client_Events:%u", (unsigned int)private_client->stamp);
 
+       pthread_mutex_unlock(&private_client->lock);
+
        return TDM_ERROR_NONE;
        /* LCOV_EXCL_STOP */
 }
@@ -476,11 +541,20 @@ _tdm_client_vblank_handler_temp(tdm_client_vblank *vblank, tdm_error error, unsi
                                                                unsigned int tv_sec, unsigned int tv_usec, void *user_data)
 {
        tdm_client_vblank_temp *vblank_temp = user_data;
+       tdm_private_client_vblank *private_vblank;
+       tdm_private_client *private_client;
 
        TDM_RETURN_IF_FAIL(vblank_temp != NULL);
+       TDM_RETURN_IF_FAIL(vblank != NULL);
+
+       private_vblank = vblank;
+       private_client = private_vblank->private_output->private_client;
 
-       if (vblank_temp->func)
+       if (vblank_temp->func) {
+               pthread_mutex_unlock(&private_client->lock);
                vblank_temp->func(sequence, tv_sec, tv_usec, vblank_temp->user_data);
+               pthread_mutex_lock(&private_client->lock);
+       }
 
        free(vblank_temp);
 }
@@ -541,12 +615,16 @@ tdm_client_get_output(tdm_client *client, char *name, tdm_error *error)
 
        private_client = (tdm_private_client*)client;
 
+       pthread_mutex_lock(&private_client->lock);
+
        if (!name)
                name = "primary";
 
        LIST_FOR_EACH_ENTRY(private_output, &private_client->output_list, link) {
-               if (!strncmp(private_output->name, name, TDM_NAME_LEN))
+               if (!strncmp(private_output->name, name, TDM_NAME_LEN)) {
+                       pthread_mutex_unlock(&private_client->lock);
                        return (tdm_client_output*)private_output;
+               }
        }
 
        wrapper = wl_proxy_create_wrapper(private_client->tdm);
@@ -554,6 +632,7 @@ tdm_client_get_output(tdm_client *client, char *name, tdm_error *error)
                TDM_ERR("create output_wrapper failed");
                if (error)
                        *error = TDM_ERROR_OUT_OF_MEMORY;
+               pthread_mutex_unlock(&private_client->lock);
                return NULL;
        }
 
@@ -566,6 +645,7 @@ tdm_client_get_output(tdm_client *client, char *name, tdm_error *error)
                TDM_ERR("alloc failed");
                if (error)
                        *error = TDM_ERROR_OUT_OF_MEMORY;
+               pthread_mutex_unlock(&private_client->lock);
                return NULL;
 
                /* LCOV_EXCL_STOP */
@@ -583,6 +663,7 @@ tdm_client_get_output(tdm_client *client, char *name, tdm_error *error)
                free(private_output);
                if (error)
                        *error = TDM_ERROR_OUT_OF_MEMORY;
+               pthread_mutex_unlock(&private_client->lock);
                return NULL;
 
                /* LCOV_EXCL_STOP */
@@ -598,6 +679,8 @@ tdm_client_get_output(tdm_client *client, char *name, tdm_error *error)
 
        wl_proxy_set_queue((struct wl_proxy *)private_output->output, NULL);
 
+       pthread_mutex_unlock(&private_client->lock);
+
        return (tdm_client_output*)private_output;
 }
 
@@ -607,16 +690,20 @@ tdm_client_output_add_change_handler(tdm_client_output *output,
                                                                         void *user_data)
 {
        tdm_private_client_output *private_output;
+       tdm_private_client *private_client;
        tdm_client_output_handler_info *h;
 
        TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER);
        TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER);
 
        private_output = (tdm_private_client_output*)output;
+       private_client = private_output->private_client;
 
        h = calloc(1, sizeof *h);
        TDM_RETURN_VAL_IF_FAIL(h != NULL, TDM_ERROR_OUT_OF_MEMORY);
 
+       pthread_mutex_lock(&private_client->lock);
+
        if (LIST_IS_EMPTY(&private_output->change_handler_list)) {
                wl_tdm_output_watch_output_changes(private_output->output, 1);
 
@@ -633,8 +720,11 @@ tdm_client_output_add_change_handler(tdm_client_output *output,
        h->func = func;
        h->user_data = user_data;
        LIST_ADDTAIL(&h->link, &private_output->change_handler_list);
+       LIST_INITHEAD(&h->call_link);
+
+       pthread_mutex_unlock(&private_client->lock);
 
-       return TDM_ERROR_NOT_IMPLEMENTED;
+       return TDM_ERROR_NONE;
 }
 
 void
@@ -643,12 +733,16 @@ tdm_client_output_remove_change_handler(tdm_client_output *output,
                                                                                void *user_data)
 {
        tdm_private_client_output *private_output;
+       tdm_private_client *private_client;
        tdm_client_output_handler_info *h = NULL;
 
        TDM_RETURN_IF_FAIL(output != NULL);
        TDM_RETURN_IF_FAIL(func != NULL);
 
        private_output = (tdm_private_client_output*)output;
+       private_client = private_output->private_client;
+
+       pthread_mutex_lock(&private_client->lock);
 
        LIST_FOR_EACH_ENTRY(h, &private_output->change_handler_list, link) {
                if (h->func != func || h->user_data != user_data)
@@ -660,8 +754,12 @@ tdm_client_output_remove_change_handler(tdm_client_output *output,
                if (LIST_IS_EMPTY(&private_output->change_handler_list))
                        wl_tdm_output_watch_output_changes(private_output->output, 0);
 
+               pthread_mutex_unlock(&private_client->lock);
+
                return;
        }
+
+       pthread_mutex_unlock(&private_client->lock);
 }
 
 tdm_error
@@ -674,15 +772,16 @@ tdm_client_output_get_refresh_rate(tdm_client_output *output, unsigned int *refr
        TDM_RETURN_VAL_IF_FAIL(refresh != NULL, TDM_ERROR_INVALID_PARAMETER);
 
        private_output = (tdm_private_client_output*)output;
+       private_client = private_output->private_client;
+
+       pthread_mutex_lock(&private_client->lock);
 
        if (private_output->watch_output_changes) {
                *refresh = private_output->refresh;
+               pthread_mutex_unlock(&private_client->lock);
                return TDM_ERROR_NONE;
        }
 
-       private_client = private_output->private_client;
-       TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_ERROR_INVALID_PARAMETER);
-
        wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
        wl_tdm_output_get_mode(private_output->output);
        wl_display_roundtrip_queue(private_client->display, private_client->queue);
@@ -690,6 +789,8 @@ tdm_client_output_get_refresh_rate(tdm_client_output *output, unsigned int *refr
 
        *refresh = private_output->refresh;
 
+       pthread_mutex_unlock(&private_client->lock);
+
        return TDM_ERROR_NONE;
 }
 
@@ -703,15 +804,16 @@ tdm_client_output_get_conn_status(tdm_client_output *output, tdm_output_conn_sta
        TDM_RETURN_VAL_IF_FAIL(status != NULL, TDM_ERROR_INVALID_PARAMETER);
 
        private_output = (tdm_private_client_output*)output;
+       private_client = private_output->private_client;
+
+       pthread_mutex_lock(&private_client->lock);
 
        if (private_output->watch_output_changes) {
                *status = private_output->connection;
+               pthread_mutex_unlock(&private_client->lock);
                return TDM_ERROR_NONE;
        }
 
-       private_client = private_output->private_client;
-       TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_ERROR_INVALID_PARAMETER);
-
        wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
        wl_tdm_output_get_connection(private_output->output);
        wl_display_roundtrip_queue(private_client->display, private_client->queue);
@@ -719,6 +821,8 @@ tdm_client_output_get_conn_status(tdm_client_output *output, tdm_output_conn_sta
 
        *status = private_output->connection;
 
+       pthread_mutex_unlock(&private_client->lock);
+
        return TDM_ERROR_NONE;
 }
 
@@ -732,14 +836,14 @@ tdm_client_output_get_dpms(tdm_client_output *output, tdm_output_dpms *dpms)
        TDM_RETURN_VAL_IF_FAIL(dpms != NULL, TDM_ERROR_INVALID_PARAMETER);
 
        private_output = (tdm_private_client_output*)output;
+       private_client = private_output->private_client;
 
        if (private_output->watch_output_changes) {
                *dpms = private_output->dpms;
                return TDM_ERROR_NONE;
        }
 
-       private_client = private_output->private_client;
-       TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_ERROR_INVALID_PARAMETER);
+       pthread_mutex_lock(&private_client->lock);
 
        wl_proxy_set_queue((struct wl_proxy *)private_output->output, private_client->queue);
        wl_tdm_output_get_dpms(private_output->output);
@@ -748,6 +852,8 @@ tdm_client_output_get_dpms(tdm_client_output *output, tdm_output_dpms *dpms)
 
        *dpms = private_output->dpms;
 
+       pthread_mutex_unlock(&private_client->lock);
+
        return TDM_ERROR_NONE;
 }
 
@@ -772,18 +878,14 @@ tdm_client_output_create_vblank(tdm_client_output *output, tdm_error *error)
        private_output = (tdm_private_client_output*)output;
        private_client = private_output->private_client;
 
-       if (!private_client) {
-               TDM_ERR("'!private_client' failed");
-               if (error)
-                       *error = TDM_ERROR_INVALID_PARAMETER;
-               return NULL;
-       }
+       pthread_mutex_lock(&private_client->lock);
 
        wrapper = wl_proxy_create_wrapper(private_output->output);
        if (!wrapper) {
                TDM_ERR("create output_wrapper failed");
                if (error)
                        *error = TDM_ERROR_OUT_OF_MEMORY;
+               pthread_mutex_unlock(&private_client->lock);
                return NULL;
        }
 
@@ -797,6 +899,7 @@ tdm_client_output_create_vblank(tdm_client_output *output, tdm_error *error)
                wl_proxy_wrapper_destroy(wrapper);
                if (error)
                        *error = TDM_ERROR_OUT_OF_MEMORY;
+               pthread_mutex_unlock(&private_client->lock);
                return NULL;
 
                /* LCOV_EXCL_STOP */
@@ -813,6 +916,7 @@ tdm_client_output_create_vblank(tdm_client_output *output, tdm_error *error)
                free(private_vblank);
                if (error)
                        *error = TDM_ERROR_OUT_OF_MEMORY;
+               pthread_mutex_unlock(&private_client->lock);
                return NULL;
 
                /* LCOV_EXCL_STOP */
@@ -832,6 +936,8 @@ tdm_client_output_create_vblank(tdm_client_output *output, tdm_error *error)
 
        wl_proxy_set_queue((struct wl_proxy *)private_vblank->vblank, NULL);
 
+       pthread_mutex_unlock(&private_client->lock);
+
        return (tdm_client_vblank*)private_vblank;
 }
 
@@ -839,11 +945,16 @@ void
 tdm_client_vblank_destroy(tdm_client_vblank *vblank)
 {
        tdm_private_client_vblank *private_vblank;
+       tdm_private_client *private_client;
        tdm_client_wait_info *w = NULL, *ww = NULL;
 
        TDM_RETURN_IF_FAIL(vblank != NULL);
 
        private_vblank = vblank;
+       private_client = private_vblank->private_output->private_client;
+
+       pthread_mutex_lock(&private_client->lock);
+
        LIST_DEL(&private_vblank->link);
 
        LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->wait_list, link) {
@@ -854,16 +965,22 @@ tdm_client_vblank_destroy(tdm_client_vblank *vblank)
        wl_tdm_vblank_destroy(private_vblank->vblank);
 
        free(private_vblank);
+
+       pthread_mutex_unlock(&private_client->lock);
 }
 
 tdm_error
 tdm_client_vblank_set_name(tdm_client_vblank *vblank, const char *name)
 {
        tdm_private_client_vblank *private_vblank;
+       tdm_private_client *private_client;
 
        TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
 
        private_vblank = vblank;
+       private_client = private_vblank->private_output->private_client;
+
+       pthread_mutex_lock(&private_client->lock);
 
        if (!name)
                name = TDM_VBLANK_DEFAULT_NAME;
@@ -873,6 +990,8 @@ tdm_client_vblank_set_name(tdm_client_vblank *vblank, const char *name)
 
        wl_tdm_vblank_set_name(private_vblank->vblank, private_vblank->name);
 
+       pthread_mutex_unlock(&private_client->lock);
+
        return TDM_ERROR_NONE;
 }
 
@@ -880,11 +999,16 @@ tdm_error
 tdm_client_vblank_set_sync(tdm_client_vblank *vblank, unsigned int sync)
 {
        tdm_private_client_vblank *private_vblank;
+       tdm_private_client *private_client;
 
        TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
 
        private_vblank = vblank;
+       private_client = private_vblank->private_output->private_client;
+
+       pthread_mutex_lock(&private_client->lock);
        private_vblank->sync = sync;
+       pthread_mutex_unlock(&private_client->lock);
 
        return TDM_ERROR_NONE;
 }
@@ -893,18 +1017,27 @@ tdm_error
 tdm_client_vblank_set_fps(tdm_client_vblank *vblank, unsigned int fps)
 {
        tdm_private_client_vblank *private_vblank;
+       tdm_private_client *private_client;
 
        TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
        TDM_RETURN_VAL_IF_FAIL(fps > 0, TDM_ERROR_INVALID_PARAMETER);
 
        private_vblank = vblank;
+       private_client = private_vblank->private_output->private_client;
 
-       if (private_vblank->fps == fps)
+       pthread_mutex_lock(&private_client->lock);
+
+       if (private_vblank->fps == fps) {
+               pthread_mutex_unlock(&private_client->lock);
                return TDM_ERROR_NONE;
+       }
+
        private_vblank->fps = fps;
 
        wl_tdm_vblank_set_fps(private_vblank->vblank, fps);
 
+       pthread_mutex_unlock(&private_client->lock);
+
        return TDM_ERROR_NONE;
 }
 
@@ -912,18 +1045,28 @@ tdm_error
 tdm_client_vblank_set_offset(tdm_client_vblank *vblank, int offset_ms)
 {
        tdm_private_client_vblank *private_vblank;
+       tdm_private_client *private_client;
 
        TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
 
        private_vblank = vblank;
        TDM_RETURN_VAL_IF_FAIL(private_vblank->started == 0, TDM_ERROR_BAD_REQUEST);
 
-       if (private_vblank->offset == offset_ms)
+       private_client = private_vblank->private_output->private_client;
+
+       pthread_mutex_lock(&private_client->lock);
+
+       if (private_vblank->offset == offset_ms) {
+               pthread_mutex_unlock(&private_client->lock);
                return TDM_ERROR_NONE;
+       }
+
        private_vblank->offset = offset_ms;
 
        wl_tdm_vblank_set_offset(private_vblank->vblank, offset_ms);
 
+       pthread_mutex_unlock(&private_client->lock);
+
        return TDM_ERROR_NONE;
 }
 
@@ -931,17 +1074,26 @@ tdm_error
 tdm_client_vblank_set_enable_fake(tdm_client_vblank *vblank, unsigned int enable_fake)
 {
        tdm_private_client_vblank *private_vblank;
+       tdm_private_client *private_client;
 
        TDM_RETURN_VAL_IF_FAIL(vblank != NULL, TDM_ERROR_INVALID_PARAMETER);
 
        private_vblank = vblank;
+       private_client = private_vblank->private_output->private_client;
+
+       pthread_mutex_lock(&private_client->lock);
 
-       if (private_vblank->enable_fake == enable_fake)
+       if (private_vblank->enable_fake == enable_fake) {
+               pthread_mutex_unlock(&private_client->lock);
                return TDM_ERROR_NONE;
+       }
+
        private_vblank->enable_fake = enable_fake;
 
        wl_tdm_vblank_set_enable_fake(private_vblank->vblank, enable_fake);
 
+       pthread_mutex_unlock(&private_client->lock);
+
        return TDM_ERROR_NONE;
 }
 
@@ -968,16 +1120,20 @@ tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_cli
        private_output = private_vblank->private_output;
        private_client = private_output->private_client;
 
+       pthread_mutex_lock(&private_client->lock);
+
        if (!private_vblank->started)
                private_vblank->started = 1;
 
        if (private_output->watch_output_changes && !private_vblank->enable_fake) {
                if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
                        TDM_ERR("output disconnected");
+                       pthread_mutex_unlock(&private_client->lock);
                        return TDM_ERROR_OUTPUT_DISCONNECTED;
                }
                if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->dpms)) {
                        TDM_ERR("dpms %s", tdm_dpms_str(private_output->dpms));
+                       pthread_mutex_unlock(&private_client->lock);
                        return TDM_ERROR_DPMS_OFF;
                }
        }
@@ -987,6 +1143,7 @@ tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_cli
                /* LCOV_EXCL_START */
 
                TDM_ERR("alloc failed");
+               pthread_mutex_unlock(&private_client->lock);
                return TDM_ERROR_OUT_OF_MEMORY;
 
                /* LCOV_EXCL_STOP */
@@ -997,6 +1154,7 @@ tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_cli
        w->user_data = user_data;
 
        LIST_ADDTAIL(&w->link, &private_vblank->wait_list);
+       LIST_INITHEAD(&w->call_link);
 
        clock_gettime(CLOCK_MONOTONIC, &tp);
        req_sec = (unsigned int)tp.tv_sec;
@@ -1021,6 +1179,7 @@ tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_cli
 
        if (!private_vblank->sync) {
                wl_display_flush(private_client->display);
+               pthread_mutex_unlock(&private_client->lock);
                return TDM_ERROR_NONE;
        }
 
@@ -1037,6 +1196,8 @@ tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_cli
        LIST_DEL(&w->link);
        free(w);
 
+       pthread_mutex_unlock(&private_client->lock);
+
        return TDM_ERROR_NONE;
 
        /* LCOV_EXCL_STOP */
@@ -1061,16 +1222,20 @@ tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence,
        private_output = private_vblank->private_output;
        private_client = private_output->private_client;
 
+       pthread_mutex_lock(&private_client->lock);
+
        if (!private_vblank->started)
                private_vblank->started = 1;
 
        if (private_output->watch_output_changes && !private_vblank->enable_fake) {
                if (private_output->connection == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) {
                        TDM_ERR("output disconnected");
+                       pthread_mutex_unlock(&private_client->lock);
                        return TDM_ERROR_OUTPUT_DISCONNECTED;
                }
                if (TDM_OUTPUT_DPMS_VSYNC_IS_OFF(private_output->dpms)) {
                        TDM_ERR("dpms %s", tdm_dpms_str(private_output->dpms));
+                       pthread_mutex_unlock(&private_client->lock);
                        return TDM_ERROR_DPMS_OFF;
                }
        }
@@ -1080,6 +1245,7 @@ tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence,
                /* LCOV_EXCL_START */
 
                TDM_ERR("alloc failed");
+               pthread_mutex_unlock(&private_client->lock);
                return TDM_ERROR_OUT_OF_MEMORY;
 
                /* LCOV_EXCL_STOP */
@@ -1090,6 +1256,7 @@ tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence,
        w->user_data = user_data;
 
        LIST_ADDTAIL(&w->link, &private_vblank->wait_list);
+       LIST_INITHEAD(&w->call_link);
 
        clock_gettime(CLOCK_MONOTONIC, &tp);
        req_sec = (unsigned int)tp.tv_sec;
@@ -1114,6 +1281,7 @@ tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence,
 
        if (!private_vblank->sync) {
                wl_display_flush(private_client->display);
+               pthread_mutex_unlock(&private_client->lock);
                return TDM_ERROR_NONE;
        }
 
@@ -1130,6 +1298,8 @@ tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence,
        LIST_DEL(&w->link);
        free(w);
 
+       pthread_mutex_unlock(&private_client->lock);
+
        return TDM_ERROR_NONE;
 
        /* LCOV_EXCL_STOP */