perf: delay source start until polkit has authorized

Without this, after logging in you are already multiple seconds into your
profiling session recording. Not ideal. So instead, we do the async polkit
auth upfront during SpSource::prepare(), and then toggle ready after we
have received notification.
This commit is contained in:
Christian Hergert
2016-04-14 04:36:18 -07:00
parent bdf888f556
commit a7982ad1e8
3 changed files with 179 additions and 5 deletions

View File

@ -118,6 +118,10 @@ G_DEFINE_BOXED_TYPE (SpPerfCounter,
(GBoxedCopyFunc)sp_perf_counter_ref,
(GBoxedFreeFunc)sp_perf_counter_unref)
#if ENABLE_SYSPROFD
static GDBusConnection *shared_conn;
#endif
static gboolean
perf_gsource_dispatch (GSource *source,
GSourceFunc callback,
@ -413,16 +417,17 @@ static GDBusProxy *
get_proxy (void)
{
static GDBusProxy *proxy;
GDBusConnection *bus = NULL;
if (proxy != NULL)
return g_object_ref (proxy);
bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL);
if (bus == NULL)
if (shared_conn == NULL)
shared_conn = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL);
if (shared_conn == NULL)
return NULL;
proxy = g_dbus_proxy_new_sync (bus,
proxy = g_dbus_proxy_new_sync (shared_conn,
(G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS |
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START_AT_CONSTRUCTION),
@ -490,8 +495,125 @@ get_authorized_proxy (void)
return NULL;
}
static void
sp_perf_counter_acquire_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
g_autoptr(GTask) task = user_data;
GPermission *permission = (GPermission *)object;
GError *error = NULL;
g_assert (G_IS_PERMISSION (permission));
g_assert (G_IS_ASYNC_RESULT (result));
g_assert (G_IS_TASK (task));
if (!g_permission_acquire_finish (permission, result, &error))
{
g_task_return_error (task, error);
return;
}
g_task_return_boolean (task, TRUE);
}
static void
sp_perf_counter_permission_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
g_autoptr(GTask) task = user_data;
GPermission *permission;
GError *error = NULL;
g_assert (G_IS_ASYNC_RESULT (result));
g_assert (G_IS_TASK (task));
if (NULL == (permission = polkit_permission_new_finish (result, &error)))
{
g_task_return_error (task, error);
return;
}
g_permission_acquire_async (permission,
g_task_get_cancellable (task),
sp_perf_counter_acquire_cb,
g_object_ref (task));
g_object_unref (permission);
}
static void
sp_perf_counter_get_bus_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
g_autoptr(GDBusConnection) bus = NULL;
g_autoptr(GTask) task = user_data;
PolkitSubject *subject = NULL;
const gchar *name;
GError *error = NULL;
g_assert (G_IS_ASYNC_RESULT (result));
g_assert (G_IS_TASK (task));
if (NULL == (bus = g_bus_get_finish (result, &error)))
{
g_task_return_error (task, error);
return;
}
shared_conn = g_object_ref (bus);
name = g_dbus_connection_get_unique_name (bus);
subject = polkit_system_bus_name_new (name);
polkit_permission_new ("org.gnome.sysprof2.perf-event-open",
subject,
g_task_get_cancellable (task),
sp_perf_counter_permission_cb,
g_object_ref (task));
g_object_unref (subject);
}
#endif
void
sp_perf_counter_authorize_async (GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_autoptr(GTask) task = NULL;
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
task = g_task_new (NULL, cancellable, callback, user_data);
#if ENABLE_SYSPROFD
g_bus_get (G_BUS_TYPE_SYSTEM,
cancellable,
sp_perf_counter_get_bus_cb,
g_object_ref (task));
#else
g_task_return_new_error (error,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"Sysprofd is not supported in current configuration");
#endif
}
gboolean
sp_perf_counter_authorize_finish (GAsyncResult *result,
GError **error)
{
g_assert (G_IS_TASK (result));
return g_task_propagate_boolean (G_TASK (result), error);
}
gint
sp_perf_counter_open (SpPerfCounter *self,
struct perf_event_attr *attr,

View File

@ -19,7 +19,7 @@
#ifndef SP_PERF_COUNTER_H
#define SP_PERF_COUNTER_H
#include <glib-object.h>
#include <gio/gio.h>
#include <linux/perf_event.h>
@ -110,6 +110,12 @@ typedef void (*SpPerfCounterCallback) (SpPerfCounterEvent *event,
guint cpu,
gpointer user_data);
void sp_perf_counter_authorize_async (GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean sp_perf_counter_authorize_finish (GAsyncResult *result,
GError **error);
GType sp_perf_counter_get_type (void);
SpPerfCounter *sp_perf_counter_new (GMainContext *context);
void sp_perf_counter_set_callback (SpPerfCounter *self,

View File

@ -55,6 +55,7 @@ struct _SpPerfSource
GHashTable *pids;
guint running : 1;
guint is_ready : 1;
};
static void source_iface_init (SpSourceInterface *iface);
@ -430,6 +431,49 @@ sp_perf_source_add_pid (SpSource *source,
g_hash_table_add (self->pids, GINT_TO_POINTER (pid));
}
static void
sp_perf_source_authorize_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
g_autoptr(SpPerfSource) self = user_data;
g_autoptr(GError) error = NULL;
g_assert (G_IS_ASYNC_RESULT (result));
if (!sp_perf_counter_authorize_finish (result, &error))
{
sp_source_emit_failed (SP_SOURCE (self), error);
return;
}
self->is_ready = TRUE;
sp_source_emit_ready (SP_SOURCE (self));
}
static void
sp_perf_source_prepare (SpSource *source)
{
SpPerfSource *self = (SpPerfSource *)source;
g_assert (SP_IS_PERF_SOURCE (self));
sp_perf_counter_authorize_async (NULL,
sp_perf_source_authorize_cb,
g_object_ref (self));
}
static gboolean
sp_perf_source_get_is_ready (SpSource *source)
{
SpPerfSource *self = (SpPerfSource *)source;
g_assert (SP_IS_PERF_SOURCE (self));
return self->is_ready;
}
static void
source_iface_init (SpSourceInterface *iface)
{
@ -437,6 +481,8 @@ source_iface_init (SpSourceInterface *iface)
iface->stop = sp_perf_source_stop;
iface->set_writer = sp_perf_source_set_writer;
iface->add_pid = sp_perf_source_add_pid;
iface->prepare = sp_perf_source_prepare;
iface->get_is_ready = sp_perf_source_get_is_ready;
}
SpSource *