mirror of
https://github.com/brl/mutter.git
synced 2024-11-21 23:50:41 -05:00
native: Add device pool for tracking device file descriptors
This practically does the same thing as part of MetaLauncher, except with added thread safety and caching. For example, opening the same file a second time will return the same MetaDeviceFile, and only once all acquired MetaDeviceFile's are released, will the file descriptor be closed and control of the device released. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1828>
This commit is contained in:
parent
44af2c0d37
commit
ee8c252a8c
@ -25,8 +25,11 @@
|
||||
#ifndef META_BACKEND_NATIVE_PRIVATE_H
|
||||
#define META_BACKEND_NATIVE_PRIVATE_H
|
||||
|
||||
#include "backends/native/meta-backend-native.h"
|
||||
#include "backends/native/meta-barrier-native.h"
|
||||
|
||||
MetaBarrierManagerNative *meta_backend_native_get_barrier_manager (MetaBackendNative *native);
|
||||
|
||||
MetaDevicePool * meta_backend_native_get_device_pool (MetaBackendNative *native);
|
||||
|
||||
#endif /* META_BACKEND_NATIVE_PRIVATE_H */
|
||||
|
@ -29,6 +29,7 @@ typedef struct _MetaRendererNative MetaRendererNative;
|
||||
typedef struct _MetaGpuKms MetaGpuKms;
|
||||
typedef struct _MetaCrtcVirtual MetaCrtcVirtual;
|
||||
typedef struct _MetaCrtcModeVirtual MetaCrtcModeVirtual;
|
||||
typedef struct _MetaDevicePool MetaDevicePool;
|
||||
|
||||
typedef enum _MetaSeatNativeFlag
|
||||
{
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include "backends/meta-settings-private.h"
|
||||
#include "backends/meta-stage-private.h"
|
||||
#include "backends/native/meta-clutter-backend-native.h"
|
||||
#include "backends/native/meta-device-pool-private.h"
|
||||
#include "backends/native/meta-kms.h"
|
||||
#include "backends/native/meta-kms-device.h"
|
||||
#include "backends/native/meta-launcher.h"
|
||||
@ -81,6 +82,7 @@ struct _MetaBackendNative
|
||||
MetaBackend parent;
|
||||
|
||||
MetaLauncher *launcher;
|
||||
MetaDevicePool *device_pool;
|
||||
MetaUdev *udev;
|
||||
MetaKms *kms;
|
||||
|
||||
@ -119,6 +121,7 @@ meta_backend_native_dispose (GObject *object)
|
||||
|
||||
g_clear_object (&native->kms);
|
||||
g_clear_object (&native->udev);
|
||||
g_clear_object (&native->device_pool);
|
||||
g_clear_pointer (&native->launcher, meta_launcher_free);
|
||||
}
|
||||
|
||||
@ -574,6 +577,8 @@ meta_backend_native_initable_init (GInitable *initable,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
native->device_pool = meta_device_pool_new (native->launcher);
|
||||
|
||||
#ifdef HAVE_WAYLAND
|
||||
meta_backend_init_wayland_display (META_BACKEND (native));
|
||||
#endif
|
||||
@ -672,6 +677,12 @@ meta_backend_native_get_launcher (MetaBackendNative *native)
|
||||
return native->launcher;
|
||||
}
|
||||
|
||||
MetaDevicePool *
|
||||
meta_backend_native_get_device_pool (MetaBackendNative *native)
|
||||
{
|
||||
return native->device_pool;
|
||||
}
|
||||
|
||||
MetaUdev *
|
||||
meta_backend_native_get_udev (MetaBackendNative *native)
|
||||
{
|
||||
|
35
src/backends/native/meta-device-pool-private.h
Normal file
35
src/backends/native/meta-device-pool-private.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef META_DEVICE_POOL_PRIVATE_H
|
||||
#define META_DEVICE_POOL_PRIVATE_H
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "backends/native/meta-device-pool.h"
|
||||
#include "backends/native/meta-launcher.h"
|
||||
|
||||
#define META_TYPE_DEVICE_POOL (meta_device_pool_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (MetaDevicePool, meta_device_pool,
|
||||
META, DEVICE_POOL,
|
||||
GObject)
|
||||
|
||||
MetaDevicePool * meta_device_pool_new (MetaLauncher *launcher);
|
||||
|
||||
#endif /* META_DEVICE_POOL_PRIVATE_H */
|
338
src/backends/native/meta-device-pool.c
Normal file
338
src/backends/native/meta-device-pool.c
Normal file
@ -0,0 +1,338 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2021 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "backends/native/meta-device-pool-private.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <gio/gunixfdlist.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "backends/native/meta-launcher.h"
|
||||
|
||||
#include "meta-dbus-login1.h"
|
||||
|
||||
struct _MetaDeviceFile
|
||||
{
|
||||
MetaDevicePool *pool;
|
||||
|
||||
grefcount ref_count;
|
||||
|
||||
char *path;
|
||||
int major;
|
||||
int minor;
|
||||
int fd;
|
||||
MetaDeviceFileFlags flags;
|
||||
};
|
||||
|
||||
struct _MetaDevicePool
|
||||
{
|
||||
GObject parent;
|
||||
|
||||
MetaDbusLogin1Session *session_proxy;
|
||||
|
||||
GMutex mutex;
|
||||
|
||||
GList *files;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (MetaDevicePool, meta_device_pool, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
release_device_file (MetaDevicePool *pool,
|
||||
MetaDeviceFile *file);
|
||||
|
||||
static MetaDeviceFile *
|
||||
meta_device_file_new (MetaDevicePool *pool,
|
||||
const char *path,
|
||||
int major,
|
||||
int minor,
|
||||
int fd,
|
||||
MetaDeviceFileFlags flags)
|
||||
{
|
||||
MetaDeviceFile *file;
|
||||
|
||||
file = g_new0 (MetaDeviceFile, 1);
|
||||
|
||||
file->pool = pool;
|
||||
g_ref_count_init (&file->ref_count);
|
||||
|
||||
file->path = g_strdup (path);
|
||||
file->major = major;
|
||||
file->minor = minor;
|
||||
file->fd = fd;
|
||||
file->flags = flags;
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_device_file_free (MetaDeviceFile *file)
|
||||
{
|
||||
g_free (file->path);
|
||||
g_free (file);
|
||||
}
|
||||
|
||||
int
|
||||
meta_device_file_get_fd (MetaDeviceFile *device_file)
|
||||
{
|
||||
g_assert (!g_ref_count_compare (&device_file->ref_count, 0));
|
||||
|
||||
return device_file->fd;
|
||||
}
|
||||
|
||||
const char *
|
||||
meta_device_file_get_path (MetaDeviceFile *device_file)
|
||||
{
|
||||
return device_file->path;
|
||||
}
|
||||
|
||||
static MetaDeviceFile *
|
||||
meta_device_file_acquire_locked (MetaDeviceFile *file)
|
||||
{
|
||||
g_ref_count_inc (&file->ref_count);
|
||||
return file;
|
||||
}
|
||||
|
||||
MetaDeviceFile *
|
||||
meta_device_file_acquire (MetaDeviceFile *file)
|
||||
{
|
||||
g_mutex_lock (&file->pool->mutex);
|
||||
meta_device_file_acquire_locked (file);
|
||||
g_mutex_unlock (&file->pool->mutex);
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
void
|
||||
meta_device_file_release (MetaDeviceFile *file)
|
||||
{
|
||||
g_warn_if_fail (file->fd != -1);
|
||||
|
||||
release_device_file (file->pool, file);
|
||||
}
|
||||
|
||||
MetaDevicePool *
|
||||
meta_device_file_get_pool (MetaDeviceFile *device_file)
|
||||
{
|
||||
return device_file->pool;
|
||||
}
|
||||
|
||||
static MetaDeviceFile *
|
||||
find_device_file_from_path (MetaDevicePool *pool,
|
||||
const char *path)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = pool->files; l; l = l->next)
|
||||
{
|
||||
MetaDeviceFile *file = l->data;
|
||||
|
||||
if (g_strcmp0 (file->path, path) == 0)
|
||||
return file;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
take_device (MetaDbusLogin1Session *session_proxy,
|
||||
int dev_major,
|
||||
int dev_minor,
|
||||
int *out_fd,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr (GVariant) fd_variant = NULL;
|
||||
g_autoptr (GUnixFDList) fd_list = NULL;
|
||||
int fd = -1;
|
||||
|
||||
if (!meta_dbus_login1_session_call_take_device_sync (session_proxy,
|
||||
dev_major,
|
||||
dev_minor,
|
||||
NULL,
|
||||
&fd_variant,
|
||||
NULL, /* paused */
|
||||
&fd_list,
|
||||
cancellable,
|
||||
error))
|
||||
return FALSE;
|
||||
|
||||
fd = g_unix_fd_list_get (fd_list, g_variant_get_handle (fd_variant), error);
|
||||
if (fd == -1)
|
||||
return FALSE;
|
||||
|
||||
*out_fd = fd;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_device_info_from_path (const char *path,
|
||||
int *out_major,
|
||||
int *out_minor)
|
||||
{
|
||||
int ret;
|
||||
struct stat st;
|
||||
|
||||
ret = stat (path, &st);
|
||||
if (ret < 0 || !S_ISCHR (st.st_mode))
|
||||
return FALSE;
|
||||
|
||||
*out_major = major (st.st_rdev);
|
||||
*out_minor = minor (st.st_rdev);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
MetaDeviceFile *
|
||||
meta_device_pool_open (MetaDevicePool *pool,
|
||||
const char *path,
|
||||
MetaDeviceFileFlags flags,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr (GMutexLocker) locker = NULL;
|
||||
MetaDeviceFile *file;
|
||||
int major, minor;
|
||||
int fd;
|
||||
|
||||
locker = g_mutex_locker_new (&pool->mutex);
|
||||
|
||||
file = find_device_file_from_path (pool, path);
|
||||
if (file)
|
||||
{
|
||||
g_warn_if_fail (file->flags == flags);
|
||||
meta_device_file_acquire_locked (file);
|
||||
return file;
|
||||
}
|
||||
|
||||
if (!get_device_info_from_path (path, &major, &minor))
|
||||
{
|
||||
g_set_error (error,
|
||||
G_IO_ERROR,
|
||||
G_IO_ERROR_NOT_FOUND,
|
||||
"Could not get device info for path %s: %m", path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (flags & META_DEVICE_FILE_FLAG_TAKE_CONTROL)
|
||||
{
|
||||
if (!pool->session_proxy)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
||||
"Can't take control without logind session");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!take_device (pool->session_proxy, major, minor, &fd, NULL, error))
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
fd = open (path, O_RDWR | O_CLOEXEC, 0);
|
||||
if (fd == -1)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
|
||||
"Failed to open device '%s': %s",
|
||||
path, g_strerror (errno));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
file = meta_device_file_new (pool, path, major, minor, fd, flags);
|
||||
pool->files = g_list_prepend (pool->files, file);
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
static void
|
||||
release_device_file (MetaDevicePool *pool,
|
||||
MetaDeviceFile *file)
|
||||
{
|
||||
g_autoptr (GMutexLocker) locker = NULL;
|
||||
g_autoptr (GError) error = NULL;
|
||||
|
||||
locker = g_mutex_locker_new (&pool->mutex);
|
||||
|
||||
if (!g_ref_count_dec (&file->ref_count))
|
||||
return;
|
||||
|
||||
pool->files = g_list_remove (pool->files, file);
|
||||
|
||||
if (file->flags & META_DEVICE_FILE_FLAG_TAKE_CONTROL)
|
||||
{
|
||||
MetaDbusLogin1Session *session_proxy;
|
||||
|
||||
session_proxy = pool->session_proxy;
|
||||
if (!meta_dbus_login1_session_call_release_device_sync (session_proxy,
|
||||
file->major,
|
||||
file->minor,
|
||||
NULL, &error))
|
||||
{
|
||||
g_warning ("Could not release device '%s' (%d,%d): %s",
|
||||
file->path,
|
||||
file->major, file->minor,
|
||||
error->message);
|
||||
}
|
||||
}
|
||||
|
||||
close (file->fd);
|
||||
|
||||
meta_device_file_free (file);
|
||||
}
|
||||
|
||||
MetaDevicePool *
|
||||
meta_device_pool_new (MetaLauncher *launcher)
|
||||
{
|
||||
MetaDevicePool *pool;
|
||||
|
||||
pool = g_object_new (META_TYPE_DEVICE_POOL, NULL);
|
||||
|
||||
if (launcher)
|
||||
pool->session_proxy = meta_launcher_get_session_proxy (launcher);
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_device_pool_finalize (GObject *object)
|
||||
{
|
||||
MetaDevicePool *pool = META_DEVICE_POOL (object);
|
||||
|
||||
g_mutex_clear (&pool->mutex);
|
||||
g_warn_if_fail (!pool->files);
|
||||
|
||||
G_OBJECT_CLASS (meta_device_pool_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_device_pool_init (MetaDevicePool *pool)
|
||||
{
|
||||
g_mutex_init (&pool->mutex);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_device_pool_class_init (MetaDevicePoolClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = meta_device_pool_finalize;
|
||||
}
|
52
src/backends/native/meta-device-pool.h
Normal file
52
src/backends/native/meta-device-pool.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program 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
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef META_DEVICE_POOL_H
|
||||
#define META_DEVICE_POOL_H
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum _MetaDeviceFileFlags
|
||||
{
|
||||
META_DEVICE_FILE_FLAG_NONE = 0,
|
||||
META_DEVICE_FILE_FLAG_TAKE_CONTROL = 1 << 0,
|
||||
} MetaDeviceFileFlags;
|
||||
|
||||
typedef struct _MetaDeviceFile MetaDeviceFile;
|
||||
typedef struct _MetaDevicePool MetaDevicePool;
|
||||
|
||||
int meta_device_file_get_fd (MetaDeviceFile *device_file);
|
||||
|
||||
const char * meta_device_file_get_path (MetaDeviceFile *device_file);
|
||||
|
||||
MetaDeviceFile * meta_device_file_acquire (MetaDeviceFile *file);
|
||||
|
||||
void meta_device_file_release (MetaDeviceFile *device_file);
|
||||
|
||||
MetaDevicePool * meta_device_file_get_pool (MetaDeviceFile *device_file);
|
||||
|
||||
MetaDeviceFile * meta_device_pool_open (MetaDevicePool *pool,
|
||||
const char *path,
|
||||
MetaDeviceFileFlags flags,
|
||||
GError **error);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (MetaDeviceFile, meta_device_file_release)
|
||||
|
||||
#endif /* META_DEVICE_FILE_POOL_H */
|
@ -503,6 +503,12 @@ get_seat_id (GError **error)
|
||||
return seat_id;
|
||||
}
|
||||
|
||||
MetaDbusLogin1Session *
|
||||
meta_launcher_get_session_proxy (MetaLauncher *launcher)
|
||||
{
|
||||
return launcher->session_proxy;
|
||||
}
|
||||
|
||||
MetaLauncher *
|
||||
meta_launcher_new (GError **error)
|
||||
{
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <glib-object.h>
|
||||
|
||||
typedef struct _MetaLauncher MetaLauncher;
|
||||
typedef struct _MetaDbusLogin1Session MetaDbusLogin1Session;
|
||||
|
||||
MetaLauncher *meta_launcher_new (GError **error);
|
||||
void meta_launcher_free (MetaLauncher *self);
|
||||
@ -40,5 +41,7 @@ int meta_launcher_open_restricted (MetaLauncher *launcher,
|
||||
void meta_launcher_close_restricted (MetaLauncher *launcher,
|
||||
int fd);
|
||||
|
||||
MetaDbusLogin1Session * meta_launcher_get_session_proxy (MetaLauncher *launcher);
|
||||
|
||||
|
||||
#endif /* META_LAUNCHER_H */
|
||||
|
@ -662,6 +662,9 @@ if have_native_backend
|
||||
'backends/native/meta-crtc-virtual.h',
|
||||
'backends/native/meta-cursor-renderer-native.c',
|
||||
'backends/native/meta-cursor-renderer-native.h',
|
||||
'backends/native/meta-device-pool-private.h',
|
||||
'backends/native/meta-device-pool.c',
|
||||
'backends/native/meta-device-pool.h',
|
||||
'backends/native/meta-drm-buffer-dumb.c',
|
||||
'backends/native/meta-drm-buffer-dumb.h',
|
||||
'backends/native/meta-drm-buffer-gbm.c',
|
||||
|
Loading…
Reference in New Issue
Block a user