From 195a0cb6bb8cc8739902fcf3245bfe256c980c60 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Wed, 23 Dec 2015 16:35:24 +0000 Subject: [PATCH] gio: Add SystemTap and DTrace probes for GTask This adds a basic tapset for GIO, covering various interesting parts of GTask. https://bugzilla.gnome.org/show_bug.cgi?id=759813 --- docs/reference/gio/Makefile.am | 1 + docs/reference/glib/running.xml | 3 +- gio/Makefile.am | 35 +++++++++++ gio/gio.stp.in | 107 ++++++++++++++++++++++++++++++++ gio/gio_probes.d | 10 +++ gio/gio_trace.h | 41 ++++++++++++ gio/gtask.c | 34 +++++++++- 7 files changed, 227 insertions(+), 4 deletions(-) create mode 100644 gio/gio.stp.in create mode 100644 gio/gio_probes.d create mode 100644 gio/gio_trace.h diff --git a/docs/reference/gio/Makefile.am b/docs/reference/gio/Makefile.am index 38666b41a..ff201cd05 100644 --- a/docs/reference/gio/Makefile.am +++ b/docs/reference/gio/Makefile.am @@ -51,6 +51,7 @@ IGNORE_HFILES = \ gfileattribute-priv.h \ gfileinfo-priv.h \ ghttpproxy.h \ + gio_trace.h \ giomodule-priv.h \ gioprivate.h \ giowin32-priv.h \ diff --git a/docs/reference/glib/running.xml b/docs/reference/glib/running.xml index a00369b3c..c05820b24 100644 --- a/docs/reference/glib/running.xml +++ b/docs/reference/glib/running.xml @@ -310,7 +310,8 @@ Which would print the contents of each widget in a list of widgets. SystemTap is a dynamic whole-system analysis toolkit. GLib ships with a file glib.stp which defines a set of probe points, which you can hook into with custom SystemTap scripts. -See the files glib.stp and gobject.stp which +See the files glib.stp, gobject.stp +and gio.stp which are in your shared SystemTap scripts directory. diff --git a/gio/Makefile.am b/gio/Makefile.am index e911d9145..18e0ca11f 100644 --- a/gio/Makefile.am +++ b/gio/Makefile.am @@ -391,6 +391,7 @@ libgio_2_0_la_SOURCES = \ ginetsocketaddress.c \ ginitable.c \ ginputstream.c \ + gio_trace.h \ gioenums.h \ gioerror.c \ giomodule.c \ @@ -755,6 +756,40 @@ dist_schema_DATA = gschema.dtd itsdir = $(datadir)/gettext/its dist_its_DATA = gschema.loc gschema.its +# ------------------------------------------------------------------------ +# SystemTap and dtrace + +if ENABLE_DTRACE +DTCOMPILE = $(patsubst -W%,,$(LTCOMPILE)) +DTCFLAGS = $(patsubst -W%,,$(CFLAGS)) + +gio_probes.h: gio_probes.d + $(AM_V_GEN) $(DTRACE) -C -h -s $< -o $@.tmp + @$(SED) -e "s,define STAP_HAS_SEMAPHORES 1,undef STAP_HAS_SEMAPHORES," < $@.tmp > $@ && rm -f $@.tmp + +gio_probes.lo: gio_probes.d + $(AM_V_GEN) env CC="$(DTCOMPILE)" CFLAGS="$(DTCFLAGS)" $(DTRACE) -G -s $< -o $@ + +BUILT_SOURCES += gio_probes.h gio_probes.lo +CLEANFILES += gio_probes.h gio_probes.h.tmp +libgio_2_0_la_LIBADD += gio_probes.lo +endif + +if ENABLE_SYSTEMTAP +tapset_in_files = gio.stp.in +tapsetdir = @ABS_TAPSET_DIR@ +tapset_DATA = $(tapset_in_files:.stp.in=.stp) +EXTRA_DIST += $(tapset_in_files) +CLEANFILES += $(tapset_in_files:.stp.in=.stp) + +$(tapset_DATA): %.stp: %.stp.in Makefile + $(AM_V_GEN)$(SED) \ + -e 's|[@]ABS_GLIB_RUNTIME_LIBDIR[@]|$(ABS_GLIB_RUNTIME_LIBDIR)|g' \ + -e 's|[@]LT_CURRENT[@]|$(LT_CURRENT)|g' \ + -e 's|[@]LT_REVISION[@]|$(LT_REVISION)|g' \ + $< > $@ +endif + # ------------------------------------------------------------------------ # gdbus(1) tool diff --git a/gio/gio.stp.in b/gio/gio.stp.in new file mode 100644 index 000000000..3ca0cd393 --- /dev/null +++ b/gio/gio.stp.in @@ -0,0 +1,107 @@ +/** + * probe gio.task_new - Called when a new #GTask is created + * @task: the new #GTask object + * @source_object: the source object + * @cancellable: the #GCancellable + * @callback: the task’s callback + * @callback_data: data for @callback + */ +probe gio.task_new = process("@ABS_GLIB_RUNTIME_LIBDIR@/libgio-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("task__new") +{ + task = $arg1; + source_object = $arg2; + cancellable = $arg3; + callback = $arg4; + callback_data = $arg5; + probestr = sprintf("gio.task_new(%p, %p, %p, %p) -> %p", source_object, cancellable, callback, callback_data, task); +} + +/** + * probe gio.task_set_task_data - Called when the task data is set on a #GTask + * @task: the #GTask object + * @task_data: the task data + * @task_data_destroy: the destroy notify function for the data + */ +probe gio.task_set_task_data = process("@ABS_GLIB_RUNTIME_LIBDIR@/libgio-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("task__set_task_data") +{ + task = $arg1; + task_data = $arg2; + task_data_destroy = $arg3; + probestr = sprintf("gio.task_set_task_data(%p, %p, %p)", task, task_data, task_data_destroy); +} + +/** + * probe gio.task_set_priority - Called when the priority of a #GTask is set + * @task: the #GTask object + * @priority: the priority + */ +probe gio.task_set_priority = process("@ABS_GLIB_RUNTIME_LIBDIR@/libgio-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("task__set_priority") +{ + task = $arg1; + priority = $arg2; + probestr = sprintf("gio.task_set_priority(%p, %i)", task, priority); +} + +/** + * probe gio.task_set_source_tag - Called when the source tag of a #GTask is set + * @task: the #GTask object + * @source_tag: the source tag + */ +probe gio.task_set_source_tag = process("@ABS_GLIB_RUNTIME_LIBDIR@/libgio-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("task__set_source_tag") +{ + task = $arg1; + source_tag = $arg2; + probestr = sprintf("gio.task_set_source_tag(%p, %p)", task, source_tag); +} + +/** + * probe gio.task_before_return - Called before a #GTask invokes its callback or returns from g_task_run_in_thread_sync() + * @task: the #GTask object + * @source_object: the source object passed to the callback + * @callback: the callback about to be invoked + * @callback_data: data passed to @callback + */ +probe gio.task_before_return = process("@ABS_GLIB_RUNTIME_LIBDIR@/libgio-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("task__before_return") +{ + task = $arg1; + source_object = $arg2; + callback = $arg3; + callback_data = $arg4; + probestr = sprintf("gio.task_before_return(%p, %p, %p, %p)", task, source_object, callback, callback_data); +} + +/** + * probe gio.task_propagate - Called when a #GTask’s result is propagated + * @task: the #GTask object + * @error_set: %TRUE if propagating an error, %FALSE otherwise + */ +probe gio.task_propagate = process("@ABS_GLIB_RUNTIME_LIBDIR@/libgio-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("task__propagate") +{ + task = $arg1; + error_set = $arg2; + probestr = sprintf("gio.task_propagate(%p) -> %u", task, error_set); +} + +/** + * probe gio.task_before_run_in_thread - Called before a #GTask’s function is run in a thread + * @task: the #GTask object + * @task_func: the task function being run + */ +probe gio.task_before_run_in_thread = process("@ABS_GLIB_RUNTIME_LIBDIR@/libgio-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("task__before_run_in_thread") +{ + task = $arg1; + task_func = $arg2; + probestr = sprintf("gio.task_before_run_in_thread(%p, %p)", task, task_func); +} + +/** + * probe gio.task_after_run_in_thread - Called after a #GTask’s function is run in a thread + * @task: the #GTask object + * @thread_cancelled: %TRUE if the thread was cancelled, %FALSE otherwise + */ +probe gio.task_after_run_in_thread = process("@ABS_GLIB_RUNTIME_LIBDIR@/libgio-2.0.so.0.@LT_CURRENT@.@LT_REVISION@").mark("task__after_run_in_thread") +{ + task = $arg1; + thread_cancelled = $arg2; + probestr = sprintf("gio.task_after_run_in_thread(%p) -> %u", task, thread_cancelled); +} diff --git a/gio/gio_probes.d b/gio/gio_probes.d new file mode 100644 index 000000000..8747d8d29 --- /dev/null +++ b/gio/gio_probes.d @@ -0,0 +1,10 @@ +provider gio { + probe task__new(void*, void*, void*, void*, void*); + probe task__set_task_data(void*, void*, void*); + probe task__set_priority(void*, int); + probe task__set_source_tag(void*, void*); + probe task__before_return(void*, void*, void*, void*); + probe task__propagate(void*, unsigned int); + probe task__before_run_in_thread(void*, void*); + probe task__after_run_in_thread(void*, unsigned int); +}; diff --git a/gio/gio_trace.h b/gio/gio_trace.h new file mode 100644 index 000000000..ba69a6eaa --- /dev/null +++ b/gio/gio_trace.h @@ -0,0 +1,41 @@ +/* GLIB - Library of useful routines for C programming + * + * Copyright (C) 2009,2010 Red Hat, Inc. + * + * 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 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, see . + * + * Author: Alexander Larsson + */ + +#ifndef __GIOTRACE_H__ +#define __GIOTRACE_H__ + +#ifndef SIZEOF_CHAR +#error "config.h must be included prior to gio_trace.h" +#endif + +#ifdef HAVE_DTRACE + +/* include the generated probes header and put markers in code */ +#include "gio_probes.h" +#define TRACE(probe) probe + +#else + +/* Wrap the probe to allow it to be removed when no systemtap available */ +#define TRACE(probe) + +#endif + +#endif /* __GIOTRACE_H__ */ diff --git a/gio/gtask.c b/gio/gtask.c index 042e04764..4af423764 100644 --- a/gio/gtask.c +++ b/gio/gtask.c @@ -17,6 +17,7 @@ */ #include "config.h" +#include "gio_trace.h" #include "gtask.h" @@ -700,6 +701,9 @@ g_task_new (gpointer source_object, if (source) task->creation_time = g_source_get_time (source); + TRACE (GIO_TASK_NEW (task, source_object, cancellable, + callback, callback_data)); + return task; } @@ -803,6 +807,8 @@ g_task_set_task_data (GTask *task, task->task_data = task_data; task->task_data_destroy = task_data_destroy; + + TRACE (GIO_TASK_SET_TASK_DATA (task, task_data, task_data_destroy)); } /** @@ -825,6 +831,8 @@ g_task_set_priority (GTask *task, gint priority) { task->priority = priority; + + TRACE (GIO_TASK_SET_PRIORITY (task, priority)); } /** @@ -951,6 +959,8 @@ g_task_set_source_tag (GTask *task, gpointer source_tag) { task->source_tag = source_tag; + + TRACE (GIO_TASK_SET_SOURCE_TAG (task, source_tag)); } /** @@ -1101,6 +1111,9 @@ g_task_get_source_tag (GTask *task) static void g_task_return_now (GTask *task) { + TRACE (GIO_TASK_BEFORE_RETURN (task, task->source_object, task->callback, + task->callback_data)); + g_main_context_push_thread_default (task->context); if (task->callback != NULL) @@ -1219,6 +1232,8 @@ g_task_thread_complete (GTask *task) return; } + TRACE (GIO_TASK_AFTER_RUN_IN_THREAD (task, task->thread_cancelled)); + task->thread_complete = TRUE; g_mutex_unlock (&task->lock); @@ -1338,6 +1353,8 @@ g_task_start_task_thread (GTask *task, g_mutex_lock (&task->lock); + TRACE (GIO_TASK_BEFORE_RUN_IN_THREAD (task, task_func)); + task->task_func = task_func; if (task->cancellable) @@ -1347,6 +1364,7 @@ g_task_start_task_thread (GTask *task, &task->error)) { task->thread_cancelled = task->thread_complete = TRUE; + TRACE (GIO_TASK_AFTER_RUN_IN_THREAD (task, task->thread_cancelled)); g_thread_pool_push (task_pool, g_object_ref (task), NULL); return; } @@ -1453,6 +1471,10 @@ g_task_run_in_thread_sync (GTask *task, g_mutex_unlock (&task->lock); + TRACE (GIO_TASK_BEFORE_RETURN (task, task->source_object, + NULL /* callback */, + NULL /* callback data */)); + /* Notify of completion in this thread. */ task->completed = TRUE; g_object_notify (G_OBJECT (task), "completed"); @@ -1491,18 +1513,24 @@ static gboolean g_task_propagate_error (GTask *task, GError **error) { + gboolean error_set; + if (task->check_cancellable && g_cancellable_set_error_if_cancelled (task->cancellable, error)) - return TRUE; + error_set = TRUE; else if (task->error) { g_propagate_error (error, task->error); task->error = NULL; task->had_error = TRUE; - return TRUE; + error_set = TRUE; } else - return FALSE; + error_set = FALSE; + + TRACE (GIO_TASK_PROPAGATE (task, error_set)); + + return error_set; } /**