gtk3/use-memfd.patch

791 lines
23 KiB
Diff
Raw Normal View History

From 31e75c3e5c4f59b603602420d2708588091a07b2 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 20 Jan 2016 12:22:29 -0500
Subject: [PATCH 1/6] wayland: unlink shm file earlier in create function
create_shm_pool unlinks the temporary file a little,
too late. It should be unlinked before ftruncate()
is called for two reasons:
1) if ftruncate fails, the file is currently not
getting cleaned up at all
2) in theory, if the file is public some other process
could muck with it
This commit just moves the unlink call a little higher
up.
https://bugzilla.gnome.org/show_bug.cgi?id=760897
---
gdk/wayland/gdkdisplay-wayland.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c
index 97eebca..2f0c64e 100644
--- a/gdk/wayland/gdkdisplay-wayland.c
+++ b/gdk/wayland/gdkdisplay-wayland.c
@@ -914,73 +914,73 @@ buffer_release_callback (void *_data,
cairo_surface_t *surface = _data;
GdkWaylandCairoSurfaceData *data = cairo_surface_get_user_data (surface, &gdk_wayland_cairo_key);
data->busy = FALSE;
cairo_surface_destroy (surface);
}
static const struct wl_buffer_listener buffer_listener = {
buffer_release_callback
};
static struct wl_shm_pool *
create_shm_pool (struct wl_shm *shm,
int width,
int height,
size_t *buf_length,
void **data_out)
{
char filename[] = "/tmp/wayland-shm-XXXXXX";
struct wl_shm_pool *pool;
int fd, size, stride;
void *data;
fd = mkstemp (filename);
if (fd < 0)
{
g_critical (G_STRLOC ": Unable to create temporary file (%s): %s",
filename, g_strerror (errno));
return NULL;
}
+ unlink (filename);
stride = width * 4;
size = stride * height;
if (ftruncate (fd, size) < 0)
{
g_critical (G_STRLOC ": Truncating temporary file failed: %s",
g_strerror (errno));
close (fd);
return NULL;
}
data = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
- unlink (filename);
if (data == MAP_FAILED)
{
g_critical (G_STRLOC ": mmap'ping temporary file failed: %s",
g_strerror (errno));
close (fd);
return NULL;
}
pool = wl_shm_create_pool (shm, fd, size);
close (fd);
*data_out = data;
*buf_length = size;
return pool;
}
static void
gdk_wayland_cairo_surface_destroy (void *p)
{
GdkWaylandCairoSurfaceData *data = p;
if (data->buffer)
wl_buffer_destroy (data->buffer);
if (data->pool)
wl_shm_pool_destroy (data->pool);
--
2.7.0
From 743f5ef21afe0c00aa572d49d197658aa9613a01 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 20 Jan 2016 11:40:34 -0500
Subject: [PATCH 2/6] wayland: clean up stride calculation when creating shm
surface
Right now, we assume the stride for the image surface needs to
be 4 byte aligned. This is, in fact, true, but it's better to
ask cairo for the alignment requirement directly rather than
assume we know the alignment rules.
This commit changes the code to use cairo_format_stride_for_width
to calculate a suitable rowstride for pixman.
https://bugzilla.gnome.org/show_bug.cgi?id=760897
---
gdk/wayland/gdkdisplay-wayland.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c
index 2f0c64e..bf3c20c 100644
--- a/gdk/wayland/gdkdisplay-wayland.c
+++ b/gdk/wayland/gdkdisplay-wayland.c
@@ -978,76 +978,76 @@ gdk_wayland_cairo_surface_destroy (void *p)
{
GdkWaylandCairoSurfaceData *data = p;
if (data->buffer)
wl_buffer_destroy (data->buffer);
if (data->pool)
wl_shm_pool_destroy (data->pool);
munmap (data->buf, data->buf_length);
g_free (data);
}
cairo_surface_t *
_gdk_wayland_display_create_shm_surface (GdkWaylandDisplay *display,
int width,
int height,
guint scale)
{
GdkWaylandCairoSurfaceData *data;
cairo_surface_t *surface = NULL;
cairo_status_t status;
int stride;
data = g_new (GdkWaylandCairoSurfaceData, 1);
data->display = display;
data->buffer = NULL;
data->scale = scale;
data->busy = FALSE;
- stride = width * 4;
+ stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, width*scale);
data->pool = create_shm_pool (display->shm,
width*scale, height*scale,
&data->buf_length,
&data->buf);
surface = cairo_image_surface_create_for_data (data->buf,
CAIRO_FORMAT_ARGB32,
width*scale,
height*scale,
- stride*scale);
+ stride);
data->buffer = wl_shm_pool_create_buffer (data->pool, 0,
width*scale, height*scale,
- stride*scale, WL_SHM_FORMAT_ARGB8888);
+ stride, WL_SHM_FORMAT_ARGB8888);
wl_buffer_add_listener (data->buffer, &buffer_listener, surface);
cairo_surface_set_user_data (surface, &gdk_wayland_cairo_key,
data, gdk_wayland_cairo_surface_destroy);
cairo_surface_set_device_scale (surface, scale, scale);
status = cairo_surface_status (surface);
if (status != CAIRO_STATUS_SUCCESS)
{
g_critical (G_STRLOC ": Unable to create Cairo image surface: %s",
cairo_status_to_string (status));
}
return surface;
}
struct wl_buffer *
_gdk_wayland_shm_surface_get_wl_buffer (cairo_surface_t *surface)
{
GdkWaylandCairoSurfaceData *data = cairo_surface_get_user_data (surface, &gdk_wayland_cairo_key);
return data->buffer;
}
void
_gdk_wayland_shm_surface_set_busy (cairo_surface_t *surface)
{
GdkWaylandCairoSurfaceData *data = cairo_surface_get_user_data (surface, &gdk_wayland_cairo_key);
data->busy = TRUE;
cairo_surface_reference (surface);
--
2.7.0
From 2e704d3c0f7daaf38701d341186178c2adc442d1 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 20 Jan 2016 12:35:44 -0500
Subject: [PATCH 3/6] wayland: don't pass in width and height to
create_shm_pool
create_shm_pool doesn't need the width or height, it just needs
the total size. By passing it in, we're requiring it to redo
stride calculation unnecessarily.
This commit drops the width and height parameters and makes the
function just take the total size directly.
https://bugzilla.gnome.org/show_bug.cgi?id=760897
---
gdk/wayland/gdkdisplay-wayland.c | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c
index bf3c20c..7c19a5c 100644
--- a/gdk/wayland/gdkdisplay-wayland.c
+++ b/gdk/wayland/gdkdisplay-wayland.c
@@ -897,81 +897,78 @@ gdk_wayland_display_get_xdg_shell (GdkDisplay *display)
static const cairo_user_data_key_t gdk_wayland_cairo_key;
typedef struct _GdkWaylandCairoSurfaceData {
gpointer buf;
size_t buf_length;
struct wl_shm_pool *pool;
struct wl_buffer *buffer;
GdkWaylandDisplay *display;
uint32_t scale;
gboolean busy;
} GdkWaylandCairoSurfaceData;
static void
buffer_release_callback (void *_data,
struct wl_buffer *wl_buffer)
{
cairo_surface_t *surface = _data;
GdkWaylandCairoSurfaceData *data = cairo_surface_get_user_data (surface, &gdk_wayland_cairo_key);
data->busy = FALSE;
cairo_surface_destroy (surface);
}
static const struct wl_buffer_listener buffer_listener = {
buffer_release_callback
};
static struct wl_shm_pool *
create_shm_pool (struct wl_shm *shm,
- int width,
- int height,
+ int size,
size_t *buf_length,
void **data_out)
{
char filename[] = "/tmp/wayland-shm-XXXXXX";
struct wl_shm_pool *pool;
- int fd, size, stride;
+ int fd;
void *data;
fd = mkstemp (filename);
if (fd < 0)
{
g_critical (G_STRLOC ": Unable to create temporary file (%s): %s",
filename, g_strerror (errno));
return NULL;
}
unlink (filename);
- stride = width * 4;
- size = stride * height;
if (ftruncate (fd, size) < 0)
{
g_critical (G_STRLOC ": Truncating temporary file failed: %s",
g_strerror (errno));
close (fd);
return NULL;
}
data = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED)
{
g_critical (G_STRLOC ": mmap'ping temporary file failed: %s",
g_strerror (errno));
close (fd);
return NULL;
}
pool = wl_shm_create_pool (shm, fd, size);
close (fd);
*data_out = data;
*buf_length = size;
return pool;
}
static void
gdk_wayland_cairo_surface_destroy (void *p)
@@ -981,61 +978,61 @@ gdk_wayland_cairo_surface_destroy (void *p)
if (data->buffer)
wl_buffer_destroy (data->buffer);
if (data->pool)
wl_shm_pool_destroy (data->pool);
munmap (data->buf, data->buf_length);
g_free (data);
}
cairo_surface_t *
_gdk_wayland_display_create_shm_surface (GdkWaylandDisplay *display,
int width,
int height,
guint scale)
{
GdkWaylandCairoSurfaceData *data;
cairo_surface_t *surface = NULL;
cairo_status_t status;
int stride;
data = g_new (GdkWaylandCairoSurfaceData, 1);
data->display = display;
data->buffer = NULL;
data->scale = scale;
data->busy = FALSE;
stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, width*scale);
data->pool = create_shm_pool (display->shm,
- width*scale, height*scale,
+ height*scale*stride,
&data->buf_length,
&data->buf);
surface = cairo_image_surface_create_for_data (data->buf,
CAIRO_FORMAT_ARGB32,
width*scale,
height*scale,
stride);
data->buffer = wl_shm_pool_create_buffer (data->pool, 0,
width*scale, height*scale,
stride, WL_SHM_FORMAT_ARGB8888);
wl_buffer_add_listener (data->buffer, &buffer_listener, surface);
cairo_surface_set_user_data (surface, &gdk_wayland_cairo_key,
data, gdk_wayland_cairo_surface_destroy);
cairo_surface_set_device_scale (surface, scale, scale);
status = cairo_surface_status (surface);
if (status != CAIRO_STATUS_SUCCESS)
{
g_critical (G_STRLOC ": Unable to create Cairo image surface: %s",
cairo_status_to_string (status));
}
return surface;
}
struct wl_buffer *
--
2.7.0
From 8717b4221f634e321aee80bc8accb60b6a24552d Mon Sep 17 00:00:00 2001
From: Matthias Clasen <mclasen@redhat.com>
Date: Thu, 21 Jan 2016 22:53:06 -0500
Subject: [PATCH 4/6] wayland: Don't hardcode /tmp
As pointed out in https://bugzilla.gnome.org/show_bug.cgi?id=760964,
we should use the GLib facilities for determining the preferred
location for temporary files.
---
gdk/wayland/gdkdisplay-wayland.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c
index 7c19a5c..5e88d96 100644
--- a/gdk/wayland/gdkdisplay-wayland.c
+++ b/gdk/wayland/gdkdisplay-wayland.c
@@ -901,95 +901,100 @@ typedef struct _GdkWaylandCairoSurfaceData {
gpointer buf;
size_t buf_length;
struct wl_shm_pool *pool;
struct wl_buffer *buffer;
GdkWaylandDisplay *display;
uint32_t scale;
gboolean busy;
} GdkWaylandCairoSurfaceData;
static void
buffer_release_callback (void *_data,
struct wl_buffer *wl_buffer)
{
cairo_surface_t *surface = _data;
GdkWaylandCairoSurfaceData *data = cairo_surface_get_user_data (surface, &gdk_wayland_cairo_key);
data->busy = FALSE;
cairo_surface_destroy (surface);
}
static const struct wl_buffer_listener buffer_listener = {
buffer_release_callback
};
static struct wl_shm_pool *
create_shm_pool (struct wl_shm *shm,
int size,
size_t *buf_length,
void **data_out)
{
- char filename[] = "/tmp/wayland-shm-XXXXXX";
+ char *filename;
struct wl_shm_pool *pool;
int fd;
void *data;
+ filename = g_strconcat (g_get_tmp_dir (), G_DIR_SEPARATOR_S, "wayland-shm-XXXXXX", NULL);
fd = mkstemp (filename);
if (fd < 0)
{
g_critical (G_STRLOC ": Unable to create temporary file (%s): %s",
filename, g_strerror (errno));
+ g_free (filename);
return NULL;
}
unlink (filename);
if (ftruncate (fd, size) < 0)
{
- g_critical (G_STRLOC ": Truncating temporary file failed: %s",
- g_strerror (errno));
+ g_critical (G_STRLOC ": Truncating temporary file (%s) failed: %s",
+ filename, g_strerror (errno));
+ g_free (filename);
close (fd);
return NULL;
}
data = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED)
{
- g_critical (G_STRLOC ": mmap'ping temporary file failed: %s",
- g_strerror (errno));
+ g_critical (G_STRLOC ": mmap'ping temporary file (%s) failed: %s",
+ filename, g_strerror (errno));
+ g_free (filename);
close (fd);
return NULL;
}
pool = wl_shm_create_pool (shm, fd, size);
close (fd);
+ g_free (filename);
*data_out = data;
*buf_length = size;
return pool;
}
static void
gdk_wayland_cairo_surface_destroy (void *p)
{
GdkWaylandCairoSurfaceData *data = p;
if (data->buffer)
wl_buffer_destroy (data->buffer);
if (data->pool)
wl_shm_pool_destroy (data->pool);
munmap (data->buf, data->buf_length);
g_free (data);
}
cairo_surface_t *
_gdk_wayland_display_create_shm_surface (GdkWaylandDisplay *display,
int width,
int height,
guint scale)
{
GdkWaylandCairoSurfaceData *data;
cairo_surface_t *surface = NULL;
--
2.7.0
From e9ba1539160378dbf484e5760c1e54ca0415f939 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Mon, 25 Jan 2016 11:41:23 -0500
Subject: [PATCH 5/6] wayland: use memfd_create instead of open in tmpdir
The tmpdir is used for a wide assortment of things, and
can easily fill up. If it fills then desktop will start
crashing with SIGBUS errors.
This commit changes the shm pool allocation code, to use
memfd_create, instead, so the shared memory files will
be anonymous and not associated with /tmp
https://bugzilla.gnome.org/show_bug.cgi?id=761095
---
gdk/wayland/gdkdisplay-wayland.c | 28 ++++++++++++----------------
1 file changed, 12 insertions(+), 16 deletions(-)
diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c
index 5e88d96..360c489 100644
--- a/gdk/wayland/gdkdisplay-wayland.c
+++ b/gdk/wayland/gdkdisplay-wayland.c
@@ -1,55 +1,57 @@
/*
* Copyright © 2010 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
+#include <linux/memfd.h>
#include <sys/mman.h>
+#include <sys/syscall.h>
#include <glib.h>
#include "gdkwayland.h"
#include "gdkdisplay.h"
#include "gdkdisplay-wayland.h"
#include "gdkscreen.h"
#include "gdkinternals.h"
#include "gdkdeviceprivate.h"
#include "gdkdevicemanager.h"
#include "gdkkeysprivate.h"
#include "gdkprivate-wayland.h"
#include "gdkglcontext-wayland.h"
#include "pointer-gestures-unstable-v1-client-protocol.h"
/**
* SECTION:wayland_interaction
* @Short_description: Wayland backend-specific functions
* @Title: Wayland Interaction
*
* The functions in this section are specific to the GDK Wayland backend.
* To use them, you need to include the `<gdk/gdkwayland.h>` header and use
* the Wayland-specific pkg-config files to build your application (either
* `gdk-wayland-3.0` or `gtk+-wayland-3.0`).
*
* To make your code compile with other GDK backends, guard backend-specific
* calls by an ifdef as follows. Since GDK may be built with multiple
* backends, you should also check for the backend that is in use (e.g. by
* using the GDK_IS_WAYLAND_DISPLAY() macro).
* |[<!-- language="C" -->
* #ifdef GDK_WINDOWING_WAYLAND
@@ -901,100 +903,94 @@ typedef struct _GdkWaylandCairoSurfaceData {
gpointer buf;
size_t buf_length;
struct wl_shm_pool *pool;
struct wl_buffer *buffer;
GdkWaylandDisplay *display;
uint32_t scale;
gboolean busy;
} GdkWaylandCairoSurfaceData;
static void
buffer_release_callback (void *_data,
struct wl_buffer *wl_buffer)
{
cairo_surface_t *surface = _data;
GdkWaylandCairoSurfaceData *data = cairo_surface_get_user_data (surface, &gdk_wayland_cairo_key);
data->busy = FALSE;
cairo_surface_destroy (surface);
}
static const struct wl_buffer_listener buffer_listener = {
buffer_release_callback
};
static struct wl_shm_pool *
create_shm_pool (struct wl_shm *shm,
int size,
size_t *buf_length,
void **data_out)
{
- char *filename;
struct wl_shm_pool *pool;
- int fd;
+ int ret, fd;
void *data;
- filename = g_strconcat (g_get_tmp_dir (), G_DIR_SEPARATOR_S, "wayland-shm-XXXXXX", NULL);
- fd = mkstemp (filename);
- if (fd < 0)
+ ret = syscall (SYS_memfd_create, "gdk-wayland", MFD_CLOEXEC);
+
+ if (ret < 0)
{
- g_critical (G_STRLOC ": Unable to create temporary file (%s): %s",
- filename, g_strerror (errno));
- g_free (filename);
+ g_critical (G_STRLOC ": creating shared memory file failed: %s",
+ g_strerror (-ret));
return NULL;
}
- unlink (filename);
+
+ fd = ret;
if (ftruncate (fd, size) < 0)
{
- g_critical (G_STRLOC ": Truncating temporary file (%s) failed: %s",
- filename, g_strerror (errno));
- g_free (filename);
+ g_critical (G_STRLOC ": Truncating shared memory file failed: %m");
close (fd);
return NULL;
}
data = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED)
{
- g_critical (G_STRLOC ": mmap'ping temporary file (%s) failed: %s",
- filename, g_strerror (errno));
- g_free (filename);
+ g_critical (G_STRLOC ": mmap'ping shared memory file failed: %m");
close (fd);
return NULL;
}
pool = wl_shm_create_pool (shm, fd, size);
close (fd);
- g_free (filename);
*data_out = data;
*buf_length = size;
return pool;
}
static void
gdk_wayland_cairo_surface_destroy (void *p)
{
GdkWaylandCairoSurfaceData *data = p;
if (data->buffer)
wl_buffer_destroy (data->buffer);
if (data->pool)
wl_shm_pool_destroy (data->pool);
munmap (data->buf, data->buf_length);
g_free (data);
}
cairo_surface_t *
_gdk_wayland_display_create_shm_surface (GdkWaylandDisplay *display,
int width,
int height,
guint scale)
{
GdkWaylandCairoSurfaceData *data;
cairo_surface_t *surface = NULL;
--
2.7.0
From ba8ce203ed2f1723b7f332fba1efb28f96f0a1c4 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Mon, 25 Jan 2016 13:55:25 -0500
Subject: [PATCH 6/6] wayland: __NR_memfd_create instead of SYS_memfd_create
It looks like the gnome-continuous headers haven't quite
caught up yet, so try __NR_memfd_create instead.
If that doesn't work, i'll likely just add in a fallback
code path.
---
gdk/wayland/gdkdisplay-wayland.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c
index 360c489..f200800 100644
--- a/gdk/wayland/gdkdisplay-wayland.c
+++ b/gdk/wayland/gdkdisplay-wayland.c
@@ -907,61 +907,61 @@ typedef struct _GdkWaylandCairoSurfaceData {
GdkWaylandDisplay *display;
uint32_t scale;
gboolean busy;
} GdkWaylandCairoSurfaceData;
static void
buffer_release_callback (void *_data,
struct wl_buffer *wl_buffer)
{
cairo_surface_t *surface = _data;
GdkWaylandCairoSurfaceData *data = cairo_surface_get_user_data (surface, &gdk_wayland_cairo_key);
data->busy = FALSE;
cairo_surface_destroy (surface);
}
static const struct wl_buffer_listener buffer_listener = {
buffer_release_callback
};
static struct wl_shm_pool *
create_shm_pool (struct wl_shm *shm,
int size,
size_t *buf_length,
void **data_out)
{
struct wl_shm_pool *pool;
int ret, fd;
void *data;
- ret = syscall (SYS_memfd_create, "gdk-wayland", MFD_CLOEXEC);
+ ret = syscall (__NR_memfd_create, "gdk-wayland", MFD_CLOEXEC);
if (ret < 0)
{
g_critical (G_STRLOC ": creating shared memory file failed: %s",
g_strerror (-ret));
return NULL;
}
fd = ret;
if (ftruncate (fd, size) < 0)
{
g_critical (G_STRLOC ": Truncating shared memory file failed: %m");
close (fd);
return NULL;
}
data = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED)
{
g_critical (G_STRLOC ": mmap'ping shared memory file failed: %m");
close (fd);
return NULL;
}
pool = wl_shm_create_pool (shm, fd, size);
close (fd);
--
2.7.0