Richard W.M. Jones
2015-Oct-07 17:29 UTC
[Libguestfs] [PATCH 0/2] New APIs: set-identifier, get-identifier
This is very useful for debugging multithreaded programs. Rich.
Richard W.M. Jones
2015-Oct-07 17:29 UTC
[Libguestfs] [PATCH 1/2] New APIs: set-identifier, get-identifier
Add a per-handle identifier. The main effect of this is to change
trace output from:
libguestfs: trace: foo
to:
libguestfs: trace: ID: foo
which makes it simpler to follow traces from multi-threaded programs.
---
generator/actions.ml | 43 +++++++++++++++++++++++++++++++++++++++++++
src/events.c | 10 ++++++++--
src/guestfs-internal.h | 1 +
src/handle.c | 32 ++++++++++++++++++++++++++++++++
src/launch.c | 5 +++++
5 files changed, 89 insertions(+), 2 deletions(-)
diff --git a/generator/actions.ml b/generator/actions.ml
index c1755b9..ae4bb0c 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -3369,6 +3369,49 @@ To download to the current directory, use C<.> as
in:
Wildcards cannot be used." };
+ { defaults with
+ name = "set_identifier"; added = (1, 31, 14);
+ style = RErr, [String "identifier"], [];
+ fish_alias = ["identifier"];
+ blocking = false;
+ shortdesc = "set the handle identifier";
+ longdesc = "\
+This is an informative string which the caller may optionally
+set in the handle. It is printed in various places, allowing
+the current handle to be identified in debugging output.
+
+One important place is when tracing is enabled. If the
+identifier string is not an empty string, then trace messages
+change from this:
+
+ libguestfs: trace: get_tmpdir
+ libguestfs: trace: get_tmpdir = \"/tmp\"
+
+to this:
+
+ libguestfs: trace: ID: get_tmpdir
+ libguestfs: trace: ID: get_tmpdir = \"/tmp\"
+
+where C<ID> is the identifier string set by this call.
+
+The identifier must only contain alphanumeric ASCII characters,
+underscore and minus sign. The default is the empty string.
+
+See also C<guestfs_set_program>, C<guestfs_set_trace>,
+C<guestfs_get_identifier>" };
+
+ { defaults with
+ name = "get_identifier"; added = (1, 31, 14);
+ style = RConstString "identifier", [], [];
+ blocking = false;
+ tests = [
+ InitNone, Always, TestRun (
+ [["get_identifier"]]), []
+ ];
+ shortdesc = "get the handle identifier";
+ longdesc = "\
+Get the handle identifier. See C<guestfs_set_identifier>." };
+
]
(* daemon_functions are any functions which cause some action
diff --git a/src/events.c b/src/events.c
index d5efefe..5fed0c0 100644
--- a/src/events.c
+++ b/src/events.c
@@ -20,6 +20,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <assert.h>
#include "c-ctype.h"
@@ -136,7 +137,7 @@ guestfs_int_call_callbacks_message (guestfs_h *g, uint64_t
event,
/* APPLIANCE => <buf>
* LIBRARY => libguestfs: <buf>\n
* WARNING => libguestfs: warning: <buf>\n
- * TRACE => libguestfs: trace: <buf>\n (RHBZ#673479)
+ * TRACE => libguestfs: trace: [<ID>:] <buf>\n
(RHBZ#673479)
*/
if (event != GUESTFS_EVENT_APPLIANCE)
@@ -145,8 +146,13 @@ guestfs_int_call_callbacks_message (guestfs_h *g, uint64_t
event,
if (event == GUESTFS_EVENT_WARNING)
fputs ("warning: ", stderr);
- if (event == GUESTFS_EVENT_TRACE)
+ if (event == GUESTFS_EVENT_TRACE) {
fputs ("trace: ", stderr);
+ if (STRNEQ (g->identifier, "")) {
+ fputs (g->identifier, stderr);
+ fputs (": ", stderr);
+ }
+ }
/* Special or non-printing characters in the buffer must be
* escaped (RHBZ#731744). The buffer can contain any 8 bit
diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h
index 72f9968..34b5f1d 100644
--- a/src/guestfs-internal.h
+++ b/src/guestfs-internal.h
@@ -371,6 +371,7 @@ struct guestfs_h
struct hv_param *hv_params; /* Extra hv parameters. */
char *program; /* Program name. */
+ char *identifier; /* Handle identifier. */
/* Array of drives added by add-drive* APIs.
*
diff --git a/src/handle.c b/src/handle.c
index e2d0aa3..ff109ea 100644
--- a/src/handle.c
+++ b/src/handle.c
@@ -32,6 +32,7 @@
#include "glthread/lock.h"
#include "ignore-value.h"
+#include "c-ctype.h"
#include "guestfs.h"
#include "guestfs-internal.h"
@@ -128,6 +129,9 @@ guestfs_create_flags (unsigned flags, ...)
#endif
if (!g->program) goto error;
+ g->identifier = strdup ("");
+ if (!g->identifier) goto error;
+
if (guestfs_int_set_backend (g, DEFAULT_BACKEND) == -1) {
warning (g, _("libguestfs was built with an invalid default backend,
using 'direct' instead"));
if (guestfs_int_set_backend (g, "direct") == -1) {
@@ -667,6 +671,34 @@ guestfs_impl_get_program (guestfs_h *g)
}
int
+guestfs_impl_set_identifier (guestfs_h *g, const char *identifier)
+{
+ size_t i, len;
+
+ /* Check the identifier contains only permitted characters. */
+ len = strlen (identifier);
+ for (i = 0; i < len; ++i) {
+ char c = identifier[i];
+
+ if (!c_isalnum (c) && c != '_' && c != '-')
{
+ error (g, _("identifier must contain only alphanumeric characters,
underscore or minus sign"));
+ return -1;
+ }
+ }
+
+ free (g->identifier);
+ g->identifier = safe_strdup (g, identifier);
+
+ return 0;
+}
+
+const char *
+guestfs_impl_get_identifier (guestfs_h *g)
+{
+ return g->identifier;
+}
+
+int
guestfs_impl_set_backend (guestfs_h *g, const char *method)
{
if (guestfs_int_set_backend (g, method) == -1) {
diff --git a/src/launch.c b/src/launch.c
index 99c5582..ddd7091 100644
--- a/src/launch.c
+++ b/src/launch.c
@@ -75,6 +75,8 @@ guestfs_impl_launch (guestfs_h *g)
CLEANUP_FREE char *backend = guestfs_get_backend (g);
debug (g, "launch: program=%s", g->program);
+ if (STRNEQ (g->identifier, ""))
+ debug (g, "launch: identifier=%s", g->identifier);
debug (g, "launch:
version=%"PRIi64".%"PRIi64".%"PRIi64"%s",
v->major, v->minor, v->release, v->extra);
@@ -359,6 +361,7 @@ guestfs_int_appliance_command_line (guestfs_h *g, const char
*appliance_dev,
"%s" /* verbose */
"%s" /* network */
" TERM=%s" /* TERM environment variable */
+ "%s%s" /* handle identifier */
"%s%s", /* append */
#ifdef __arm__
g->memsize,
@@ -369,6 +372,8 @@ guestfs_int_appliance_command_line (guestfs_h *g, const char
*appliance_dev,
g->verbose ? " guestfs_verbose=1" : "",
g->enable_network ? " guestfs_network=1" : "",
term ? term : "linux",
+ STRNEQ (g->identifier, "") ? " guestfs_identifier="
: "",
+ g->identifier,
g->append ? " " : "", g->append ? g->append :
"");
return ret;
--
2.5.0
Richard W.M. Jones
2015-Oct-07 17:29 UTC
[Libguestfs] [PATCH 2/2] Add the thread identifier to various multi-threaded programs and tests.
---
df/parallel.c | 6 ++++++
src/guestfs.pod | 3 +++
tests/mount-local/test-parallel-mount-local.c | 2 ++
tests/parallel/test-parallel.c | 6 ++++++
4 files changed, 17 insertions(+)
diff --git a/df/parallel.c b/df/parallel.c
index 2d1d1d3..114cc27 100644
--- a/df/parallel.c
+++ b/df/parallel.c
@@ -149,6 +149,7 @@ worker_thread (void *thread_data_vp)
size_t output_len = 0;
guestfs_h *g;
int err;
+ char id[64];
/* Take the next domain from the list. */
if (thread_data->verbose)
@@ -191,6 +192,11 @@ worker_thread (void *thread_data_vp)
return &thread_data->r;
}
+ /* Set the handle identifier so we can tell threads apart. */
+ snprintf (id, sizeof id, "thread_%zu_domain_%zu",
+ thread_data->thread_num, i);
+ guestfs_set_identifier (g, id);
+
/* Copy some settings from the options guestfs handle. */
guestfs_set_trace (g, thread_data->trace);
guestfs_set_verbose (g, thread_data->verbose);
diff --git a/src/guestfs.pod b/src/guestfs.pod
index 248a4d0..349aa8d 100644
--- a/src/guestfs.pod
+++ b/src/guestfs.pod
@@ -1328,6 +1328,9 @@ safe to be called from multiple threads without a mutex.
See the graphical program guestfs-browser for one possible
architecture for multithreaded programs using libvirt and libguestfs.
+Use L</guestfs_set_identifier> to make it simpler to identify threads
+in trace output.
+
=head2 PATH
Libguestfs needs a supermin appliance, which it finds by looking along
diff --git a/tests/mount-local/test-parallel-mount-local.c
b/tests/mount-local/test-parallel-mount-local.c
index 0210330..873d20a 100644
--- a/tests/mount-local/test-parallel-mount-local.c
+++ b/tests/mount-local/test-parallel-mount-local.c
@@ -177,6 +177,8 @@ start_thread (void *statevp)
pthread_exit (&state->exit_status);
}
+ guestfs_set_identifier (g, state->mp);
+
if (guestfs_add_drive_scratch (g, 512*1024*1024, -1) == -1)
goto error;
if (guestfs_launch (g) == -1)
diff --git a/tests/parallel/test-parallel.c b/tests/parallel/test-parallel.c
index d018ec7..85182f2 100644
--- a/tests/parallel/test-parallel.c
+++ b/tests/parallel/test-parallel.c
@@ -43,6 +43,7 @@
#define NR_THREADS 5
struct thread_state {
+ size_t thread_num; /* Thread number. */
pthread_t thread; /* Thread handle. */
int exit_status; /* Thread exit status. */
};
@@ -89,6 +90,7 @@ main (int argc, char *argv[])
sigaction (SIGQUIT, &sa, NULL);
for (i = 0; i < NR_THREADS; ++i) {
+ threads[i].thread_num = i;
/* Start the thread. */
r = pthread_create (&threads[i].thread, NULL, start_thread,
&threads[i]);
@@ -117,6 +119,7 @@ start_thread (void *statevp)
struct thread_state *state = statevp;
guestfs_h *g;
time_t start_t, t;
+ char id[64];
time (&start_t);
@@ -133,6 +136,9 @@ start_thread (void *statevp)
pthread_exit (&state->exit_status);
}
+ snprintf (id, sizeof id, "%zu", state->thread_num);
+ guestfs_set_identifier (g, id);
+
if (guestfs_add_drive_opts (g, "/dev/null",
GUESTFS_ADD_DRIVE_OPTS_FORMAT, "raw",
GUESTFS_ADD_DRIVE_OPTS_READONLY, 1,
--
2.5.0
Maybe Matching Threads
- [PATCH 0/5] Use less stack.
- [nbdkit PATCH 0/4] thread-safety issues prior to parallel handling
- [PATCH] tests/c-api: Allow the C API tests to run in parallel.
- [PATCH nbdkit 1/2] nbd: Fix -Werror=maybe-uninitialized warning.
- About memory index/search in multithread program