[PATCH wayland 2/2] shm: Defer wl_shm_pool_resize if a pool has external references

Bryce Harrington bryce at osg.samsung.com
Sat Feb 20 03:10:06 UTC 2016


On Tue, Feb 09, 2016 at 04:03:48PM -0600, Derek Foreman wrote:
> If a compositor is rendering in one thread while dispatching wayland
> events in another, a wl_shm_pool_resize() could change the memory
> mappings it's rendering from and cause a crash.
> 
> Now we defer wl_shm_pool_resize() if the compositor has references on a
> pool, and perform the actual resize when it drops those references.
> 
> Signed-off-by: Derek Foreman <derekf at osg.samsung.com>

Reviewed-by: Bryce Harrington <bryce at osg.samsung.com>

> ---
>  src/wayland-shm.c | 47 +++++++++++++++++++++++++++++++++++------------
>  1 file changed, 35 insertions(+), 12 deletions(-)
> 
> diff --git a/src/wayland-shm.c b/src/wayland-shm.c
> index 6fbf34b..6351259 100644
> --- a/src/wayland-shm.c
> +++ b/src/wayland-shm.c
> @@ -56,6 +56,7 @@ struct wl_shm_pool {
>  	int external_refcount;
>  	char *data;
>  	int32_t size;
> +	int32_t new_size;
>  };
>  
>  struct wl_shm_buffer {
> @@ -74,12 +75,35 @@ struct wl_shm_sigbus_data {
>  };
>  
>  static void
> +shm_pool_finish_resize(struct wl_shm_pool *pool)
> +{
> +	void *data;
> +
> +	if (pool->size == pool->new_size)
> +		return;
> +
> +	data = mremap(pool->data, pool->size, pool->new_size, MREMAP_MAYMOVE);
> +	if (data == MAP_FAILED) {
> +		wl_resource_post_error(pool->resource,
> +				       WL_SHM_ERROR_INVALID_FD,
> +				       "failed mremap");
> +		return;
> +	}
> +
> +	pool->data = data;
> +	pool->size = pool->new_size;
> +}
> +
> +static void
>  shm_pool_unref(struct wl_shm_pool *pool, bool external)
>  {
> -	if (external)
> +	if (external) {
>  		pool->external_refcount--;
> -	else
> +		if (pool->external_refcount == 0)
> +			shm_pool_finish_resize(pool);
> +	} else {
>  		pool->internal_refcount--;
> +	}
>  
>  	if (pool->internal_refcount + pool->external_refcount)
>  		return;
> @@ -202,7 +226,6 @@ shm_pool_resize(struct wl_client *client, struct wl_resource *resource,
>  		int32_t size)
>  {
>  	struct wl_shm_pool *pool = wl_resource_get_user_data(resource);
> -	void *data;
>  
>  	if (size < pool->size) {
>  		wl_resource_post_error(resource,
> @@ -211,16 +234,15 @@ shm_pool_resize(struct wl_client *client, struct wl_resource *resource,
>  		return;
>  	}
>  
> -	data = mremap(pool->data, pool->size, size, MREMAP_MAYMOVE);
> -	if (data == MAP_FAILED) {
> -		wl_resource_post_error(resource,
> -				       WL_SHM_ERROR_INVALID_FD,
> -				       "failed mremap");
> -		return;
> -	}
> +	pool->new_size = size;
>  
> -	pool->data = data;
> -	pool->size = size;
> +	/* If the compositor has taken references on this pool it
> +	 * may be caching pointers into it. In that case we
> +	 * defer the resize (which may move the entire mapping)
> +	 * until the compositor finishes dereferencing the pool.
> +	 */
> +	if (pool->external_refcount == 0)
> +		shm_pool_finish_resize(pool);
>  }
>  
>  struct wl_shm_pool_interface shm_pool_interface = {
> @@ -251,6 +273,7 @@ shm_create_pool(struct wl_client *client, struct wl_resource *resource,
>  	pool->internal_refcount = 1;
>  	pool->external_refcount = 0;
>  	pool->size = size;
> +	pool->new_size = size;
>  	pool->data = mmap(NULL, size,
>  			  PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
>  	if (pool->data == MAP_FAILED) {
> -- 
> 2.7.0
> 
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/wayland-devel


More information about the wayland-devel mailing list