diff --git a/src/common/common/cursor.h b/src/common/common/cursor.h index 52d93c2ae8..9b0c08788c 100644 --- a/src/common/common/cursor.h +++ b/src/common/common/cursor.h @@ -123,6 +123,14 @@ typedef struct guac_common_cursor { */ guac_timestamp timestamp; + /** + * Lock which restricts simultaneous access to the cursor, guaranteeing + * ordered modifications to the cursor and that incompatible operations + * do not occur simultaneously. This lock is for internal use within the + * cursor only. + */ + pthread_mutex_t lock; + } guac_common_cursor; /** diff --git a/src/common/cursor.c b/src/common/cursor.c index b70134d81e..0f2b1364b8 100644 --- a/src/common/cursor.c +++ b/src/common/cursor.c @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -74,12 +75,16 @@ guac_common_cursor* guac_common_cursor_alloc(guac_client* client) { cursor->x = 0; cursor->y = 0; + pthread_mutex_init(&(cursor->lock), NULL); + return cursor; } void guac_common_cursor_free(guac_common_cursor* cursor) { + pthread_mutex_destroy(&(cursor->lock)); + guac_client* client = cursor->client; guac_layer* buffer = cursor->buffer; cairo_surface_t* surface = cursor->surface; @@ -102,6 +107,8 @@ void guac_common_cursor_free(guac_common_cursor* cursor) { void guac_common_cursor_dup(guac_common_cursor* cursor, guac_user* user, guac_socket* socket) { + pthread_mutex_lock(&(cursor->lock)); + /* Synchronize location */ guac_protocol_send_mouse(socket, cursor->x, cursor->y, cursor->button_mask, cursor->timestamp); @@ -119,6 +126,8 @@ void guac_common_cursor_dup(guac_common_cursor* cursor, guac_user* user, cursor->buffer, 0, 0, cursor->width, cursor->height); } + pthread_mutex_unlock(&(cursor->lock)); + guac_socket_flush(socket); } @@ -154,6 +163,8 @@ static void* guac_common_cursor_broadcast_state(guac_user* user, void guac_common_cursor_update(guac_common_cursor* cursor, guac_user* user, int x, int y, int button_mask) { + pthread_mutex_lock(&(cursor->lock)); + /* Update current user of cursor */ cursor->user = user; @@ -169,6 +180,8 @@ void guac_common_cursor_update(guac_common_cursor* cursor, guac_user* user, guac_client_foreach_user(cursor->client, guac_common_cursor_broadcast_state, cursor); + pthread_mutex_unlock(&(cursor->lock)); + } /** @@ -212,6 +225,8 @@ static void guac_common_cursor_resize(guac_common_cursor* cursor, void guac_common_cursor_set_argb(guac_common_cursor* cursor, int hx, int hy, unsigned const char* data, int width, int height, int stride) { + pthread_mutex_lock(&(cursor->lock)); + /* Copy image data */ guac_common_cursor_resize(cursor, width, height, stride); memcpy(cursor->image_buffer, data, height * stride); @@ -242,6 +257,8 @@ void guac_common_cursor_set_argb(guac_common_cursor* cursor, int hx, int hy, guac_socket_flush(cursor->client->socket); + pthread_mutex_unlock(&(cursor->lock)); + } void guac_common_cursor_set_surface(guac_common_cursor* cursor, int hx, int hy, @@ -298,9 +315,13 @@ void guac_common_cursor_set_blank(guac_common_cursor* cursor) { void guac_common_cursor_remove_user(guac_common_cursor* cursor, guac_user* user) { + pthread_mutex_lock(&(cursor->lock)); + /* Disassociate from given user */ if (cursor->user == user) cursor->user = NULL; + pthread_mutex_unlock(&(cursor->lock)); + }