From 552ccb4f6086eeb86fe3d317105d7493439aef28 Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Fri, 24 May 2019 16:01:32 -0700 Subject: [PATCH] libsysprof: move tracefd to separate source --- src/libsysprof/meson.build | 2 + src/libsysprof/sysprof-proxy-source.c | 40 ---- src/libsysprof/sysprof-tracefd-source.c | 290 ++++++++++++++++++++++++ src/libsysprof/sysprof-tracefd-source.h | 49 ++++ src/libsysprof/sysprof.h | 1 + 5 files changed, 342 insertions(+), 40 deletions(-) create mode 100644 src/libsysprof/sysprof-tracefd-source.c create mode 100644 src/libsysprof/sysprof-tracefd-source.h diff --git a/src/libsysprof/meson.build b/src/libsysprof/meson.build index 6d47e154..2a7d40fa 100644 --- a/src/libsysprof/meson.build +++ b/src/libsysprof/meson.build @@ -20,6 +20,7 @@ libsysprof_public_sources = [ 'sysprof-source.c', 'sysprof-symbol-dirs.c', 'sysprof-symbol-resolver.c', + 'sysprof-tracefd-source.c', ] libsysprof_public_headers = [ @@ -42,6 +43,7 @@ libsysprof_public_headers = [ 'sysprof-source.h', 'sysprof-symbol-dirs.h', 'sysprof-symbol-resolver.h', + 'sysprof-tracefd-source.h', 'sysprof.h', ] diff --git a/src/libsysprof/sysprof-proxy-source.c b/src/libsysprof/sysprof-proxy-source.c index d38716b9..536c51e0 100644 --- a/src/libsysprof/sysprof-proxy-source.c +++ b/src/libsysprof/sysprof-proxy-source.c @@ -375,12 +375,6 @@ sysprof_proxy_source_start (SysprofSource *source) self->has_started = TRUE; - /* If we're doing subprocess monitoring, we don't need to do - * anything special here to connect to a bus. - */ - if (self->monitors->len > 0) - return; - g_bus_get (self->bus_type, self->cancellable, sysprof_proxy_source_get_bus_cb, @@ -504,39 +498,6 @@ sysprof_proxy_source_add_pid (SysprofSource *source, g_array_append_val (self->pids, pid); } -static void -sysprof_proxy_source_modify_spawn (SysprofSource *source, - GSubprocessLauncher *launcher, - GPtrArray *argv) -{ - SysprofProxySource *self = (SysprofProxySource *)source; - gchar fdstr[12]; - Monitor *monitor; - gint fd; - - g_assert (SYSPROF_IS_PROXY_SOURCE (self)); - g_assert (G_IS_SUBPROCESS_LAUNCHER (launcher)); - g_assert (argv != NULL); - - /* We need to create a new FD for the peer process to write - * to and notify it via SYSPROF_TRACE_FD. We will largely - * ignore things until the capture has finished. - */ - - if (-1 == (fd = sysprof_memfd_create ("[sysprof-proxy-capture]"))) - return; - - monitor = g_slice_new0 (Monitor); - monitor->self = g_object_ref (self); - monitor->fd = dup (fd); - - g_snprintf (fdstr, sizeof fdstr, "%d", fd); - g_subprocess_launcher_setenv (launcher, "SYSPROF_TRACE_FD", fdstr, TRUE); - g_subprocess_launcher_take_fd (launcher, fd, fd); - - sysprof_proxy_source_take_monitor (self, g_steal_pointer (&monitor)); -} - static void sysprof_proxy_source_serialize (SysprofSource *source, GKeyFile *keyfile, @@ -585,7 +546,6 @@ source_iface_init (SysprofSourceInterface *iface) iface->get_is_ready = sysprof_proxy_source_get_is_ready; iface->stop = sysprof_proxy_source_stop; iface->start = sysprof_proxy_source_start; - iface->modify_spawn = sysprof_proxy_source_modify_spawn; iface->serialize = sysprof_proxy_source_serialize; iface->deserialize = sysprof_proxy_source_deserialize; } diff --git a/src/libsysprof/sysprof-tracefd-source.c b/src/libsysprof/sysprof-tracefd-source.c new file mode 100644 index 00000000..5a57c552 --- /dev/null +++ b/src/libsysprof/sysprof-tracefd-source.c @@ -0,0 +1,290 @@ +/* sysprof-tracefd-source.c + * + * Copyright 2019 Christian Hergert + * + * 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 3 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, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#define G_LOG_DOMAIN "sysprof-tracefd-source" + +#include "config.h" + +#include +#include + +#include "sysprof-platform.h" +#include "sysprof-tracefd-source.h" + +typedef struct +{ + SysprofCaptureWriter *writer; + gchar *envvar; + gint tracefd; +} SysprofTracefdSourcePrivate; + +enum { + PROP_0, + PROP_ENVVAR, + N_PROPS +}; + +static void source_iface_init (SysprofSourceInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (SysprofTracefdSource, sysprof_tracefd_source, G_TYPE_OBJECT, + G_ADD_PRIVATE (SysprofTracefdSource) + G_IMPLEMENT_INTERFACE (SYSPROF_TYPE_SOURCE, source_iface_init)) + +static GParamSpec *properties [N_PROPS]; + +static void +sysprof_tracefd_source_finalize (GObject *object) +{ + SysprofTracefdSource *self = (SysprofTracefdSource *)object; + SysprofTracefdSourcePrivate *priv = sysprof_tracefd_source_get_instance_private (self); + + g_clear_pointer (&priv->writer, sysprof_capture_writer_unref); + g_clear_pointer (&priv->envvar, g_free); + + if (priv->tracefd != -1) + { + close (priv->tracefd); + priv->tracefd = -1; + } + + G_OBJECT_CLASS (sysprof_tracefd_source_parent_class)->finalize (object); +} + +static void +sysprof_tracefd_source_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + SysprofTracefdSource *self = SYSPROF_TRACEFD_SOURCE (object); + + switch (prop_id) + { + case PROP_ENVVAR: + g_value_set_string (value, sysprof_tracefd_source_get_envvar (self)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_tracefd_source_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + SysprofTracefdSource *self = SYSPROF_TRACEFD_SOURCE (object); + + switch (prop_id) + { + case PROP_ENVVAR: + sysprof_tracefd_source_set_envvar (self, g_value_get_string (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +sysprof_tracefd_source_class_init (SysprofTracefdSourceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = sysprof_tracefd_source_finalize; + object_class->get_property = sysprof_tracefd_source_get_property; + object_class->set_property = sysprof_tracefd_source_set_property; + + properties [PROP_ENVVAR] = + g_param_spec_string ("envvar", + "Environment Variable", + "The environment variable to set", + "SYSPROF_TRACE_FD", + (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_properties (object_class, N_PROPS, properties); +} + +static void +sysprof_tracefd_source_init (SysprofTracefdSource *self) +{ + SysprofTracefdSourcePrivate *priv = sysprof_tracefd_source_get_instance_private (self); + + priv->tracefd = -1; + priv->envvar = g_strdup ("SYSPROF_TRACE_FD"); +} + +const gchar * +sysprof_tracefd_source_get_envvar (SysprofTracefdSource *self) +{ + SysprofTracefdSourcePrivate *priv = sysprof_tracefd_source_get_instance_private (self); + + g_return_val_if_fail (SYSPROF_IS_TRACEFD_SOURCE (self), NULL); + + return priv->envvar; +} + +void +sysprof_tracefd_source_set_envvar (SysprofTracefdSource *self, + const gchar *envvar) +{ + SysprofTracefdSourcePrivate *priv = sysprof_tracefd_source_get_instance_private (self); + + g_return_if_fail (SYSPROF_IS_TRACEFD_SOURCE (self)); + + if (envvar == NULL) + envvar = "SYSPROF_TRACE_FD"; + + if (g_strcmp0 (priv->envvar, envvar) != 0) + { + g_free (priv->envvar); + priv->envvar = g_strdup (envvar); + g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ENVVAR]); + } +} + +static void +sysprof_tracefd_source_modify_spawn (SysprofSource *source, + GSubprocessLauncher *launcher, + GPtrArray *argv) +{ + SysprofTracefdSource *self = (SysprofTracefdSource *)source; + SysprofTracefdSourcePrivate *priv = sysprof_tracefd_source_get_instance_private (self); + gchar fdstr[12]; + gint fd; + + g_assert (SYSPROF_IS_TRACEFD_SOURCE (self)); + g_assert (G_IS_SUBPROCESS_LAUNCHER (launcher)); + g_assert (argv != NULL); + g_assert (priv->tracefd == -1); + + if (-1 == (fd = sysprof_memfd_create ("[sysprof-proxy-capture]"))) + { + g_warning ("Failed to create FD for tracefd capture: %s", + g_strerror (errno)); + return; + } + + if (-1 == (priv->tracefd = dup (fd))) + { + g_warning ("Failed to duplicate tracefd for readback: %s", + g_strerror (errno)); + close (fd); + return; + } + + g_snprintf (fdstr, sizeof fdstr, "%d", fd); + g_subprocess_launcher_setenv (launcher, priv->envvar, fdstr, TRUE); + g_subprocess_launcher_take_fd (launcher, fd, fd); +} + +static void +sysprof_tracefd_source_serialize (SysprofSource *source, + GKeyFile *keyfile, + const gchar *group) +{ + SysprofTracefdSource *self = (SysprofTracefdSource *)source; + SysprofTracefdSourcePrivate *priv = sysprof_tracefd_source_get_instance_private (self); + + g_assert (SYSPROF_IS_TRACEFD_SOURCE (self)); + g_assert (keyfile != NULL); + g_assert (group != NULL); + + g_key_file_set_string (keyfile, group, "envvar", priv->envvar); +} + +static void +sysprof_tracefd_source_deserialize (SysprofSource *source, + GKeyFile *keyfile, + const gchar *group) +{ + SysprofTracefdSource *self = (SysprofTracefdSource *)source; + g_autofree gchar *envvar = NULL; + + g_assert (SYSPROF_IS_TRACEFD_SOURCE (self)); + g_assert (keyfile != NULL); + g_assert (group != NULL); + + if ((envvar = g_key_file_get_string (keyfile, group, "envvar", NULL))) + sysprof_tracefd_source_set_envvar (self, envvar); +} + +static void +sysprof_tracefd_source_prepare (SysprofSource *source) +{ + g_assert (SYSPROF_IS_TRACEFD_SOURCE (source)); + + sysprof_source_emit_ready (source); +} + +static gboolean +sysprof_tracefd_source_get_is_ready (SysprofSource *source) +{ + g_assert (SYSPROF_IS_TRACEFD_SOURCE (source)); + + return TRUE; +} + +static void +sysprof_tracefd_source_stop (SysprofSource *source) +{ + SysprofTracefdSource *self = (SysprofTracefdSource *)source; + SysprofTracefdSourcePrivate *priv = sysprof_tracefd_source_get_instance_private (self); + + g_assert (SYSPROF_IS_TRACEFD_SOURCE (self)); + + if (priv->writer != NULL && priv->tracefd != -1) + { + g_autoptr(SysprofCaptureReader) reader = NULL; + + if ((reader = sysprof_capture_reader_new_from_fd (priv->tracefd, 0))) + sysprof_capture_writer_cat (priv->writer, reader, NULL); + } + + sysprof_source_emit_finished (source); +} + +static void +sysprof_tracefd_source_set_writer (SysprofSource *source, + SysprofCaptureWriter *writer) +{ + SysprofTracefdSource *self = (SysprofTracefdSource *)source; + SysprofTracefdSourcePrivate *priv = sysprof_tracefd_source_get_instance_private (self); + + g_assert (SYSPROF_IS_TRACEFD_SOURCE (self)); + g_assert (writer != NULL); + + g_clear_pointer (&priv->writer, sysprof_capture_writer_unref); + priv->writer = sysprof_capture_writer_ref (writer); +} + +static void +source_iface_init (SysprofSourceInterface *iface) +{ + iface->deserialize = sysprof_tracefd_source_deserialize; + iface->get_is_ready = sysprof_tracefd_source_get_is_ready; + iface->modify_spawn = sysprof_tracefd_source_modify_spawn; + iface->prepare = sysprof_tracefd_source_prepare; + iface->serialize = sysprof_tracefd_source_serialize; + iface->set_writer = sysprof_tracefd_source_set_writer; + iface->stop = sysprof_tracefd_source_stop; +} diff --git a/src/libsysprof/sysprof-tracefd-source.h b/src/libsysprof/sysprof-tracefd-source.h new file mode 100644 index 00000000..1dfd5519 --- /dev/null +++ b/src/libsysprof/sysprof-tracefd-source.h @@ -0,0 +1,49 @@ +/* sysprof-tracefd-source.h + * + * Copyright 2019 Christian Hergert + * + * 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 3 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, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include "sysprof-source.h" + +G_BEGIN_DECLS + +#define SYSPROF_TYPE_TRACEFD_SOURCE (sysprof_tracefd_source_get_type()) + +SYSPROF_AVAILABLE_IN_ALL +G_DECLARE_DERIVABLE_TYPE (SysprofTracefdSource, sysprof_tracefd_source, SYSPROF, TRACEFD_SOURCE, GObject) + +struct _SysprofTracefdSourceClass +{ + GObjectClass parent_class; + + /*< private >*/ + gpointer _reserved[16]; +}; + +SYSPROF_AVAILABLE_IN_ALL +SysprofSource *sysprof_tracefd_source_new (void); +SYSPROF_AVAILABLE_IN_ALL +const gchar *sysprof_tracefd_source_get_envvar (SysprofTracefdSource *self); +SYSPROF_AVAILABLE_IN_ALL +void sysprof_tracefd_source_set_envvar (SysprofTracefdSource *self, + const gchar *envvar); + + +G_END_DECLS diff --git a/src/libsysprof/sysprof.h b/src/libsysprof/sysprof.h index 4ea6c122..bc23ebb0 100644 --- a/src/libsysprof/sysprof.h +++ b/src/libsysprof/sysprof.h @@ -43,6 +43,7 @@ G_BEGIN_DECLS # include "sysprof-symbol-resolver.h" # include "sysprof-map-lookaside.h" # include "sysprof-selection.h" +# include "sysprof-tracefd-source.h" #ifdef __linux__ # include "sysprof-gjs-source.h"