mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-15 23:29:19 +00:00
Add FuDeviceLocker to simplify device open/close lifecycles
We can use the power of g_autoptr() to automatically close devices that have gone out of scope. When everything is converted we can drop the GUsbContect AUTO_OPEN_DEVICES flag which is making us look bad in powertop.
This commit is contained in:
parent
0f224225f7
commit
7c52580f9c
151
src/fu-device-locker.c
Normal file
151
src/fu-device-locker.c
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Richard Hughes <richard@hughsie.com>
|
||||||
|
*
|
||||||
|
* Licensed under the GNU Lesser General Public License Version 2.1
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <gio/gio.h>
|
||||||
|
#include <gusb.h>
|
||||||
|
|
||||||
|
#include "fu-device-locker.h"
|
||||||
|
|
||||||
|
struct _FuDeviceLocker {
|
||||||
|
GObject parent_instance;
|
||||||
|
GObject *device;
|
||||||
|
gboolean device_open;
|
||||||
|
FuDeviceLockerFunc open_func;
|
||||||
|
FuDeviceLockerFunc close_func;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (FuDeviceLocker, fu_device_locker, G_TYPE_OBJECT)
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_device_locker_finalize (GObject *obj)
|
||||||
|
{
|
||||||
|
FuDeviceLocker *self = FU_DEVICE_LOCKER (obj);
|
||||||
|
|
||||||
|
/* close device */
|
||||||
|
if (self->device_open) {
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
if (!self->close_func (self->device, &error))
|
||||||
|
g_warning ("failed to close device: %s", error->message);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_unref (self->device);
|
||||||
|
G_OBJECT_CLASS (fu_device_locker_parent_class)->finalize (obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_device_locker_class_init (FuDeviceLockerClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
object_class->finalize = fu_device_locker_finalize;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_device_locker_init (FuDeviceLocker *self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fu_device_locker_new:
|
||||||
|
* @device: A #GObject
|
||||||
|
* @error: A #GError, or %NULL
|
||||||
|
*
|
||||||
|
* Opens the device for use. When the #FuDeviceLocker is deallocated the device
|
||||||
|
* will be closed and any error will just be directed to the console.
|
||||||
|
* This object is typically called using g_autoptr() but the device can also be
|
||||||
|
* manually closed using g_clear_object().
|
||||||
|
*
|
||||||
|
* The functions used for opening and closing the device are set automatically.
|
||||||
|
* If the @device is not a type or supertype of @GUsbDevice then this function
|
||||||
|
* will not work. For custom objects please use fu_device_locker_new_full().
|
||||||
|
*
|
||||||
|
* NOTE: If the @open_func failed then the @close_func will not be called.
|
||||||
|
*
|
||||||
|
* Think of this object as the device ownership.
|
||||||
|
*
|
||||||
|
* Returns: a #FuDeviceLocker, or %NULL if the @open_func failed.
|
||||||
|
**/
|
||||||
|
FuDeviceLocker *
|
||||||
|
fu_device_locker_new (gpointer device, GError **error)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (device != NULL, NULL);
|
||||||
|
g_return_val_if_fail (error != NULL, NULL);
|
||||||
|
|
||||||
|
/* GUsbDevice */
|
||||||
|
if (G_USB_IS_DEVICE (device)) {
|
||||||
|
return fu_device_locker_new_full (device,
|
||||||
|
(FuDeviceLockerFunc) g_usb_device_open,
|
||||||
|
(FuDeviceLockerFunc) g_usb_device_close,
|
||||||
|
error);
|
||||||
|
}
|
||||||
|
g_set_error_literal (error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_NOT_SUPPORTED,
|
||||||
|
"device object type not supported");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fu_device_locker_new_full:
|
||||||
|
* @device: A #GObject
|
||||||
|
* @open_func: A function to open the device
|
||||||
|
* @close_func: A function to close the device
|
||||||
|
* @error: A #GError, or %NULL
|
||||||
|
*
|
||||||
|
* Opens the device for use. When the #FuDeviceLocker is deallocated the device
|
||||||
|
* will be closed and any error will just be directed to the console.
|
||||||
|
* This object is typically called using g_autoptr() but the device can also be
|
||||||
|
* manually closed using g_clear_object().
|
||||||
|
*
|
||||||
|
* NOTE: If the @open_func failed then the @close_func will not be called.
|
||||||
|
*
|
||||||
|
* Think of this object as the device ownership.
|
||||||
|
*
|
||||||
|
* Returns: a #FuDeviceLocker, or %NULL if the @open_func failed.
|
||||||
|
**/
|
||||||
|
FuDeviceLocker *
|
||||||
|
fu_device_locker_new_full (gpointer device,
|
||||||
|
FuDeviceLockerFunc open_func,
|
||||||
|
FuDeviceLockerFunc close_func,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
g_autoptr(FuDeviceLocker) self = NULL;
|
||||||
|
|
||||||
|
g_return_val_if_fail (device != NULL, NULL);
|
||||||
|
g_return_val_if_fail (open_func != NULL, NULL);
|
||||||
|
g_return_val_if_fail (close_func != NULL, NULL);
|
||||||
|
g_return_val_if_fail (error != NULL, NULL);
|
||||||
|
|
||||||
|
/* create object */
|
||||||
|
self = g_object_new (FU_TYPE_DEVICE_LOCKER, NULL);
|
||||||
|
self->device = g_object_ref (device);
|
||||||
|
self->open_func = open_func;
|
||||||
|
self->close_func = close_func;
|
||||||
|
|
||||||
|
/* open device */
|
||||||
|
if (!self->open_func (device, error))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* success */
|
||||||
|
self->device_open = TRUE;
|
||||||
|
return g_steal_pointer (&self);
|
||||||
|
}
|
45
src/fu-device-locker.h
Normal file
45
src/fu-device-locker.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Richard Hughes <richard@hughsie.com>
|
||||||
|
*
|
||||||
|
* Licensed under the GNU Lesser General Public License Version 2.1
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FU_DEVICE_LOCKER_H
|
||||||
|
#define __FU_DEVICE_LOCKER_H
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define FU_TYPE_DEVICE_LOCKER (fu_device_locker_get_type ())
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE (FuDeviceLocker, fu_device_locker, FU, DEVICE_LOCKER, GObject)
|
||||||
|
|
||||||
|
typedef gboolean (*FuDeviceLockerFunc) (GObject *device,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
FuDeviceLocker *fu_device_locker_new (gpointer device,
|
||||||
|
GError **error);
|
||||||
|
FuDeviceLocker *fu_device_locker_new_full (gpointer device,
|
||||||
|
FuDeviceLockerFunc open_func,
|
||||||
|
FuDeviceLockerFunc close_func,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __FU_DEVICE_LOCKER_H */
|
@ -650,6 +650,62 @@ fu_test_stdout_cb (const gchar *line, gpointer user_data)
|
|||||||
(*lines)++;
|
(*lines)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_open_cb (GObject *device, GError **error)
|
||||||
|
{
|
||||||
|
g_assert_cmpstr (g_object_get_data (device, "state"), ==, "closed");
|
||||||
|
g_object_set_data (device, "state", "opened");
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_close_cb (GObject *device, GError **error)
|
||||||
|
{
|
||||||
|
g_assert_cmpstr (g_object_get_data (device, "state"), ==, "opened");
|
||||||
|
g_object_set_data (device, "state", "closed-on-unref");
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_device_locker_func (void)
|
||||||
|
{
|
||||||
|
g_autoptr(FuDeviceLocker) locker = NULL;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
g_autoptr(GObject) device = g_object_new (G_TYPE_OBJECT, NULL);
|
||||||
|
|
||||||
|
g_object_set_data (device, "state", "closed");
|
||||||
|
locker = fu_device_locker_new_full (device, _open_cb, _close_cb, &error);
|
||||||
|
g_assert_no_error (error);
|
||||||
|
g_assert_nonnull (locker);
|
||||||
|
g_clear_object (&locker);
|
||||||
|
g_assert_cmpstr (g_object_get_data (device, "state"), ==, "closed-on-unref");
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_fail_open_cb (GObject *device, GError **error)
|
||||||
|
{
|
||||||
|
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, "fail");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
_fail_close_cb (GObject *device, GError **error)
|
||||||
|
{
|
||||||
|
g_assert_not_reached ();
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_device_locker_fail_func (void)
|
||||||
|
{
|
||||||
|
g_autoptr(FuDeviceLocker) locker = NULL;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
g_autoptr(GObject) device = g_object_new (G_TYPE_OBJECT, NULL);
|
||||||
|
locker = fu_device_locker_new_full (device, _fail_open_cb, _fail_close_cb, &error);
|
||||||
|
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
|
||||||
|
g_assert_null (locker);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fu_common_spawn_func (void)
|
fu_common_spawn_func (void)
|
||||||
{
|
{
|
||||||
@ -681,6 +737,8 @@ main (int argc, char **argv)
|
|||||||
g_assert_cmpint (g_mkdir_with_parents ("/tmp/fwupd-self-test/var/lib/fwupd", 0755), ==, 0);
|
g_assert_cmpint (g_mkdir_with_parents ("/tmp/fwupd-self-test/var/lib/fwupd", 0755), ==, 0);
|
||||||
|
|
||||||
/* tests go here */
|
/* tests go here */
|
||||||
|
g_test_add_func ("/fwupd/device-locker{success}", fu_device_locker_func);
|
||||||
|
g_test_add_func ("/fwupd/device-locker{fail}", fu_device_locker_fail_func);
|
||||||
g_test_add_func ("/fwupd/device{metadata}", fu_device_metadata_func);
|
g_test_add_func ("/fwupd/device{metadata}", fu_device_metadata_func);
|
||||||
g_test_add_func ("/fwupd/hwids", fu_hwids_func);
|
g_test_add_func ("/fwupd/hwids", fu_hwids_func);
|
||||||
g_test_add_func ("/fwupd/smbios", fu_smbios_func);
|
g_test_add_func ("/fwupd/smbios", fu_smbios_func);
|
||||||
|
@ -23,6 +23,7 @@ libfwupdprivate = static_library(
|
|||||||
sources : [
|
sources : [
|
||||||
'fu-common.c',
|
'fu-common.c',
|
||||||
'fu-device.c',
|
'fu-device.c',
|
||||||
|
'fu-device-locker.c',
|
||||||
'fu-hwids.c',
|
'fu-hwids.c',
|
||||||
'fu-pending.c',
|
'fu-pending.c',
|
||||||
'fu-plugin.c',
|
'fu-plugin.c',
|
||||||
@ -105,6 +106,7 @@ executable(
|
|||||||
'fu-hwids.c',
|
'fu-hwids.c',
|
||||||
'fu-debug.c',
|
'fu-debug.c',
|
||||||
'fu-device.c',
|
'fu-device.c',
|
||||||
|
'fu-device-locker.c',
|
||||||
'fu-keyring.c',
|
'fu-keyring.c',
|
||||||
'fu-pending.c',
|
'fu-pending.c',
|
||||||
'fu-plugin.c',
|
'fu-plugin.c',
|
||||||
@ -153,6 +155,7 @@ if get_option('enable-tests')
|
|||||||
'fu-keyring.c',
|
'fu-keyring.c',
|
||||||
'fu-hwids.c',
|
'fu-hwids.c',
|
||||||
'fu-device.c',
|
'fu-device.c',
|
||||||
|
'fu-device-locker.c',
|
||||||
'fu-pending.c',
|
'fu-pending.c',
|
||||||
'fu-keyring.c',
|
'fu-keyring.c',
|
||||||
'fu-keyring-result.c',
|
'fu-keyring-result.c',
|
||||||
|
Loading…
Reference in New Issue
Block a user