[ltt-dev] [UST PATCH] Rename libustd to libustconsumer and ustd to ust-consumerd
Nils Carlson
nils.carlson at ericsson.com
Wed Jan 5 09:13:00 EST 2011
If nobody protests quickly I will pull this patch so I can go on to work
on more fun things... :-)
Mathieu, any comments?
/Nils
Nils Carlson wrote:
> This is a fargoing but necessary renaming of some ust components.
> The point of the renaming is to allow for a new daemon, ustd, which
> will be able to keep track of tracing sessions and connect applications
> with consumers. Also, the current names were non-sensical.
>
> This patch is a step on the way towards creating a session daemon
> that can connect trace producers and consumers in a nice way.
>
> Signed-off-by: Nils Carlson <nils.carlson at ericsson.com>
> ---
> Makefile.am | 2 +-
> README | 10 +-
> TODO | 2 +-
> configure.ac | 4 +-
> doc/Makefile.am | 2 +-
> doc/info/ust.texi | 10 +-
> doc/man/Makefile.am | 4 +-
> doc/man/ust-consumerd.1 | 51 +++
> doc/man/ust-consumerd.1.md | 44 ++
> doc/man/ustctl.1 | 4 +-
> doc/man/ustctl.1.md | 4 +-
> doc/man/ustd.1 | 51 ---
> doc/man/ustd.1.md | 44 --
> doc/man/usttrace.1 | 2 +-
> doc/man/usttrace.1.md | 2 +-
> include/Makefile.am | 2 +-
> include/ust/ustconsumer.h | 287 +++++++++++++
> include/ust/ustd.h | 287 -------------
> libust/tracectl.c | 14 +-
> libustcmd/ustcmd.c | 2 +-
> libustconsumer/Makefile.am | 16 +
> libustconsumer/libustconsumer.c | 891 +++++++++++++++++++++++++++++++++++++++
> libustconsumer/lowlevel.c | 143 +++++++
> libustconsumer/lowlevel.h | 35 ++
> libustd/Makefile.am | 17 -
> libustd/libustd.c | 891 ---------------------------------------
> libustd/lowlevel.c | 143 -------
> libustd/lowlevel.h | 35 --
> tests/manual_mode_tracing.sh | 10 +-
> tests/runtests | 2 +-
> tests/valgrind_ust-consumerd.sh | 54 +++
> tests/valgrind_ustd.sh | 54 ---
> ust-consumerd/Makefile.am | 14 +
> ust-consumerd/README | 3 +
> ust-consumerd/ust-consumerd.c | 505 ++++++++++++++++++++++
> ustd/Makefile.am | 14 -
> ustd/README | 3 -
> ustd/ustd.c | 505 ----------------------
> usttrace | 46 +-
> 39 files changed, 2106 insertions(+), 2103 deletions(-)
> create mode 100644 doc/man/ust-consumerd.1
> create mode 100644 doc/man/ust-consumerd.1.md
> delete mode 100644 doc/man/ustd.1
> delete mode 100644 doc/man/ustd.1.md
> create mode 100644 include/ust/ustconsumer.h
> delete mode 100644 include/ust/ustd.h
> create mode 100644 libustconsumer/Makefile.am
> create mode 100644 libustconsumer/libustconsumer.c
> create mode 100644 libustconsumer/lowlevel.c
> create mode 100644 libustconsumer/lowlevel.h
> delete mode 100644 libustd/Makefile.am
> delete mode 100644 libustd/libustd.c
> delete mode 100644 libustd/lowlevel.c
> delete mode 100644 libustd/lowlevel.h
> create mode 100755 tests/valgrind_ust-consumerd.sh
> delete mode 100755 tests/valgrind_ustd.sh
> create mode 100644 ust-consumerd/Makefile.am
> create mode 100644 ust-consumerd/README
> create mode 100644 ust-consumerd/ust-consumerd.c
> delete mode 100644 ustd/Makefile.am
> delete mode 100644 ustd/README
> delete mode 100644 ustd/ustd.c
>
> diff --git a/Makefile.am b/Makefile.am
> index 5132d59..249bf02 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -5,7 +5,7 @@ ACLOCAL_AMFLAGS = -I config
> # libust and '.' (that contains the linker script). However, '.'
> # must be installed after libust so it can overwrite libust.so with
> # the linker script.
> -SUBDIRS = snprintf libustcomm libustcmd libust . tests libustinstr-malloc libustd ustd ustctl libustfork include doc
> +SUBDIRS = snprintf libustcomm libustcmd libust . tests libustinstr-malloc libustconsumer ust-consumerd ustctl libustfork include doc
>
> EXTRA_DIST = libust.ldscript.in libust-initializer.c libust-initializer.h
> dist_bin_SCRIPTS = usttrace
> diff --git a/README b/README
> index 8eaf618..a381c95 100644
> --- a/README
> +++ b/README
> @@ -61,7 +61,7 @@ PACKAGE CONTENTS:
> - include
> The public header files that will be installed on the system.
>
> - - ustd
> + - ust-consumerd
> The daemon that collects trace data and writes it to the disk.
>
> - doc
> @@ -83,8 +83,12 @@ PACKAGE CONTENTS:
> A library to control tracing in other processes. Used by ustctl.
>
> - libustcomm
> - A static library shared between libust, ustd and libustcmd, that provides
> - functions that allow these components to communicate together.
> + A static library shared between libust, ust-consumerd and libustcmd, that
> + provides functions that allow these components to communicate together.
> +
> + - libustconsumer
> + A library to create ust consumers by registering callbacks, used by
> + ust-consumerd.
>
> - snprintf
> An asynchronous signal-safe version of snprintf.
> diff --git a/TODO b/TODO
> index 46d5b64..0d07589 100644
> --- a/TODO
> +++ b/TODO
> @@ -19,7 +19,7 @@
> - save_registers: save them only when the marker is active (complicated because we need to know their value at the address that is put in struct marker)
> - make streaming work, including periodical flush
> - make a system (signal-based?) that allow the listener thread to not be started initially
> -- ustd should work as a pool of threads
> +- ust-consumerd should work as a pool of threads
> - support more than one marker with the same channel and name on the same line?
> - make a mode where the listener thread can poll buffers to check if they are ready to be collected
> This is to guarantee there will never be a system call in the tracing path. Currently there is a system
> diff --git a/configure.ac b/configure.ac
> index 189ab12..b6cf946 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -129,8 +129,8 @@ AC_CONFIG_FILES([
> tests/ustcmd_function_tests/Makefile
> libustinstr-malloc/Makefile
> libustfork/Makefile
> - libustd/Makefile
> - ustd/Makefile
> + libustconsumer/Makefile
> + ust-consumerd/Makefile
> ustctl/Makefile
> libustcomm/Makefile
> libustcmd/Makefile
> diff --git a/doc/Makefile.am b/doc/Makefile.am
> index 37a55ac..463203c 100644
> --- a/doc/Makefile.am
> +++ b/doc/Makefile.am
> @@ -1 +1 @@
> -SUBDIRS = man info
> \ No newline at end of file
> +SUBDIRS = man info
> diff --git a/doc/info/ust.texi b/doc/info/ust.texi
> index e0565f3..a0ccdf1 100644
> --- a/doc/info/ust.texi
> +++ b/doc/info/ust.texi
> @@ -92,7 +92,7 @@ Components licensed as GPL v2:
> @itemize @bullet
> @item ustctl
> @item libustcmd
> - at item ustd
> + at item ust-consumerd
> @end itemize
>
> @node Supported platforms
> @@ -112,7 +112,7 @@ The following packages are required:
> @item
> ust
>
> -This contains the tracing library, the ustd daemon, trace control tools
> +This contains the tracing library, the ust-consumerd daemon, trace control tools
> and other helper tools.
>
> Repository: @url{http://git.dorsal.polymtl.ca}
> @@ -385,11 +385,11 @@ First the daemon must be started.
> # Make sure the directory for the communication sockets exists.
> $ mkdir /tmp/ustsocks
>
> -# Make sure the directory where ustd will write the trace exists.
> +# Make sure the directory where ust-consumerd will write the trace exists.
> $ mkdir /tmp/trace
>
> # Start the daemon
> -$ ustd
> +$ ust-consumerd
>
> # We assume the program we want to trace is already running and that
> # it has pid 1234.
> @@ -543,7 +543,7 @@ the application (or library) being linked to libust.
> Libust is initialized by a constructor, which by definition runs before the
> @code{main()} function of the application starts. This constructor creates a
> thread called the @emph{listener thread}. The listener thread initializes a
> -named socket and waits for connections for ustd or ustctl.
> +named socket and waits for connections for ust-consumerd or ustctl.
>
> Libust-specific code may:
> @itemize @bullet
> diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am
> index 7e18b8e..5adbba4 100644
> --- a/doc/man/Makefile.am
> +++ b/doc/man/Makefile.am
> @@ -1,2 +1,2 @@
> -EXTRA_DIST = ustctl.1 ustd.1 usttrace.1
> -man_MANS = ustctl.1 ustd.1 usttrace.1
> +EXTRA_DIST = ustctl.1 ust-consumerd.1 usttrace.1
> +man_MANS = ustctl.1 ust-consumerd.1 usttrace.1
> diff --git a/doc/man/ust-consumerd.1 b/doc/man/ust-consumerd.1
> new file mode 100644
> index 0000000..c6ce6a4
> --- /dev/null
> +++ b/doc/man/ust-consumerd.1
> @@ -0,0 +1,51 @@
> +.\" generated with Ronn/v0.5
> +.\" http://github.com/rtomayko/ronn/
> +.
> +.TH "UST-CONSUMERD" "1" "May 2010" "" ""
> +.
> +.SH "NAME"
> +\fBust-consumerd\fR \-\- a daemon that collects trace data and writes it to the disk
> +.
> +.SH "SYNOPSIS"
> +\fBust-consumerd\fR [\fIoptions\fR]
> +.
> +.SH "DESCRIPTION"
> +\fBust-consumerd\fR is a program that collects trace data and writes it to the disk.
> +.
> +.SH "OPTIONS"
> +These programs follow the usual GNU command line syntax, with long options
> +starting with two dashes(`\-'). A summary of options is included below.
> +.
> +.TP
> +\fB\-h\fR, \fB\-\-help\fR
> +Show summary of options.
> +.
> +.TP
> +\fB\-o\fR \fIDIR\fR
> +Specify the directory where to output the traces.
> +.
> +.TP
> +\fB\-s\fR \fIPATH\fR
> +Specify the path to use for the daemon socket.
> +.
> +.TP
> +\fB\-d\fR
> +Start as a daemon.
> +.
> +.TP
> +\fB\-p\fR, \fB\-\-pidfile\fR=\fIFILE\fR
> +Write the PID in this file (when using \-d).
> +.
> +.TP
> +\fB\-V\fR, \fB\-\-version\fR
> +Show version of program.
> +.
> +.SH "SEE ALSO"
> +ustctl(1), usttrace(1)
> +.
> +.SH "AUTHOR"
> +\fBust-consumerd\fR was written by Pierre\-Marc Fournier.
> +.
> +.P
> +This manual page was written by Jon Bernard <jbernard at debian.org>, for
> +the Debian project (and may be used by others).
> diff --git a/doc/man/ust-consumerd.1.md b/doc/man/ust-consumerd.1.md
> new file mode 100644
> index 0000000..1b93f47
> --- /dev/null
> +++ b/doc/man/ust-consumerd.1.md
> @@ -0,0 +1,44 @@
> +ust-consumerd(1) -- a daemon that collects trace data and writes it to the disk
> +======================================================================
> +
> +## SYNOPSIS
> +
> +`ust-consumerd` [<options>]
> +
> +## DESCRIPTION
> +
> +`ust-consumerd` is a program that collects trace data and writes it to the disk.
> +
> +## OPTIONS
> +
> +These programs follow the usual GNU command line syntax, with long options
> +starting with two dashes(`-'). A summary of options is included below.
> +
> + * `-h`, `--help`:
> + Show summary of options.
> +
> + * `-o` <DIR>:
> + Specify the directory where to output the traces.
> +
> + * `-s` <PATH>:
> + Specify the path to use for the daemon socket.
> +
> + * `-d`:
> + Start as a daemon.
> +
> + * `-p`, `--pidfile`=<FILE>:
> + Write the PID in this file (when using -d).
> +
> + * `-V`, `--version`:
> + Show version of program.
> +
> +## SEE ALSO
> +
> +ustctl(1), usttrace(1)
> +
> +## AUTHOR
> +
> +`ust-consumerd` was written by Pierre-Marc Fournier.
> +
> +This manual page was written by Jon Bernard <jbernard at debian.org>, for
> +the Debian project (and may be used by others).
> diff --git a/doc/man/ustctl.1 b/doc/man/ustctl.1
> index 4f171c6..b0f97d9 100644
> --- a/doc/man/ustctl.1
> +++ b/doc/man/ustctl.1
> @@ -114,7 +114,7 @@ have flushed to the disk the full contents of the buffer yet.
> .P
> Finally, when \fB\-\-destroy\-trace\fR is used, the trace buffers are unallocated.
> However, the memory may not be effectively freed until the daemon finishes to
> -collect them. When the trace is being collected by \fBustd\fR, this command
> +collect them. When the trace is being collected by \fBust-consumerd\fR, this command
> guarantees its full contents is flushed to the disk.
> .
> .SH "STRUCTURE OF A TRACE"
> @@ -139,7 +139,7 @@ for a given channel may be chosen with \fB\-\-set\-subbuf\-size\fR while the sub
> count is set with \fB\-\-set\-subbuf\-num\fR.
> .
> .SH "SEE ALSO"
> -usttrace(1), ustd(1)
> +usttrace(1), ust-consumerd(1)
> .
> .SH "AUTHOR"
> \fBustctl\fR was written by Pierre\-Marc Fournier.
> diff --git a/doc/man/ustctl.1.md b/doc/man/ustctl.1.md
> index 208e1dd..c8ad1f1 100644
> --- a/doc/man/ustctl.1.md
> +++ b/doc/man/ustctl.1.md
> @@ -92,7 +92,7 @@ have flushed to the disk the full contents of the buffer yet.
>
> Finally, when `--destroy-trace` is used, the trace buffers are unallocated.
> However, the memory may not be effectively freed until the daemon finishes to
> -collect them. When the trace is being collected by `ustd`, this command
> +collect them. When the trace is being collected by `ust-consumerd`, this command
> guarantees its full contents is flushed to the disk.
>
> ## STRUCTURE OF A TRACE
> @@ -118,7 +118,7 @@ count is set with `--set-subbuf-num`.
>
> ## SEE ALSO
>
> -usttrace(1), ustd(1)
> +usttrace(1), ust-consumerd(1)
>
> ## AUTHOR
>
> diff --git a/doc/man/ustd.1 b/doc/man/ustd.1
> deleted file mode 100644
> index f423978..0000000
> --- a/doc/man/ustd.1
> +++ /dev/null
> @@ -1,51 +0,0 @@
> -.\" generated with Ronn/v0.5
> -.\" http://github.com/rtomayko/ronn/
> -.
> -.TH "USTD" "1" "May 2010" "" ""
> -.
> -.SH "NAME"
> -\fBustd\fR \-\- a daemon that collects trace data and writes it to the disk
> -.
> -.SH "SYNOPSIS"
> -\fBustd\fR [\fIoptions\fR]
> -.
> -.SH "DESCRIPTION"
> -\fBustd\fR is a program that collects trace data and writes it to the disk.
> -.
> -.SH "OPTIONS"
> -These programs follow the usual GNU command line syntax, with long options
> -starting with two dashes(`\-'). A summary of options is included below.
> -.
> -.TP
> -\fB\-h\fR, \fB\-\-help\fR
> -Show summary of options.
> -.
> -.TP
> -\fB\-o\fR \fIDIR\fR
> -Specify the directory where to output the traces.
> -.
> -.TP
> -\fB\-s\fR \fIPATH\fR
> -Specify the path to use for the daemon socket.
> -.
> -.TP
> -\fB\-d\fR
> -Start as a daemon.
> -.
> -.TP
> -\fB\-p\fR, \fB\-\-pidfile\fR=\fIFILE\fR
> -Write the PID in this file (when using \-d).
> -.
> -.TP
> -\fB\-V\fR, \fB\-\-version\fR
> -Show version of program.
> -.
> -.SH "SEE ALSO"
> -ustctl(1), usttrace(1)
> -.
> -.SH "AUTHOR"
> -\fBustd\fR was written by Pierre\-Marc Fournier.
> -.
> -.P
> -This manual page was written by Jon Bernard <jbernard at debian.org>, for
> -the Debian project (and may be used by others).
> diff --git a/doc/man/ustd.1.md b/doc/man/ustd.1.md
> deleted file mode 100644
> index 296d1c4..0000000
> --- a/doc/man/ustd.1.md
> +++ /dev/null
> @@ -1,44 +0,0 @@
> -ustd(1) -- a daemon that collects trace data and writes it to the disk
> -======================================================================
> -
> -## SYNOPSIS
> -
> -`ustd` [<options>]
> -
> -## DESCRIPTION
> -
> -`ustd` is a program that collects trace data and writes it to the disk.
> -
> -## OPTIONS
> -
> -These programs follow the usual GNU command line syntax, with long options
> -starting with two dashes(`-'). A summary of options is included below.
> -
> - * `-h`, `--help`:
> - Show summary of options.
> -
> - * `-o` <DIR>:
> - Specify the directory where to output the traces.
> -
> - * `-s` <PATH>:
> - Specify the path to use for the daemon socket.
> -
> - * `-d`:
> - Start as a daemon.
> -
> - * `-p`, `--pidfile`=<FILE>:
> - Write the PID in this file (when using -d).
> -
> - * `-V`, `--version`:
> - Show version of program.
> -
> -## SEE ALSO
> -
> -ustctl(1), usttrace(1)
> -
> -## AUTHOR
> -
> -`ustd` was written by Pierre-Marc Fournier.
> -
> -This manual page was written by Jon Bernard <jbernard at debian.org>, for
> -the Debian project (and may be used by others).
> diff --git a/doc/man/usttrace.1 b/doc/man/usttrace.1
> index e789e45..a56cfc4 100644
> --- a/doc/man/usttrace.1
> +++ b/doc/man/usttrace.1
> @@ -91,7 +91,7 @@ Specify the number of subbuffers.
> Print the location of the last trace saved in the usttrace output directory.
> .
> .SH "SEE ALSO"
> -ustctl(1), ustd(1)
> +ustctl(1), ust-consumerd(1)
> .
> .SH "AUTHOR"
> \fBusttrace\fR was written by Pierre\-Marc Fournier.
> diff --git a/doc/man/usttrace.1.md b/doc/man/usttrace.1.md
> index 34acb36..75cff9a 100644
> --- a/doc/man/usttrace.1.md
> +++ b/doc/man/usttrace.1.md
> @@ -64,7 +64,7 @@ starting with two dashes(`-'). A summary of options is included below.
>
> ## SEE ALSO
>
> -ustctl(1), ustd(1)
> +ustctl(1), ust-consumerd(1)
>
>
> ## AUTHOR
> diff --git a/include/Makefile.am b/include/Makefile.am
> index 0ace775..400e8b1 100644
> --- a/include/Makefile.am
> +++ b/include/Makefile.am
> @@ -18,6 +18,6 @@ nobase_include_HEADERS = \
> ust/kcompat/types.h \
> ust/kcompat/stringify.h \
> ust/ustcmd.h \
> - ust/ustd.h
> + ust/ustconsumer.h
>
> noinst_HEADERS = share.h usterr.h ust_snprintf.h
> diff --git a/include/ust/ustconsumer.h b/include/ust/ustconsumer.h
> new file mode 100644
> index 0000000..e07b75e
> --- /dev/null
> +++ b/include/ust/ustconsumer.h
> @@ -0,0 +1,287 @@
> +/*
> + * libustconsumer header file
> + *
> + * Copyright 2005-2010 -
> + * Mathieu Desnoyers <mathieu.desnoyers at polymtl.ca>
> + * Copyright 2010-
> + * Oumarou Dicko <oumarou.dicko at polymtl.ca>
> + * Michael Sills-Lavoie <michael.sills-lavoie at polymtl.ca>
> + * Alexis Halle <alexis.halle at polymtl.ca>
> + *
> + * 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 _USTCONSUMER_H
> +#define _USTCONSUMER_H
> +
> +#include <pthread.h>
> +#include <dirent.h>
> +#include <ust/kcompat/kcompat.h>
> +#include <urcu/list.h>
> +
> +#define USTCONSUMER_DEFAULT_TRACE_PATH "/tmp/usttrace"
> +
> +struct ustcomm_sock;
> +
> +struct buffer_info {
> + char *name;
> + char *trace;
> + char *channel;
> + int channel_cpu;
> +
> + pid_t pid;
> + int app_sock;
> + /* The pipe file descriptor */
> + int pipe_fd;
> +
> + int shmid;
> + int bufstruct_shmid;
> +
> + /* the buffer memory */
> + void *mem;
> + /* buffer size */
> + int memlen;
> + /* number of subbuffers in buffer */
> + int n_subbufs;
> + /* size of each subbuffer */
> + int subbuf_size;
> +
> + /* the buffer information struct */
> + void *bufstruct_mem;
> +
> + long consumed_old;
> +
> + s64 pidunique;
> +
> + void *user_data;
> +};
> +
> +struct ustconsumer_callbacks;
> +
> +/**
> + * struct ustconsumer_instance - Contains the data associated with a trace instance.
> + * The lib user can read but MUST NOT change any attributes but callbacks.
> + * @callbacks: Contains the necessary callbacks for a tracing session.
> + */
> +struct ustconsumer_instance {
> + struct ustconsumer_callbacks *callbacks;
> + int quit_program;
> + int is_init;
> + struct cds_list_head connections;
> + int epoll_fd;
> + struct ustcomm_sock *listen_sock;
> + char *sock_path;
> + pthread_mutex_t mutex;
> + int active_buffers;
> +};
> +
> +/**
> +* struct ustconsumer_callbacks - Contains the necessary callbacks for a tracing
> +* session. The user can set the unnecessary functions to NULL if he does not
> +* need them.
> +*/
> +struct ustconsumer_callbacks {
> + /**
> + * on_open_buffer - Is called after a buffer is attached to process memory
> + *
> + * @data: pointer to the callbacks structure that has been passed to the
> + * library.
> + * @buf: structure that contains the data associated with the buffer
> + *
> + * Returns 0 if the callback succeeds else not 0.
> + *
> + * It has to be thread safe, because it is called by many threads.
> + */
> + int (*on_open_buffer)(struct ustconsumer_callbacks *data,
> + struct buffer_info *buf);
> +
> + /**
> + * on_close_buffer - Is called after a buffer is detached from process memory
> + *
> + * @data: pointer to the callbacks structure that has been passed to the
> + * library.
> + * @buf: structure that contains the data associated with the buffer
> + *
> + * Returns 0 if the callback succeeds else not 0.
> + *
> + * It has to be thread safe, because it is called by many threads.
> + */
> + int (*on_close_buffer)(struct ustconsumer_callbacks *data,
> + struct buffer_info *buf);
> +
> + /**
> + * on_read_subbuffer - Is called after a subbuffer is a reserved.
> + *
> + * @data: pointer to the callbacks structure that has been passed to the
> + * library.
> + * @buf: structure that contains the data associated with the buffer
> + *
> + * Returns 0 if the callback succeeds else not 0.
> + *
> + * It has to be thread safe, because it is called by many threads.
> + */
> + int (*on_read_subbuffer)(struct ustconsumer_callbacks *data,
> + struct buffer_info *buf);
> +
> + /**
> + * on_read_partial_subbuffer - Is called when an incomplete subbuffer
> + * is being salvaged from an app crash
> + *
> + * @data: pointer to the callbacks structure that has been passed to the
> + * library.
> + * @buf: structure that contains the data associated with the buffer
> + * @subbuf_index: index of the subbuffer to read in the buffer
> + * @valid_length: number of bytes considered safe to read
> + *
> + * Returns 0 if the callback succeeds else not 0.
> + *
> + * It has to be thread safe, because it is called by many threads.
> + */
> + int (*on_read_partial_subbuffer)(struct ustconsumer_callbacks *data,
> + struct buffer_info *buf,
> + long subbuf_index,
> + unsigned long valid_length);
> +
> + /**
> + * on_put_error - Is called when a put error has occured and the last
> + * subbuffer read is no longer safe to keep
> + *
> + * @data: pointer to the callbacks structure that has been passed to the
> + * library.
> + * @buf: structure that contains the data associated with the buffer
> + *
> + * Returns 0 if the callback succeeds else not 0.
> + *
> + * It has to be thread safe, because it is called by many threads.
> + */
> + int (*on_put_error)(struct ustconsumer_callbacks *data,
> + struct buffer_info *buf);
> +
> + /**
> + * on_new_thread - Is called when a new thread is created
> + *
> + * @data: pointer to the callbacks structure that has been passed to the
> + * library.
> + *
> + * Returns 0 if the callback succeeds else not 0.
> + *
> + * It has to be thread safe, because it is called by many threads.
> + */
> + int (*on_new_thread)(struct ustconsumer_callbacks *data);
> +
> + /**
> + * on_close_thread - Is called just before a thread is destroyed
> + *
> + * @data: pointer to the callbacks structure that has been passed to the
> + * library.
> + *
> + * Returns 0 if the callback succeeds else not 0.
> + *
> + * It has to be thread safe, because it is called by many threads.
> + */
> + int (*on_close_thread)(struct ustconsumer_callbacks *data);
> +
> + /**
> + * on_trace_end - Is called at the very end of the tracing session. At
> + * this time, everything has been closed and the threads have
> + * been destroyed.
> + *
> + * @instance: pointer to the instance structure that has been passed to
> + * the library.
> + *
> + * Returns 0 if the callback succeeds else not 0.
> + *
> + * After this callback is called, no other callback will be called
> + * again and the tracing instance will be deleted automatically by
> + * libustconsumer. After this call, the user must not use the libustconsumer instance.
> + */
> + int (*on_trace_end)(struct ustconsumer_instance *instance);
> +
> + /**
> + * The library's data.
> + */
> + void *user_data;
> +};
> +
> +/**
> + * ustconsumer_new_instance - Is called to create a new tracing session.
> + *
> + * @callbacks: Pointer to a callbacks structure that contain the user
> + * callbacks and data.
> + * @sock_path: Path to the socket used for communication with the traced app
> + *
> + * Returns the instance if the function succeeds else NULL.
> + */
> +struct ustconsumer_instance *
> +ustconsumer_new_instance(
> + struct ustconsumer_callbacks *callbacks, char *sock_path);
> +
> +/**
> + * ustconsumer_delete_instance - Is called to free a ustconsumer_instance struct
> + *
> + * @instance: The tracing session instance that needs to be freed.
> + *
> + * This function should only be called if the instance has not been started,
> + * as it will automatically be called at the end of ustconsumer_start_instance.
> + */
> +void ustconsumer_delete_instance(struct ustconsumer_instance *instance);
> +
> +/**
> + * ustconsumer_init_instance - Is called to initiliaze a new tracing session
> + *
> + * @instance: The tracing session instance that needs to be started.
> + *
> + * Returns 0 if the function succeeds.
> + *
> + * This function must be called between ustconsumer_new_instance and
> + * ustconsumer_start_instance. It sets up the communication between the library
> + * and the tracing application.
> + */
> +int ustconsumer_init_instance(struct ustconsumer_instance *instance);
> +
> +/**
> + * ustconsumer_start_instance - Is called to start a new tracing session.
> + *
> + * @instance: The tracing session instance that needs to be started.
> + *
> + * Returns 0 if the function succeeds.
> + *
> + * This is a blocking function. The caller will be blocked on it until the
> + * tracing session is stopped by the user using ustconsumer_stop_instance or until
> + * the traced application terminates
> + */
> +int ustconsumer_start_instance(struct ustconsumer_instance *instance);
> +
> +/**
> + * ustconsumer_stop_instance - Is called to stop a tracing session.
> + *
> + * @instance: The tracing session instance that needs to be stoped.
> + * @send_msg: If true, a message will be sent to the listening thread through
> + * the daemon socket to force it to return from the poll syscall
> + * and realize that it must close. This is not necessary if the
> + * instance is being stopped as part of an interrupt handler, as
> + * the interrupt itself will cause poll to return.
> + *
> + * Returns 0 if the function succeeds.
> + *
> + * This function returns immediately, it only tells libustconsumer to stop the
> + * instance. The on_trace_end callback will be called when the tracing session
> + * will really be stopped. The instance is deleted automatically by libustconsumer
> + * after on_trace_end is called.
> + */
> +int ustconsumer_stop_instance(struct ustconsumer_instance *instance, int send_msg);
> +
> +#endif /* _USTCONSUMER_H */
> +
> diff --git a/include/ust/ustd.h b/include/ust/ustd.h
> deleted file mode 100644
> index 6336e69..0000000
> --- a/include/ust/ustd.h
> +++ /dev/null
> @@ -1,287 +0,0 @@
> -/*
> - * libustd header file
> - *
> - * Copyright 2005-2010 -
> - * Mathieu Desnoyers <mathieu.desnoyers at polymtl.ca>
> - * Copyright 2010-
> - * Oumarou Dicko <oumarou.dicko at polymtl.ca>
> - * Michael Sills-Lavoie <michael.sills-lavoie at polymtl.ca>
> - * Alexis Halle <alexis.halle at polymtl.ca>
> - *
> - * 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 USTD_H
> -#define USTD_H
> -
> -#include <pthread.h>
> -#include <dirent.h>
> -#include <ust/kcompat/kcompat.h>
> -#include <urcu/list.h>
> -
> -#define USTD_DEFAULT_TRACE_PATH "/tmp/usttrace"
> -
> -struct ustcomm_sock;
> -
> -struct buffer_info {
> - char *name;
> - char *trace;
> - char *channel;
> - int channel_cpu;
> -
> - pid_t pid;
> - int app_sock;
> - /* The pipe file descriptor */
> - int pipe_fd;
> -
> - int shmid;
> - int bufstruct_shmid;
> -
> - /* the buffer memory */
> - void *mem;
> - /* buffer size */
> - int memlen;
> - /* number of subbuffers in buffer */
> - int n_subbufs;
> - /* size of each subbuffer */
> - int subbuf_size;
> -
> - /* the buffer information struct */
> - void *bufstruct_mem;
> -
> - long consumed_old;
> -
> - s64 pidunique;
> -
> - void *user_data;
> -};
> -
> -struct libustd_callbacks;
> -
> -/**
> - * struct libustd_instance - Contains the data associated with a trace instance.
> - * The lib user can read but MUST NOT change any attributes but callbacks.
> - * @callbacks: Contains the necessary callbacks for a tracing session.
> - */
> -struct libustd_instance {
> - struct libustd_callbacks *callbacks;
> - int quit_program;
> - int is_init;
> - struct cds_list_head connections;
> - int epoll_fd;
> - struct ustcomm_sock *listen_sock;
> - char *sock_path;
> - pthread_mutex_t mutex;
> - int active_buffers;
> -};
> -
> -/**
> -* struct libustd_callbacks - Contains the necessary callbacks for a tracing
> -* session. The user can set the unnecessary functions to NULL if he does not
> -* need them.
> -*/
> -struct libustd_callbacks {
> - /**
> - * on_open_buffer - Is called after a buffer is attached to process memory
> - *
> - * @data: pointer to the callbacks structure that has been passed to the
> - * library.
> - * @buf: structure that contains the data associated with the buffer
> - *
> - * Returns 0 if the callback succeeds else not 0.
> - *
> - * It has to be thread safe, because it is called by many threads.
> - */
> - int (*on_open_buffer)(struct libustd_callbacks *data,
> - struct buffer_info *buf);
> -
> - /**
> - * on_close_buffer - Is called after a buffer is detached from process memory
> - *
> - * @data: pointer to the callbacks structure that has been passed to the
> - * library.
> - * @buf: structure that contains the data associated with the buffer
> - *
> - * Returns 0 if the callback succeeds else not 0.
> - *
> - * It has to be thread safe, because it is called by many threads.
> - */
> - int (*on_close_buffer)(struct libustd_callbacks *data,
> - struct buffer_info *buf);
> -
> - /**
> - * on_read_subbuffer - Is called after a subbuffer is a reserved.
> - *
> - * @data: pointer to the callbacks structure that has been passed to the
> - * library.
> - * @buf: structure that contains the data associated with the buffer
> - *
> - * Returns 0 if the callback succeeds else not 0.
> - *
> - * It has to be thread safe, because it is called by many threads.
> - */
> - int (*on_read_subbuffer)(struct libustd_callbacks *data,
> - struct buffer_info *buf);
> -
> - /**
> - * on_read_partial_subbuffer - Is called when an incomplete subbuffer
> - * is being salvaged from an app crash
> - *
> - * @data: pointer to the callbacks structure that has been passed to the
> - * library.
> - * @buf: structure that contains the data associated with the buffer
> - * @subbuf_index: index of the subbuffer to read in the buffer
> - * @valid_length: number of bytes considered safe to read
> - *
> - * Returns 0 if the callback succeeds else not 0.
> - *
> - * It has to be thread safe, because it is called by many threads.
> - */
> - int (*on_read_partial_subbuffer)(struct libustd_callbacks *data,
> - struct buffer_info *buf,
> - long subbuf_index,
> - unsigned long valid_length);
> -
> - /**
> - * on_put_error - Is called when a put error has occured and the last
> - * subbuffer read is no longer safe to keep
> - *
> - * @data: pointer to the callbacks structure that has been passed to the
> - * library.
> - * @buf: structure that contains the data associated with the buffer
> - *
> - * Returns 0 if the callback succeeds else not 0.
> - *
> - * It has to be thread safe, because it is called by many threads.
> - */
> - int (*on_put_error)(struct libustd_callbacks *data,
> - struct buffer_info *buf);
> -
> - /**
> - * on_new_thread - Is called when a new thread is created
> - *
> - * @data: pointer to the callbacks structure that has been passed to the
> - * library.
> - *
> - * Returns 0 if the callback succeeds else not 0.
> - *
> - * It has to be thread safe, because it is called by many threads.
> - */
> - int (*on_new_thread)(struct libustd_callbacks *data);
> -
> - /**
> - * on_close_thread - Is called just before a thread is destroyed
> - *
> - * @data: pointer to the callbacks structure that has been passed to the
> - * library.
> - *
> - * Returns 0 if the callback succeeds else not 0.
> - *
> - * It has to be thread safe, because it is called by many threads.
> - */
> - int (*on_close_thread)(struct libustd_callbacks *data);
> -
> - /**
> - * on_trace_end - Is called at the very end of the tracing session. At
> - * this time, everything has been closed and the threads have
> - * been destroyed.
> - *
> - * @instance: pointer to the instance structure that has been passed to
> - * the library.
> - *
> - * Returns 0 if the callback succeeds else not 0.
> - *
> - * After this callback is called, no other callback will be called
> - * again and the tracing instance will be deleted automatically by
> - * libustd. After this call, the user must not use the libustd instance.
> - */
> - int (*on_trace_end)(struct libustd_instance *instance);
> -
> - /**
> - * The library's data.
> - */
> - void *user_data;
> -};
> -
> -/**
> - * libustd_new_instance - Is called to create a new tracing session.
> - *
> - * @callbacks: Pointer to a callbacks structure that contain the user
> - * callbacks and data.
> - * @sock_path: Path to the socket used for communication with the traced app
> - *
> - * Returns the instance if the function succeeds else NULL.
> - */
> -struct libustd_instance *
> -libustd_new_instance(
> - struct libustd_callbacks *callbacks, char *sock_path);
> -
> -/**
> - * libustd_delete_instance - Is called to free a libustd_instance struct
> - *
> - * @instance: The tracing session instance that needs to be freed.
> - *
> - * This function should only be called if the instance has not been started,
> - * as it will automatically be called at the end of libustd_start_instance.
> - */
> -void libustd_delete_instance(struct libustd_instance *instance);
> -
> -/**
> - * libustd_init_instance - Is called to initiliaze a new tracing session
> - *
> - * @instance: The tracing session instance that needs to be started.
> - *
> - * Returns 0 if the function succeeds.
> - *
> - * This function must be called between libustd_new_instance and
> - * libustd_start_instance. It sets up the communication between the library
> - * and the tracing application.
> - */
> -int libustd_init_instance(struct libustd_instance *instance);
> -
> -/**
> - * libustd_start_instance - Is called to start a new tracing session.
> - *
> - * @instance: The tracing session instance that needs to be started.
> - *
> - * Returns 0 if the function succeeds.
> - *
> - * This is a blocking function. The caller will be blocked on it until the
> - * tracing session is stopped by the user using libustd_stop_instance or until
> - * the traced application terminates
> - */
> -int libustd_start_instance(struct libustd_instance *instance);
> -
> -/**
> - * libustd_stop_instance - Is called to stop a tracing session.
> - *
> - * @instance: The tracing session instance that needs to be stoped.
> - * @send_msg: If true, a message will be sent to the listening thread through
> - * the daemon socket to force it to return from the poll syscall
> - * and realize that it must close. This is not necessary if the
> - * instance is being stopped as part of an interrupt handler, as
> - * the interrupt itself will cause poll to return.
> - *
> - * Returns 0 if the function succeeds.
> - *
> - * This function returns immediately, it only tells libustd to stop the
> - * instance. The on_trace_end callback will be called when the tracing session
> - * will really be stopped. The instance is deleted automatically by libustd
> - * after on_trace_end is called.
> - */
> -int libustd_stop_instance(struct libustd_instance *instance, int send_msg);
> -
> -#endif /* USTD_H */
> -
> diff --git a/libust/tracectl.c b/libust/tracectl.c
> index a7da945..b783c76 100644
> --- a/libust/tracectl.c
> +++ b/libust/tracectl.c
> @@ -122,10 +122,10 @@ static void print_trace_events(FILE *fp)
> unlock_trace_events();
> }
>
> -static int connect_ustd(void)
> +static int connect_ustconsumer(void)
> {
> int result, fd;
> - char default_daemon_path[] = SOCK_DIR "/ustd";
> + char default_daemon_path[] = SOCK_DIR "/ustconsumer";
> char *explicit_daemon_path, *daemon_path;
>
> explicit_daemon_path = getenv("UST_DAEMON_SOCKET");
> @@ -139,7 +139,7 @@ static int connect_ustd(void)
>
> result = ustcomm_connect_path(daemon_path, &fd);
> if (result < 0) {
> - WARN("connect_ustd failed, daemon_path: %s",
> + WARN("connect_ustconsumer failed, daemon_path: %s",
> daemon_path);
> return result;
> }
> @@ -194,12 +194,12 @@ static void inform_consumer_daemon(const char *trace_name)
> struct ust_trace *trace;
> const char *ch_name;
>
> - sock = connect_ustd();
> + sock = connect_ustconsumer();
> if (sock < 0) {
> return;
> }
>
> - DBG("Connected to ustd");
> + DBG("Connected to ustconsumer");
>
> ltt_lock_traces();
>
> @@ -1007,7 +1007,7 @@ static void process_client_cmd(struct ustcomm_header *recv_header,
> if (!sock_path_env) {
> result = ustcomm_pack_single_field(reply_header,
> sock_msg,
> - SOCK_DIR "/ustd");
> + SOCK_DIR "/ustconsumer");
>
> } else {
> result = ustcomm_pack_single_field(reply_header,
> @@ -1496,7 +1496,7 @@ static void stop_listener(void)
> }
>
> /* This destructor keeps the process alive for a few seconds in order
> - * to leave time to ustd to connect to its buffers. This is necessary
> + * to leave time for ustconsumer to connect to its buffers. This is necessary
> * for programs whose execution is very short. It is also useful in all
> * programs when tracing is started close to the end of the program
> * execution.
> diff --git a/libustcmd/ustcmd.c b/libustcmd/ustcmd.c
> index 2c16e75..62c117f 100644
> --- a/libustcmd/ustcmd.c
> +++ b/libustcmd/ustcmd.c
> @@ -104,7 +104,7 @@ pid_t *ustcmd_get_online_pids(void)
> }
>
> if (dirent->d_type != DT_DIR &&
> - !!strcmp(dirent->d_name, "ustd")) {
> + !!strcmp(dirent->d_name, "ust-consumer")) {
>
> sscanf(dirent->d_name, "%u", (unsigned int *) &ret[i]);
> /* FIXME: Here we previously called pid_is_online, which
> diff --git a/libustconsumer/Makefile.am b/libustconsumer/Makefile.am
> new file mode 100644
> index 0000000..1f87479
> --- /dev/null
> +++ b/libustconsumer/Makefile.am
> @@ -0,0 +1,16 @@
> +AM_CPPFLAGS = -I$(top_srcdir)/libust -I$(top_srcdir)/libustcomm \
> + -I$(top_srcdir)/include
> +AM_CFLAGS = -fno-strict-aliasing
> +
> +lib_LTLIBRARIES = libustconsumer.la
> +
> +libustconsumer_la_SOURCES = libustconsumer.c lowlevel.c lowlevel.h
> +
> +libustconsumer_la_LDFLAGS = -no-undefined -version-info 0:0:0
> +
> +libustconsumer_la_LIBADD = \
> + -lpthread \
> + $(top_builddir)/snprintf/libustsnprintf.la \
> + $(top_builddir)/libustcomm/libustcomm.la
> +
> +libustconsumer_la_CFLAGS = -fno-strict-aliasing
> diff --git a/libustconsumer/libustconsumer.c b/libustconsumer/libustconsumer.c
> new file mode 100644
> index 0000000..6cb3dbf
> --- /dev/null
> +++ b/libustconsumer/libustconsumer.c
> @@ -0,0 +1,891 @@
> +/* Copyright (C) 2009 Pierre-Marc Fournier
> + * 2010 Alexis Halle
> + *
> + * 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
> + */
> +
> +#define _GNU_SOURCE
> +
> +#include <sys/epoll.h>
> +#include <sys/shm.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <unistd.h>
> +#include <pthread.h>
> +#include <signal.h>
> +
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <errno.h>
> +#include <assert.h>
> +
> +#include <ust/ustconsumer.h>
> +#include "lowlevel.h"
> +#include "usterr.h"
> +#include "ustcomm.h"
> +
> +#define GET_SUBBUF_OK 1
> +#define GET_SUBBUF_DONE 0
> +#define GET_SUBBUF_DIED 2
> +
> +#define PUT_SUBBUF_OK 1
> +#define PUT_SUBBUF_DIED 0
> +#define PUT_SUBBUF_PUSHED 2
> +#define PUT_SUBBUF_DONE 3
> +
> +#define UNIX_PATH_MAX 108
> +
> +static int get_subbuffer(struct buffer_info *buf)
> +{
> + struct ustcomm_header _send_hdr, *send_hdr;
> + struct ustcomm_header _recv_hdr, *recv_hdr;
> + struct ustcomm_buffer_info _send_msg, _recv_msg;
> + struct ustcomm_buffer_info *send_msg, *recv_msg;
> + int result;
> +
> + send_hdr = &_send_hdr;
> + recv_hdr = &_recv_hdr;
> + send_msg = &_send_msg;
> + recv_msg = &_recv_msg;
> +
> + result = ustcomm_pack_buffer_info(send_hdr, send_msg, buf->trace,
> + buf->channel, buf->channel_cpu);
> + if (result < 0) {
> + return result;
> + }
> +
> + send_hdr->command = GET_SUBBUFFER;
> +
> + result = ustcomm_req(buf->app_sock, send_hdr, (char *)send_msg,
> + recv_hdr, (char *)recv_msg);
> + if ((result < 0 && (errno == ECONNRESET || errno == EPIPE)) ||
> + result == 0) {
> + DBG("app died while being traced");
> + return GET_SUBBUF_DIED;
> + } else if (result < 0) {
> + ERR("get_subbuffer: ustcomm_req failed");
> + return result;
> + }
> +
> + if (!recv_hdr->result) {
> + DBG("got subbuffer %s", buf->name);
> + buf->consumed_old = recv_msg->consumed_old;
> + return GET_SUBBUF_OK;
> + } else if (recv_hdr->result == -ENODATA) {
> + DBG("For buffer %s, the trace was not found. This likely means"
> + " it was destroyed by the user.", buf->name);
> + return GET_SUBBUF_DIED;
> + }
> +
> + DBG("error getting subbuffer %s", buf->name);
> + return recv_hdr->result;
> +}
> +
> +static int put_subbuffer(struct buffer_info *buf)
> +{
> + struct ustcomm_header _send_hdr, *send_hdr;
> + struct ustcomm_header _recv_hdr, *recv_hdr;
> + struct ustcomm_buffer_info _send_msg, *send_msg;
> + int result;
> +
> + send_hdr = &_send_hdr;
> + recv_hdr = &_recv_hdr;
> + send_msg = &_send_msg;
> +
> + result = ustcomm_pack_buffer_info(send_hdr, send_msg, buf->trace,
> + buf->channel, buf->channel_cpu);
> + if (result < 0) {
> + return result;
> + }
> +
> + send_hdr->command = PUT_SUBBUFFER;
> + send_msg->consumed_old = buf->consumed_old;
> +
> + result = ustcomm_req(buf->app_sock, send_hdr, (char *)send_msg,
> + recv_hdr, NULL);
> + if ((result < 0 && (errno == ECONNRESET || errno == EPIPE)) ||
> + result == 0) {
> + DBG("app died while being traced");
> + return PUT_SUBBUF_DIED;
> + } else if (result < 0) {
> + ERR("put_subbuffer: ustcomm_req failed");
> + return result;
> + }
> +
> + if (!recv_hdr->result) {
> + DBG("put subbuffer %s", buf->name);
> + return PUT_SUBBUF_OK;
> + } else if (recv_hdr->result == -ENODATA) {
> + DBG("For buffer %s, the trace was not found. This likely means"
> + " it was destroyed by the user.", buf->name);
> + return PUT_SUBBUF_DIED;
> + }
> +
> + DBG("error getting subbuffer %s", buf->name);
> + return recv_hdr->result;
> +}
> +
> +void decrement_active_buffers(void *arg)
> +{
> + struct ustconsumer_instance *instance = arg;
> + pthread_mutex_lock(&instance->mutex);
> + instance->active_buffers--;
> + pthread_mutex_unlock(&instance->mutex);
> +}
> +
> +static int get_pidunique(int sock, s64 *pidunique)
> +{
> + struct ustcomm_header _send_hdr, *send_hdr;
> + struct ustcomm_header _recv_hdr, *recv_hdr;
> + struct ustcomm_pidunique _recv_msg, *recv_msg;
> + int result;
> +
> + send_hdr = &_send_hdr;
> + recv_hdr = &_recv_hdr;
> + recv_msg = &_recv_msg;
> +
> + memset(send_hdr, 0, sizeof(*send_hdr));
> +
> + send_hdr->command = GET_PIDUNIQUE;
> + result = ustcomm_req(sock, send_hdr, NULL, recv_hdr, (char *)recv_msg);
> + if (result < 1) {
> + return -ENOTCONN;
> + }
> + if (recv_hdr->result < 0) {
> + ERR("App responded with error: %s", strerror(recv_hdr->result));
> + return recv_hdr->result;
> + }
> +
> + *pidunique = recv_msg->pidunique;
> +
> + return 0;
> +}
> +
> +static int get_buf_shmid_pipe_fd(int sock, struct buffer_info *buf,
> + int *buf_shmid, int *buf_struct_shmid,
> + int *buf_pipe_fd)
> +{
> + struct ustcomm_header _send_hdr, *send_hdr;
> + struct ustcomm_header _recv_hdr, *recv_hdr;
> + struct ustcomm_buffer_info _send_msg, *send_msg;
> + struct ustcomm_buffer_info _recv_msg, *recv_msg;
> + int result, recv_pipe_fd;
> +
> + send_hdr = &_send_hdr;
> + recv_hdr = &_recv_hdr;
> + send_msg = &_send_msg;
> + recv_msg = &_recv_msg;
> +
> + result = ustcomm_pack_buffer_info(send_hdr, send_msg, buf->trace,
> + buf->channel, buf->channel_cpu);
> + if (result < 0) {
> + ERR("Failed to pack buffer info");
> + return result;
> + }
> +
> + send_hdr->command = GET_BUF_SHMID_PIPE_FD;
> +
> + result = ustcomm_send(sock, send_hdr, (char *)send_msg);
> + if (result < 1) {
> + ERR("Failed to send request");
> + return -ENOTCONN;
> + }
> + result = ustcomm_recv_fd(sock, recv_hdr, (char *)recv_msg, &recv_pipe_fd);
> + if (result < 1) {
> + ERR("Failed to receive message and fd");
> + return -ENOTCONN;
> + }
> + if (recv_hdr->result < 0) {
> + ERR("App responded with error %s", strerror(recv_hdr->result));
> + return recv_hdr->result;
> + }
> +
> + *buf_shmid = recv_msg->buf_shmid;
> + *buf_struct_shmid = recv_msg->buf_struct_shmid;
> + *buf_pipe_fd = recv_pipe_fd;
> +
> + return 0;
> +}
> +
> +static int get_subbuf_num_size(int sock, struct buffer_info *buf,
> + int *subbuf_num, int *subbuf_size)
> +{
> + struct ustcomm_header _send_hdr, *send_hdr;
> + struct ustcomm_header _recv_hdr, *recv_hdr;
> + struct ustcomm_channel_info _send_msg, *send_msg;
> + struct ustcomm_channel_info _recv_msg, *recv_msg;
> + int result;
> +
> + send_hdr = &_send_hdr;
> + recv_hdr = &_recv_hdr;
> + send_msg = &_send_msg;
> + recv_msg = &_recv_msg;
> +
> + result = ustcomm_pack_channel_info(send_hdr, send_msg, buf->trace,
> + buf->channel);
> + if (result < 0) {
> + return result;
> + }
> +
> + send_hdr->command = GET_SUBBUF_NUM_SIZE;
> +
> + result = ustcomm_req(sock, send_hdr, (char *)send_msg,
> + recv_hdr, (char *)recv_msg);
> + if (result < 1) {
> + return -ENOTCONN;
> + }
> +
> + *subbuf_num = recv_msg->subbuf_num;
> + *subbuf_size = recv_msg->subbuf_size;
> +
> + return recv_hdr->result;
> +}
> +
> +
> +static int notify_buffer_mapped(int sock, struct buffer_info *buf)
> +{
> + struct ustcomm_header _send_hdr, *send_hdr;
> + struct ustcomm_header _recv_hdr, *recv_hdr;
> + struct ustcomm_buffer_info _send_msg, *send_msg;
> + int result;
> +
> + send_hdr = &_send_hdr;
> + recv_hdr = &_recv_hdr;
> + send_msg = &_send_msg;
> +
> + result = ustcomm_pack_buffer_info(send_hdr, send_msg, buf->trace,
> + buf->channel, buf->channel_cpu);
> + if (result < 0) {
> + return result;
> + }
> +
> + send_hdr->command = NOTIFY_BUF_MAPPED;
> +
> + result = ustcomm_req(sock, send_hdr, (char *)send_msg,
> + recv_hdr, NULL);
> + if (result < 1) {
> + return -ENOTCONN;
> + }
> +
> + return recv_hdr->result;
> +}
> +
> +
> +struct buffer_info *connect_buffer(struct ustconsumer_instance *instance, pid_t pid,
> + const char *trace, const char *channel,
> + int channel_cpu)
> +{
> + struct buffer_info *buf;
> + int result;
> + struct shmid_ds shmds;
> +
> + buf = (struct buffer_info *) zmalloc(sizeof(struct buffer_info));
> + if(buf == NULL) {
> + ERR("add_buffer: insufficient memory");
> + return NULL;
> + }
> +
> + buf->trace = strdup(trace);
> + if (!buf->trace) {
> + goto free_buf;
> + }
> +
> + buf->channel = strdup(channel);
> + if (!buf->channel) {
> + goto free_buf_trace;
> + }
> +
> + result = asprintf(&buf->name, "%s_%d", channel, channel_cpu);
> + if (result < 0 || buf->name == NULL) {
> + goto free_buf_channel;
> + }
> +
> + buf->channel_cpu = channel_cpu;
> + buf->pid = pid;
> +
> + result = ustcomm_connect_app(buf->pid, &buf->app_sock);
> + if(result) {
> + WARN("unable to connect to process, it probably died before we were able to connect");
> + goto free_buf_name;
> + }
> +
> + /* get pidunique */
> + result = get_pidunique(buf->app_sock, &buf->pidunique);
> + if (result < 0) {
> + ERR("Failed to get pidunique");
> + goto close_app_sock;
> + }
> +
> + /* get shmid and pipe fd */
> + result = get_buf_shmid_pipe_fd(buf->app_sock, buf, &buf->shmid,
> + &buf->bufstruct_shmid, &buf->pipe_fd);
> + if (result < 0) {
> + ERR("Failed to get buf_shmid and pipe_fd");
> + goto close_app_sock;
> + } else {
> + struct stat temp;
> + fstat(buf->pipe_fd, &temp);
> + if (!S_ISFIFO(temp.st_mode)) {
> + ERR("Didn't receive a fifo from the app");
> + goto close_app_sock;
> + }
> + }
> +
> +
> + /* get number of subbufs and subbuf size */
> + result = get_subbuf_num_size(buf->app_sock, buf, &buf->n_subbufs,
> + &buf->subbuf_size);
> + if (result < 0) {
> + ERR("Failed to get subbuf number and size");
> + goto close_fifo;
> + }
> +
> + /* attach memory */
> + buf->mem = shmat(buf->shmid, NULL, 0);
> + if(buf->mem == (void *) 0) {
> + PERROR("shmat");
> + goto close_fifo;
> + }
> + DBG("successfully attached buffer memory");
> +
> + buf->bufstruct_mem = shmat(buf->bufstruct_shmid, NULL, 0);
> + if(buf->bufstruct_mem == (void *) 0) {
> + PERROR("shmat");
> + goto shmdt_mem;
> + }
> + DBG("successfully attached buffer bufstruct memory");
> +
> + /* obtain info on the memory segment */
> + result = shmctl(buf->shmid, IPC_STAT, &shmds);
> + if(result == -1) {
> + PERROR("shmctl");
> + goto shmdt_bufstruct_mem;
> + }
> + buf->memlen = shmds.shm_segsz;
> +
> + /* Notify the application that we have mapped the buffer */
> + result = notify_buffer_mapped(buf->app_sock, buf);
> + if (result < 0) {
> + goto shmdt_bufstruct_mem;
> + }
> +
> + if(instance->callbacks->on_open_buffer)
> + instance->callbacks->on_open_buffer(instance->callbacks, buf);
> +
> + pthread_mutex_lock(&instance->mutex);
> + instance->active_buffers++;
> + pthread_mutex_unlock(&instance->mutex);
> +
> + return buf;
> +
> +shmdt_bufstruct_mem:
> + shmdt(buf->bufstruct_mem);
> +
> +shmdt_mem:
> + shmdt(buf->mem);
> +
> +close_fifo:
> + close(buf->pipe_fd);
> +
> +close_app_sock:
> + close(buf->app_sock);
> +
> +free_buf_name:
> + free(buf->name);
> +
> +free_buf_channel:
> + free(buf->channel);
> +
> +free_buf_trace:
> + free(buf->trace);
> +
> +free_buf:
> + free(buf);
> + return NULL;
> +}
> +
> +static void destroy_buffer(struct ustconsumer_callbacks *callbacks,
> + struct buffer_info *buf)
> +{
> + int result;
> +
> + result = close(buf->app_sock);
> + if(result == -1) {
> + WARN("problem calling ustcomm_close_app");
> + }
> +
> + result = shmdt(buf->mem);
> + if(result == -1) {
> + PERROR("shmdt");
> + }
> +
> + result = shmdt(buf->bufstruct_mem);
> + if(result == -1) {
> + PERROR("shmdt");
> + }
> +
> + if(callbacks->on_close_buffer)
> + callbacks->on_close_buffer(callbacks, buf);
> +
> + free(buf);
> +}
> +
> +int consumer_loop(struct ustconsumer_instance *instance, struct buffer_info *buf)
> +{
> + int result, read_result;
> + char read_buf;
> +
> + pthread_cleanup_push(decrement_active_buffers, instance);
> +
> + for(;;) {
> + read_result = read(buf->pipe_fd, &read_buf, 1);
> + /* get the subbuffer */
> + if (read_result == 1) {
> + result = get_subbuffer(buf);
> + if (result < 0) {
> + ERR("error getting subbuffer");
> + continue;
> + } else if (result == GET_SUBBUF_DIED) {
> + finish_consuming_dead_subbuffer(instance->callbacks, buf);
> + break;
> + }
> + } else if ((read_result == -1 && (errno == ECONNRESET || errno == EPIPE)) ||
> + result == 0) {
> + DBG("App died while being traced");
> + finish_consuming_dead_subbuffer(instance->callbacks, buf);
> + break;
> + }
> +
> + if(instance->callbacks->on_read_subbuffer)
> + instance->callbacks->on_read_subbuffer(instance->callbacks, buf);
> +
> + /* put the subbuffer */
> + result = put_subbuffer(buf);
> + if(result == -1) {
> + ERR("unknown error putting subbuffer (channel=%s)", buf->name);
> + break;
> + }
> + else if(result == PUT_SUBBUF_PUSHED) {
> + ERR("Buffer overflow (channel=%s), reader pushed. This channel will not be usable passed this point.", buf->name);
> + break;
> + }
> + else if(result == PUT_SUBBUF_DIED) {
> + DBG("application died while putting subbuffer");
> + /* Skip the first subbuffer. We are not sure it is trustable
> + * because the put_subbuffer() did not complete.
> + */
> + if(instance->callbacks->on_put_error)
> + instance->callbacks->on_put_error(instance->callbacks, buf);
> +
> + finish_consuming_dead_subbuffer(instance->callbacks, buf);
> + break;
> + }
> + else if(result == PUT_SUBBUF_DONE) {
> + /* Done with this subbuffer */
> + /* FIXME: add a case where this branch is used? Upon
> + * normal trace termination, at put_subbuf time, a
> + * special last-subbuffer code could be returned by
> + * the listener.
> + */
> + break;
> + }
> + else if(result == PUT_SUBBUF_OK) {
> + }
> + }
> +
> + DBG("thread for buffer %s is stopping", buf->name);
> +
> + /* FIXME: destroy, unalloc... */
> +
> + pthread_cleanup_pop(1);
> +
> + return 0;
> +}
> +
> +struct consumer_thread_args {
> + pid_t pid;
> + const char *trace;
> + const char *channel;
> + int channel_cpu;
> + struct ustconsumer_instance *instance;
> +};
> +
> +void *consumer_thread(void *arg)
> +{
> + struct buffer_info *buf;
> + struct consumer_thread_args *args = (struct consumer_thread_args *) arg;
> + int result;
> + sigset_t sigset;
> +
> + if(args->instance->callbacks->on_new_thread)
> + args->instance->callbacks->on_new_thread(args->instance->callbacks);
> +
> + /* Block signals that should be handled by the main thread. */
> + result = sigemptyset(&sigset);
> + if(result == -1) {
> + PERROR("sigemptyset");
> + goto end;
> + }
> + result = sigaddset(&sigset, SIGTERM);
> + if(result == -1) {
> + PERROR("sigaddset");
> + goto end;
> + }
> + result = sigaddset(&sigset, SIGINT);
> + if(result == -1) {
> + PERROR("sigaddset");
> + goto end;
> + }
> + result = sigprocmask(SIG_BLOCK, &sigset, NULL);
> + if(result == -1) {
> + PERROR("sigprocmask");
> + goto end;
> + }
> +
> + buf = connect_buffer(args->instance, args->pid, args->trace,
> + args->channel, args->channel_cpu);
> + if(buf == NULL) {
> + ERR("failed to connect to buffer");
> + goto end;
> + }
> +
> + consumer_loop(args->instance, buf);
> +
> + destroy_buffer(args->instance->callbacks, buf);
> +
> + end:
> +
> + if(args->instance->callbacks->on_close_thread)
> + args->instance->callbacks->on_close_thread(args->instance->callbacks);
> +
> + free((void *)args->channel);
> + free(args);
> + return NULL;
> +}
> +
> +int start_consuming_buffer(struct ustconsumer_instance *instance, pid_t pid,
> + const char *trace, const char *channel,
> + int channel_cpu)
> +{
> + pthread_t thr;
> + struct consumer_thread_args *args;
> + int result;
> +
> + DBG("beginning of start_consuming_buffer: args: pid %d bufname %s_%d", pid, channel,
> + channel_cpu);
> +
> + args = (struct consumer_thread_args *) zmalloc(sizeof(struct consumer_thread_args));
> + if (!args) {
> + return -ENOMEM;
> + }
> +
> + args->pid = pid;
> + args->trace = strdup(trace);
> + args->channel = strdup(channel);
> + args->channel_cpu = channel_cpu;
> + args->instance = instance;
> + DBG("beginning2 of start_consuming_buffer: args: pid %d trace %s"
> + " bufname %s_%d", args->pid, args->channel, args->channel_cpu);
> +
> + result = pthread_create(&thr, NULL, consumer_thread, args);
> + if(result == -1) {
> + ERR("pthread_create failed");
> + return -1;
> + }
> + result = pthread_detach(thr);
> + if(result == -1) {
> + ERR("pthread_detach failed");
> + return -1;
> + }
> + DBG("end of start_consuming_buffer: args: pid %d trace %s "
> + "bufname %s_%d", args->pid, args->channel, args->channel_cpu);
> +
> + return 0;
> +}
> +static void process_client_cmd(int sock, struct ustcomm_header *req_header,
> + char *recvbuf, struct ustconsumer_instance *instance)
> +{
> + int result;
> + struct ustcomm_header _res_header;
> + struct ustcomm_header *res_header = &_res_header;
> + struct ustcomm_buffer_info *buf_inf;
> +
> + DBG("Processing client command");
> +
> + switch (req_header->command) {
> + case CONSUME_BUFFER:
> +
> + buf_inf = (struct ustcomm_buffer_info *)recvbuf;
> + result = ustcomm_unpack_buffer_info(buf_inf);
> + if (result < 0) {
> + ERR("Couldn't unpack buffer info");
> + return;
> + }
> +
> + DBG("Going to consume trace %s buffer %s_%d in process %d",
> + buf_inf->trace, buf_inf->channel, buf_inf->ch_cpu,
> + buf_inf->pid);
> + result = start_consuming_buffer(instance, buf_inf->pid,
> + buf_inf->trace,
> + buf_inf->channel,
> + buf_inf->ch_cpu);
> + if (result < 0) {
> + ERR("error in add_buffer");
> + return;
> + }
> +
> + res_header->result = 0;
> + break;
> + case EXIT:
> + res_header->result = 0;
> + /* Only there to force poll to return */
> + break;
> + default:
> + res_header->result = -EINVAL;
> + WARN("unknown command: %d", req_header->command);
> + }
> +
> + if (ustcomm_send(sock, res_header, NULL) <= 0) {
> + ERR("couldn't send command response");
> + }
> +}
> +
> +#define MAX_EVENTS 10
> +
> +int ustconsumer_start_instance(struct ustconsumer_instance *instance)
> +{
> + struct ustcomm_header recv_hdr;
> + char recv_buf[USTCOMM_BUFFER_SIZE];
> + struct ustcomm_sock *epoll_sock;
> + struct epoll_event events[MAX_EVENTS];
> + struct sockaddr addr;
> + int result, epoll_fd, accept_fd, nfds, i, addr_size, timeout;
> +
> + if(!instance->is_init) {
> + ERR("libustconsumer instance not initialized");
> + return 1;
> + }
> + epoll_fd = instance->epoll_fd;
> +
> + timeout = -1;
> +
> + /* app loop */
> + for(;;) {
> + nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, timeout);
> + if (nfds == -1 && errno == EINTR) {
> + /* Caught signal */
> + } else if (nfds == -1) {
> + PERROR("ustconsumer_start_instance: epoll_wait failed");
> + continue;
> + }
> +
> + for (i = 0; i < nfds; ++i) {
> + epoll_sock = (struct ustcomm_sock *)events[i].data.ptr;
> + if (epoll_sock == instance->listen_sock) {
> + addr_size = sizeof(struct sockaddr);
> + accept_fd = accept(epoll_sock->fd,
> + &addr,
> + (socklen_t *)&addr_size);
> + if (accept_fd == -1) {
> + PERROR("ustconsumer_start_instance: "
> + "accept failed");
> + continue;
> + }
> + ustcomm_init_sock(accept_fd, epoll_fd,
> + &instance->connections);
> + } else {
> + result = ustcomm_recv(epoll_sock->fd, &recv_hdr,
> + recv_buf);
> + if (result < 1) {
> + ustcomm_del_sock(epoll_sock, 0);
> + } else {
> + process_client_cmd(epoll_sock->fd,
> + &recv_hdr, recv_buf,
> + instance);
> + }
> +
> + }
> + }
> +
> + if (instance->quit_program) {
> + pthread_mutex_lock(&instance->mutex);
> + if(instance->active_buffers == 0) {
> + pthread_mutex_unlock(&instance->mutex);
> + break;
> + }
> + pthread_mutex_unlock(&instance->mutex);
> + timeout = 100;
> + }
> + }
> +
> + if(instance->callbacks->on_trace_end)
> + instance->callbacks->on_trace_end(instance);
> +
> + ustconsumer_delete_instance(instance);
> +
> + return 0;
> +}
> +
> +/* FIXME: threads and connections !? */
> +void ustconsumer_delete_instance(struct ustconsumer_instance *instance)
> +{
> + if (instance->is_init) {
> + ustcomm_del_named_sock(instance->listen_sock, 0);
> + close(instance->epoll_fd);
> + }
> +
> + pthread_mutex_destroy(&instance->mutex);
> + free(instance->sock_path);
> + free(instance);
> +}
> +
> +/* FIXME: Do something about the fixed path length, maybe get rid
> + * of the whole concept and use a pipe?
> + */
> +int ustconsumer_stop_instance(struct ustconsumer_instance *instance, int send_msg)
> +{
> + int result;
> + int fd;
> + int bytes = 0;
> +
> + char msg[] = "exit";
> +
> + instance->quit_program = 1;
> +
> + if(!send_msg)
> + return 0;
> +
> + /* Send a message through the socket to force poll to return */
> +
> + struct sockaddr_un addr;
> +
> + result = fd = socket(PF_UNIX, SOCK_STREAM, 0);
> + if(result == -1) {
> + PERROR("socket");
> + return 1;
> + }
> +
> + addr.sun_family = AF_UNIX;
> +
> + strncpy(addr.sun_path, instance->sock_path, UNIX_PATH_MAX);
> + addr.sun_path[UNIX_PATH_MAX-1] = '\0';
> +
> + result = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
> + if(result == -1) {
> + PERROR("connect");
> + }
> +
> + while(bytes != sizeof(msg))
> + bytes += send(fd, msg, sizeof(msg), 0);
> +
> + close(fd);
> +
> + return 0;
> +}
> +
> +struct ustconsumer_instance
> +*ustconsumer_new_instance(struct ustconsumer_callbacks *callbacks,
> + char *sock_path)
> +{
> + struct ustconsumer_instance *instance =
> + zmalloc(sizeof(struct ustconsumer_instance));
> + if(!instance) {
> + return NULL;
> + }
> +
> + instance->callbacks = callbacks;
> + instance->quit_program = 0;
> + instance->is_init = 0;
> + instance->active_buffers = 0;
> + pthread_mutex_init(&instance->mutex, NULL);
> +
> + if (sock_path) {
> + instance->sock_path = strdup(sock_path);
> + } else {
> + instance->sock_path = NULL;
> + }
> +
> + return instance;
> +}
> +
> +static int init_ustconsumer_socket(struct ustconsumer_instance *instance)
> +{
> + char *name;
> +
> + if (instance->sock_path) {
> + if (asprintf(&name, "%s", instance->sock_path) < 0) {
> + ERR("ustcomm_init_ustconsumer : asprintf failed (sock_path %s)",
> + instance->sock_path);
> + return -1;
> + }
> + } else {
> + int result;
> +
> + /* Only check if socket dir exists if we are using the default directory */
> + result = ensure_dir_exists(SOCK_DIR);
> + if (result == -1) {
> + ERR("Unable to create socket directory %s", SOCK_DIR);
> + return -1;
> + }
> +
> + if (asprintf(&name, "%s/%s", SOCK_DIR, "ustconsumer") < 0) {
> + ERR("ustcomm_init_ustconsumer : asprintf failed (%s/ustconsumer)",
> + SOCK_DIR);
> + return -1;
> + }
> + }
> +
> + /* Set up epoll */
> + instance->epoll_fd = epoll_create(MAX_EVENTS);
> + if (instance->epoll_fd == -1) {
> + ERR("epoll_create failed, start instance bailing");
> + goto free_name;
> + }
> +
> + /* Create the named socket */
> + instance->listen_sock = ustcomm_init_named_socket(name,
> + instance->epoll_fd);
> + if(!instance->listen_sock) {
> + ERR("error initializing named socket at %s", name);
> + goto close_epoll;
> + }
> +
> + CDS_INIT_LIST_HEAD(&instance->connections);
> +
> + free(name);
> +
> + return 0;
> +
> +close_epoll:
> + close(instance->epoll_fd);
> +free_name:
> + free(name);
> +
> + return -1;
> +}
> +
> +int ustconsumer_init_instance(struct ustconsumer_instance *instance)
> +{
> + int result;
> + result = init_ustconsumer_socket(instance);
> + if(result == -1) {
> + ERR("failed to initialize socket");
> + return 1;
> + }
> + instance->is_init = 1;
> + return 0;
> +}
> +
> diff --git a/libustconsumer/lowlevel.c b/libustconsumer/lowlevel.c
> new file mode 100644
> index 0000000..7eb124b
> --- /dev/null
> +++ b/libustconsumer/lowlevel.c
> @@ -0,0 +1,143 @@
> +/* Copyright (C) 2009 Pierre-Marc Fournier
> + *
> + * 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 <stdlib.h>
> +#include <assert.h>
> +#include <byteswap.h>
> +
> +#include "ust/ustconsumer.h"
> +#include "buffers.h"
> +#include "tracer.h"
> +#include "usterr.h"
> +
> +/* This truncates to an offset in the buffer. */
> +#define USTD_BUFFER_TRUNC(offset, bufinfo) \
> + ((offset) & (~(((bufinfo)->subbuf_size*(bufinfo)->n_subbufs)-1)))
> +
> +#define LTT_MAGIC_NUMBER 0x00D6B7ED
> +#define LTT_REV_MAGIC_NUMBER 0xEDB7D600
> +
> +/* Returns the size of a subbuffer size. This is the size that
> + * will need to be written to disk.
> + *
> + * @subbuffer: pointer to the beginning of the subbuffer (the
> + * beginning of its header)
> + */
> +
> +size_t subbuffer_data_size(void *subbuf)
> +{
> + struct ltt_subbuffer_header *header = subbuf;
> + int reverse;
> + u32 data_size;
> +
> + if(header->magic_number == LTT_MAGIC_NUMBER) {
> + reverse = 0;
> + }
> + else if(header->magic_number == LTT_REV_MAGIC_NUMBER) {
> + reverse = 1;
> + }
> + else {
> + return -1;
> + }
> +
> + data_size = header->sb_size;
> + if(reverse)
> + data_size = bswap_32(data_size);
> +
> + return data_size;
> +}
> +
> +
> +void finish_consuming_dead_subbuffer(struct ustconsumer_callbacks *callbacks, struct buffer_info *buf)
> +{
> + struct ust_buffer *ustbuf = buf->bufstruct_mem;
> +
> + long write_offset = uatomic_read(&ustbuf->offset);
> + long consumed_offset = uatomic_read(&ustbuf->consumed);
> +
> + long i_subbuf;
> +
> + DBG("processing dead buffer (%s)", buf->name);
> + DBG("consumed offset is %ld (%s)", consumed_offset, buf->name);
> + DBG("write offset is %ld (%s)", write_offset, buf->name);
> +
> + /* First subbuf that we need to consume now. It is not modulo'd.
> + * Consumed_offset is the next byte to consume. */
> + long first_subbuf = consumed_offset / buf->subbuf_size;
> + /* Last subbuf that we need to consume now. It is not modulo'd.
> + * Write_offset is the next place to write so write_offset-1 is the
> + * last place written. */
> + long last_subbuf = (write_offset - 1) / buf->subbuf_size;
> +
> + DBG("first_subbuf=%ld", first_subbuf);
> + DBG("last_subbuf=%ld", last_subbuf);
> +
> + if(last_subbuf - first_subbuf >= buf->n_subbufs) {
> + DBG("an overflow has occurred, nothing can be recovered");
> + return;
> + }
> +
> + /* Iterate on subbuffers to recover. */
> + for(i_subbuf = first_subbuf % buf->n_subbufs; ; i_subbuf++, i_subbuf %= buf->n_subbufs) {
> + /* commit_seq is the offset in the buffer of the end of the last sequential commit.
> + * Bytes beyond this limit cannot be recovered. This is a free-running counter. */
> + long commit_seq = uatomic_read(&ustbuf->commit_seq[i_subbuf]);
> +
> + unsigned long valid_length = buf->subbuf_size;
> + long n_subbufs_order = get_count_order(buf->n_subbufs);
> + long commit_seq_mask = (~0UL >> n_subbufs_order);
> +
> + struct ltt_subbuffer_header *header = (struct ltt_subbuffer_header *)((char *)buf->mem+i_subbuf*buf->subbuf_size);
> +
> + if((commit_seq & commit_seq_mask) == 0) {
> + /* There is nothing to do. */
> + /* FIXME: is this needed? */
> + break;
> + }
> +
> + /* Check if subbuf was fully written. This is from Mathieu's algorithm/paper. */
> + /* FIXME: not sure data_size = 0xffffffff when the buffer is not full. It might
> + * take the value of the header size initially */
> + if (((commit_seq - buf->subbuf_size) & commit_seq_mask)
> + - (USTD_BUFFER_TRUNC(consumed_offset, buf) >> n_subbufs_order) == 0
> + && header->data_size != 0xffffffff && header->sb_size != 0xffffffff) {
> + /* If it was, we only check the data_size. This is the amount of valid data at
> + * the beginning of the subbuffer. */
> + valid_length = header->data_size;
> + DBG("writing full subbuffer (%d) with valid_length = %ld", i_subbuf, valid_length);
> + }
> + else {
> + /* If the subbuffer was not fully written, then we don't check data_size because
> + * it hasn't been written yet. Instead we check commit_seq and use it to choose
> + * a value for data_size. The viewer will need this value when parsing.
> + */
> +
> + valid_length = commit_seq & (buf->subbuf_size-1);
> + DBG("writing unfull subbuffer (%d) with valid_length = %ld", i_subbuf, valid_length);
> + header->data_size = valid_length;
> + header->sb_size = PAGE_ALIGN(valid_length);
> + assert(i_subbuf == (last_subbuf % buf->n_subbufs));
> + }
> +
> + if(callbacks->on_read_partial_subbuffer)
> + callbacks->on_read_partial_subbuffer(callbacks, buf, i_subbuf, valid_length);
> +
> + if(i_subbuf == last_subbuf % buf->n_subbufs)
> + break;
> + }
> +}
> +
> diff --git a/libustconsumer/lowlevel.h b/libustconsumer/lowlevel.h
> new file mode 100644
> index 0000000..6ae6476
> --- /dev/null
> +++ b/libustconsumer/lowlevel.h
> @@ -0,0 +1,35 @@
> +/*
> + * lowlevel libustd header file
> + *
> + * Copyright 2005-2010 -
> + * Mathieu Desnoyers <mathieu.desnoyers at polymtl.ca>
> + * Copyright 2010-
> + * Oumarou Dicko <oumarou.dicko at polymtl.ca>
> + * Michael Sills-Lavoie <michael.sills-lavoie at polymtl.ca>
> + * Alexis Halle <alexis.halle at polymtl.ca>
> + *
> + * 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 LOWLEVEL_H
> +#define LOWLEVEL_H
> +
> +#include "ust/ustconsumer.h"
> +
> +void finish_consuming_dead_subbuffer(struct ustconsumer_callbacks *callbacks, struct buffer_info *buf);
> +size_t subbuffer_data_size(void *subbuf);
> +
> +#endif /* LOWLEVEL_H */
> +
> diff --git a/libustd/Makefile.am b/libustd/Makefile.am
> deleted file mode 100644
> index 1b9a961..0000000
> --- a/libustd/Makefile.am
> +++ /dev/null
> @@ -1,17 +0,0 @@
> -AM_CPPFLAGS = -I$(top_srcdir)/libust -I$(top_srcdir)/libustcomm \
> - -I$(top_srcdir)/include
> -AM_CFLAGS = -fno-strict-aliasing
> -
> -lib_LTLIBRARIES = libustd.la
> -
> -libustd_la_SOURCES = libustd.c lowlevel.c lowlevel.h
> -
> -libustd_la_LDFLAGS = -no-undefined -version-info 0:0:0
> -
> -libustd_la_LIBADD = \
> - -lpthread \
> - $(top_builddir)/snprintf/libustsnprintf.la \
> - $(top_builddir)/libustcomm/libustcomm.la
> -
> -libustd_la_CFLAGS = -fno-strict-aliasing
> -
> diff --git a/libustd/libustd.c b/libustd/libustd.c
> deleted file mode 100644
> index 0dc6940..0000000
> --- a/libustd/libustd.c
> +++ /dev/null
> @@ -1,891 +0,0 @@
> -/* Copyright (C) 2009 Pierre-Marc Fournier
> - * 2010 Alexis Halle
> - *
> - * 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
> - */
> -
> -#define _GNU_SOURCE
> -
> -#include <sys/epoll.h>
> -#include <sys/shm.h>
> -#include <sys/types.h>
> -#include <sys/stat.h>
> -#include <unistd.h>
> -#include <pthread.h>
> -#include <signal.h>
> -
> -#include <stdlib.h>
> -#include <stdio.h>
> -#include <string.h>
> -#include <errno.h>
> -#include <assert.h>
> -
> -#include <ust/ustd.h>
> -#include "lowlevel.h"
> -#include "usterr.h"
> -#include "ustcomm.h"
> -
> -#define GET_SUBBUF_OK 1
> -#define GET_SUBBUF_DONE 0
> -#define GET_SUBBUF_DIED 2
> -
> -#define PUT_SUBBUF_OK 1
> -#define PUT_SUBBUF_DIED 0
> -#define PUT_SUBBUF_PUSHED 2
> -#define PUT_SUBBUF_DONE 3
> -
> -#define UNIX_PATH_MAX 108
> -
> -static int get_subbuffer(struct buffer_info *buf)
> -{
> - struct ustcomm_header _send_hdr, *send_hdr;
> - struct ustcomm_header _recv_hdr, *recv_hdr;
> - struct ustcomm_buffer_info _send_msg, _recv_msg;
> - struct ustcomm_buffer_info *send_msg, *recv_msg;
> - int result;
> -
> - send_hdr = &_send_hdr;
> - recv_hdr = &_recv_hdr;
> - send_msg = &_send_msg;
> - recv_msg = &_recv_msg;
> -
> - result = ustcomm_pack_buffer_info(send_hdr, send_msg, buf->trace,
> - buf->channel, buf->channel_cpu);
> - if (result < 0) {
> - return result;
> - }
> -
> - send_hdr->command = GET_SUBBUFFER;
> -
> - result = ustcomm_req(buf->app_sock, send_hdr, (char *)send_msg,
> - recv_hdr, (char *)recv_msg);
> - if ((result < 0 && (errno == ECONNRESET || errno == EPIPE)) ||
> - result == 0) {
> - DBG("app died while being traced");
> - return GET_SUBBUF_DIED;
> - } else if (result < 0) {
> - ERR("get_subbuffer: ustcomm_req failed");
> - return result;
> - }
> -
> - if (!recv_hdr->result) {
> - DBG("got subbuffer %s", buf->name);
> - buf->consumed_old = recv_msg->consumed_old;
> - return GET_SUBBUF_OK;
> - } else if (recv_hdr->result == -ENODATA) {
> - DBG("For buffer %s, the trace was not found. This likely means"
> - " it was destroyed by the user.", buf->name);
> - return GET_SUBBUF_DIED;
> - }
> -
> - DBG("error getting subbuffer %s", buf->name);
> - return recv_hdr->result;
> -}
> -
> -static int put_subbuffer(struct buffer_info *buf)
> -{
> - struct ustcomm_header _send_hdr, *send_hdr;
> - struct ustcomm_header _recv_hdr, *recv_hdr;
> - struct ustcomm_buffer_info _send_msg, *send_msg;
> - int result;
> -
> - send_hdr = &_send_hdr;
> - recv_hdr = &_recv_hdr;
> - send_msg = &_send_msg;
> -
> - result = ustcomm_pack_buffer_info(send_hdr, send_msg, buf->trace,
> - buf->channel, buf->channel_cpu);
> - if (result < 0) {
> - return result;
> - }
> -
> - send_hdr->command = PUT_SUBBUFFER;
> - send_msg->consumed_old = buf->consumed_old;
> -
> - result = ustcomm_req(buf->app_sock, send_hdr, (char *)send_msg,
> - recv_hdr, NULL);
> - if ((result < 0 && (errno == ECONNRESET || errno == EPIPE)) ||
> - result == 0) {
> - DBG("app died while being traced");
> - return PUT_SUBBUF_DIED;
> - } else if (result < 0) {
> - ERR("put_subbuffer: ustcomm_req failed");
> - return result;
> - }
> -
> - if (!recv_hdr->result) {
> - DBG("put subbuffer %s", buf->name);
> - return PUT_SUBBUF_OK;
> - } else if (recv_hdr->result == -ENODATA) {
> - DBG("For buffer %s, the trace was not found. This likely means"
> - " it was destroyed by the user.", buf->name);
> - return PUT_SUBBUF_DIED;
> - }
> -
> - DBG("error getting subbuffer %s", buf->name);
> - return recv_hdr->result;
> -}
> -
> -void decrement_active_buffers(void *arg)
> -{
> - struct libustd_instance *instance = arg;
> - pthread_mutex_lock(&instance->mutex);
> - instance->active_buffers--;
> - pthread_mutex_unlock(&instance->mutex);
> -}
> -
> -static int get_pidunique(int sock, s64 *pidunique)
> -{
> - struct ustcomm_header _send_hdr, *send_hdr;
> - struct ustcomm_header _recv_hdr, *recv_hdr;
> - struct ustcomm_pidunique _recv_msg, *recv_msg;
> - int result;
> -
> - send_hdr = &_send_hdr;
> - recv_hdr = &_recv_hdr;
> - recv_msg = &_recv_msg;
> -
> - memset(send_hdr, 0, sizeof(*send_hdr));
> -
> - send_hdr->command = GET_PIDUNIQUE;
> - result = ustcomm_req(sock, send_hdr, NULL, recv_hdr, (char *)recv_msg);
> - if (result < 1) {
> - return -ENOTCONN;
> - }
> - if (recv_hdr->result < 0) {
> - ERR("App responded with error: %s", strerror(recv_hdr->result));
> - return recv_hdr->result;
> - }
> -
> - *pidunique = recv_msg->pidunique;
> -
> - return 0;
> -}
> -
> -static int get_buf_shmid_pipe_fd(int sock, struct buffer_info *buf,
> - int *buf_shmid, int *buf_struct_shmid,
> - int *buf_pipe_fd)
> -{
> - struct ustcomm_header _send_hdr, *send_hdr;
> - struct ustcomm_header _recv_hdr, *recv_hdr;
> - struct ustcomm_buffer_info _send_msg, *send_msg;
> - struct ustcomm_buffer_info _recv_msg, *recv_msg;
> - int result, recv_pipe_fd;
> -
> - send_hdr = &_send_hdr;
> - recv_hdr = &_recv_hdr;
> - send_msg = &_send_msg;
> - recv_msg = &_recv_msg;
> -
> - result = ustcomm_pack_buffer_info(send_hdr, send_msg, buf->trace,
> - buf->channel, buf->channel_cpu);
> - if (result < 0) {
> - ERR("Failed to pack buffer info");
> - return result;
> - }
> -
> - send_hdr->command = GET_BUF_SHMID_PIPE_FD;
> -
> - result = ustcomm_send(sock, send_hdr, (char *)send_msg);
> - if (result < 1) {
> - ERR("Failed to send request");
> - return -ENOTCONN;
> - }
> - result = ustcomm_recv_fd(sock, recv_hdr, (char *)recv_msg, &recv_pipe_fd);
> - if (result < 1) {
> - ERR("Failed to receive message and fd");
> - return -ENOTCONN;
> - }
> - if (recv_hdr->result < 0) {
> - ERR("App responded with error %s", strerror(recv_hdr->result));
> - return recv_hdr->result;
> - }
> -
> - *buf_shmid = recv_msg->buf_shmid;
> - *buf_struct_shmid = recv_msg->buf_struct_shmid;
> - *buf_pipe_fd = recv_pipe_fd;
> -
> - return 0;
> -}
> -
> -static int get_subbuf_num_size(int sock, struct buffer_info *buf,
> - int *subbuf_num, int *subbuf_size)
> -{
> - struct ustcomm_header _send_hdr, *send_hdr;
> - struct ustcomm_header _recv_hdr, *recv_hdr;
> - struct ustcomm_channel_info _send_msg, *send_msg;
> - struct ustcomm_channel_info _recv_msg, *recv_msg;
> - int result;
> -
> - send_hdr = &_send_hdr;
> - recv_hdr = &_recv_hdr;
> - send_msg = &_send_msg;
> - recv_msg = &_recv_msg;
> -
> - result = ustcomm_pack_channel_info(send_hdr, send_msg, buf->trace,
> - buf->channel);
> - if (result < 0) {
> - return result;
> - }
> -
> - send_hdr->command = GET_SUBBUF_NUM_SIZE;
> -
> - result = ustcomm_req(sock, send_hdr, (char *)send_msg,
> - recv_hdr, (char *)recv_msg);
> - if (result < 1) {
> - return -ENOTCONN;
> - }
> -
> - *subbuf_num = recv_msg->subbuf_num;
> - *subbuf_size = recv_msg->subbuf_size;
> -
> - return recv_hdr->result;
> -}
> -
> -
> -static int notify_buffer_mapped(int sock, struct buffer_info *buf)
> -{
> - struct ustcomm_header _send_hdr, *send_hdr;
> - struct ustcomm_header _recv_hdr, *recv_hdr;
> - struct ustcomm_buffer_info _send_msg, *send_msg;
> - int result;
> -
> - send_hdr = &_send_hdr;
> - recv_hdr = &_recv_hdr;
> - send_msg = &_send_msg;
> -
> - result = ustcomm_pack_buffer_info(send_hdr, send_msg, buf->trace,
> - buf->channel, buf->channel_cpu);
> - if (result < 0) {
> - return result;
> - }
> -
> - send_hdr->command = NOTIFY_BUF_MAPPED;
> -
> - result = ustcomm_req(sock, send_hdr, (char *)send_msg,
> - recv_hdr, NULL);
> - if (result < 1) {
> - return -ENOTCONN;
> - }
> -
> - return recv_hdr->result;
> -}
> -
> -
> -struct buffer_info *connect_buffer(struct libustd_instance *instance, pid_t pid,
> - const char *trace, const char *channel,
> - int channel_cpu)
> -{
> - struct buffer_info *buf;
> - int result;
> - struct shmid_ds shmds;
> -
> - buf = (struct buffer_info *) zmalloc(sizeof(struct buffer_info));
> - if(buf == NULL) {
> - ERR("add_buffer: insufficient memory");
> - return NULL;
> - }
> -
> - buf->trace = strdup(trace);
> - if (!buf->trace) {
> - goto free_buf;
> - }
> -
> - buf->channel = strdup(channel);
> - if (!buf->channel) {
> - goto free_buf_trace;
> - }
> -
> - result = asprintf(&buf->name, "%s_%d", channel, channel_cpu);
> - if (result < 0 || buf->name == NULL) {
> - goto free_buf_channel;
> - }
> -
> - buf->channel_cpu = channel_cpu;
> - buf->pid = pid;
> -
> - result = ustcomm_connect_app(buf->pid, &buf->app_sock);
> - if(result) {
> - WARN("unable to connect to process, it probably died before we were able to connect");
> - goto free_buf_name;
> - }
> -
> - /* get pidunique */
> - result = get_pidunique(buf->app_sock, &buf->pidunique);
> - if (result < 0) {
> - ERR("Failed to get pidunique");
> - goto close_app_sock;
> - }
> -
> - /* get shmid and pipe fd */
> - result = get_buf_shmid_pipe_fd(buf->app_sock, buf, &buf->shmid,
> - &buf->bufstruct_shmid, &buf->pipe_fd);
> - if (result < 0) {
> - ERR("Failed to get buf_shmid and pipe_fd");
> - goto close_app_sock;
> - } else {
> - struct stat temp;
> - fstat(buf->pipe_fd, &temp);
> - if (!S_ISFIFO(temp.st_mode)) {
> - ERR("Didn't receive a fifo from the app");
> - goto close_app_sock;
> - }
> - }
> -
> -
> - /* get number of subbufs and subbuf size */
> - result = get_subbuf_num_size(buf->app_sock, buf, &buf->n_subbufs,
> - &buf->subbuf_size);
> - if (result < 0) {
> - ERR("Failed to get subbuf number and size");
> - goto close_fifo;
> - }
> -
> - /* attach memory */
> - buf->mem = shmat(buf->shmid, NULL, 0);
> - if(buf->mem == (void *) 0) {
> - PERROR("shmat");
> - goto close_fifo;
> - }
> - DBG("successfully attached buffer memory");
> -
> - buf->bufstruct_mem = shmat(buf->bufstruct_shmid, NULL, 0);
> - if(buf->bufstruct_mem == (void *) 0) {
> - PERROR("shmat");
> - goto shmdt_mem;
> - }
> - DBG("successfully attached buffer bufstruct memory");
> -
> - /* obtain info on the memory segment */
> - result = shmctl(buf->shmid, IPC_STAT, &shmds);
> - if(result == -1) {
> - PERROR("shmctl");
> - goto shmdt_bufstruct_mem;
> - }
> - buf->memlen = shmds.shm_segsz;
> -
> - /* Notify the application that we have mapped the buffer */
> - result = notify_buffer_mapped(buf->app_sock, buf);
> - if (result < 0) {
> - goto shmdt_bufstruct_mem;
> - }
> -
> - if(instance->callbacks->on_open_buffer)
> - instance->callbacks->on_open_buffer(instance->callbacks, buf);
> -
> - pthread_mutex_lock(&instance->mutex);
> - instance->active_buffers++;
> - pthread_mutex_unlock(&instance->mutex);
> -
> - return buf;
> -
> -shmdt_bufstruct_mem:
> - shmdt(buf->bufstruct_mem);
> -
> -shmdt_mem:
> - shmdt(buf->mem);
> -
> -close_fifo:
> - close(buf->pipe_fd);
> -
> -close_app_sock:
> - close(buf->app_sock);
> -
> -free_buf_name:
> - free(buf->name);
> -
> -free_buf_channel:
> - free(buf->channel);
> -
> -free_buf_trace:
> - free(buf->trace);
> -
> -free_buf:
> - free(buf);
> - return NULL;
> -}
> -
> -static void destroy_buffer(struct libustd_callbacks *callbacks,
> - struct buffer_info *buf)
> -{
> - int result;
> -
> - result = close(buf->app_sock);
> - if(result == -1) {
> - WARN("problem calling ustcomm_close_app");
> - }
> -
> - result = shmdt(buf->mem);
> - if(result == -1) {
> - PERROR("shmdt");
> - }
> -
> - result = shmdt(buf->bufstruct_mem);
> - if(result == -1) {
> - PERROR("shmdt");
> - }
> -
> - if(callbacks->on_close_buffer)
> - callbacks->on_close_buffer(callbacks, buf);
> -
> - free(buf);
> -}
> -
> -int consumer_loop(struct libustd_instance *instance, struct buffer_info *buf)
> -{
> - int result, read_result;
> - char read_buf;
> -
> - pthread_cleanup_push(decrement_active_buffers, instance);
> -
> - for(;;) {
> - read_result = read(buf->pipe_fd, &read_buf, 1);
> - /* get the subbuffer */
> - if (read_result == 1) {
> - result = get_subbuffer(buf);
> - if (result < 0) {
> - ERR("error getting subbuffer");
> - continue;
> - } else if (result == GET_SUBBUF_DIED) {
> - finish_consuming_dead_subbuffer(instance->callbacks, buf);
> - break;
> - }
> - } else if ((read_result == -1 && (errno == ECONNRESET || errno == EPIPE)) ||
> - result == 0) {
> - DBG("App died while being traced");
> - finish_consuming_dead_subbuffer(instance->callbacks, buf);
> - break;
> - }
> -
> - if(instance->callbacks->on_read_subbuffer)
> - instance->callbacks->on_read_subbuffer(instance->callbacks, buf);
> -
> - /* put the subbuffer */
> - result = put_subbuffer(buf);
> - if(result == -1) {
> - ERR("unknown error putting subbuffer (channel=%s)", buf->name);
> - break;
> - }
> - else if(result == PUT_SUBBUF_PUSHED) {
> - ERR("Buffer overflow (channel=%s), reader pushed. This channel will not be usable passed this point.", buf->name);
> - break;
> - }
> - else if(result == PUT_SUBBUF_DIED) {
> - DBG("application died while putting subbuffer");
> - /* Skip the first subbuffer. We are not sure it is trustable
> - * because the put_subbuffer() did not complete.
> - */
> - if(instance->callbacks->on_put_error)
> - instance->callbacks->on_put_error(instance->callbacks, buf);
> -
> - finish_consuming_dead_subbuffer(instance->callbacks, buf);
> - break;
> - }
> - else if(result == PUT_SUBBUF_DONE) {
> - /* Done with this subbuffer */
> - /* FIXME: add a case where this branch is used? Upon
> - * normal trace termination, at put_subbuf time, a
> - * special last-subbuffer code could be returned by
> - * the listener.
> - */
> - break;
> - }
> - else if(result == PUT_SUBBUF_OK) {
> - }
> - }
> -
> - DBG("thread for buffer %s is stopping", buf->name);
> -
> - /* FIXME: destroy, unalloc... */
> -
> - pthread_cleanup_pop(1);
> -
> - return 0;
> -}
> -
> -struct consumer_thread_args {
> - pid_t pid;
> - const char *trace;
> - const char *channel;
> - int channel_cpu;
> - struct libustd_instance *instance;
> -};
> -
> -void *consumer_thread(void *arg)
> -{
> - struct buffer_info *buf;
> - struct consumer_thread_args *args = (struct consumer_thread_args *) arg;
> - int result;
> - sigset_t sigset;
> -
> - if(args->instance->callbacks->on_new_thread)
> - args->instance->callbacks->on_new_thread(args->instance->callbacks);
> -
> - /* Block signals that should be handled by the main thread. */
> - result = sigemptyset(&sigset);
> - if(result == -1) {
> - PERROR("sigemptyset");
> - goto end;
> - }
> - result = sigaddset(&sigset, SIGTERM);
> - if(result == -1) {
> - PERROR("sigaddset");
> - goto end;
> - }
> - result = sigaddset(&sigset, SIGINT);
> - if(result == -1) {
> - PERROR("sigaddset");
> - goto end;
> - }
> - result = sigprocmask(SIG_BLOCK, &sigset, NULL);
> - if(result == -1) {
> - PERROR("sigprocmask");
> - goto end;
> - }
> -
> - buf = connect_buffer(args->instance, args->pid, args->trace,
> - args->channel, args->channel_cpu);
> - if(buf == NULL) {
> - ERR("failed to connect to buffer");
> - goto end;
> - }
> -
> - consumer_loop(args->instance, buf);
> -
> - destroy_buffer(args->instance->callbacks, buf);
> -
> - end:
> -
> - if(args->instance->callbacks->on_close_thread)
> - args->instance->callbacks->on_close_thread(args->instance->callbacks);
> -
> - free((void *)args->channel);
> - free(args);
> - return NULL;
> -}
> -
> -int start_consuming_buffer(struct libustd_instance *instance, pid_t pid,
> - const char *trace, const char *channel,
> - int channel_cpu)
> -{
> - pthread_t thr;
> - struct consumer_thread_args *args;
> - int result;
> -
> - DBG("beginning of start_consuming_buffer: args: pid %d bufname %s_%d", pid, channel,
> - channel_cpu);
> -
> - args = (struct consumer_thread_args *) zmalloc(sizeof(struct consumer_thread_args));
> - if (!args) {
> - return -ENOMEM;
> - }
> -
> - args->pid = pid;
> - args->trace = strdup(trace);
> - args->channel = strdup(channel);
> - args->channel_cpu = channel_cpu;
> - args->instance = instance;
> - DBG("beginning2 of start_consuming_buffer: args: pid %d trace %s"
> - " bufname %s_%d", args->pid, args->channel, args->channel_cpu);
> -
> - result = pthread_create(&thr, NULL, consumer_thread, args);
> - if(result == -1) {
> - ERR("pthread_create failed");
> - return -1;
> - }
> - result = pthread_detach(thr);
> - if(result == -1) {
> - ERR("pthread_detach failed");
> - return -1;
> - }
> - DBG("end of start_consuming_buffer: args: pid %d trace %s "
> - "bufname %s_%d", args->pid, args->channel, args->channel_cpu);
> -
> - return 0;
> -}
> -static void process_client_cmd(int sock, struct ustcomm_header *req_header,
> - char *recvbuf, struct libustd_instance *instance)
> -{
> - int result;
> - struct ustcomm_header _res_header;
> - struct ustcomm_header *res_header = &_res_header;
> - struct ustcomm_buffer_info *buf_inf;
> -
> - DBG("Processing client command");
> -
> - switch (req_header->command) {
> - case CONSUME_BUFFER:
> -
> - buf_inf = (struct ustcomm_buffer_info *)recvbuf;
> - result = ustcomm_unpack_buffer_info(buf_inf);
> - if (result < 0) {
> - ERR("Couldn't unpack buffer info");
> - return;
> - }
> -
> - DBG("Going to consume trace %s buffer %s_%d in process %d",
> - buf_inf->trace, buf_inf->channel, buf_inf->ch_cpu,
> - buf_inf->pid);
> - result = start_consuming_buffer(instance, buf_inf->pid,
> - buf_inf->trace,
> - buf_inf->channel,
> - buf_inf->ch_cpu);
> - if (result < 0) {
> - ERR("error in add_buffer");
> - return;
> - }
> -
> - res_header->result = 0;
> - break;
> - case EXIT:
> - res_header->result = 0;
> - /* Only there to force poll to return */
> - break;
> - default:
> - res_header->result = -EINVAL;
> - WARN("unknown command: %d", req_header->command);
> - }
> -
> - if (ustcomm_send(sock, res_header, NULL) <= 0) {
> - ERR("couldn't send command response");
> - }
> -}
> -
> -#define MAX_EVENTS 10
> -
> -int libustd_start_instance(struct libustd_instance *instance)
> -{
> - struct ustcomm_header recv_hdr;
> - char recv_buf[USTCOMM_BUFFER_SIZE];
> - struct ustcomm_sock *epoll_sock;
> - struct epoll_event events[MAX_EVENTS];
> - struct sockaddr addr;
> - int result, epoll_fd, accept_fd, nfds, i, addr_size, timeout;
> -
> - if(!instance->is_init) {
> - ERR("libustd instance not initialized");
> - return 1;
> - }
> - epoll_fd = instance->epoll_fd;
> -
> - timeout = -1;
> -
> - /* app loop */
> - for(;;) {
> - nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, timeout);
> - if (nfds == -1 && errno == EINTR) {
> - /* Caught signal */
> - } else if (nfds == -1) {
> - PERROR("libustd_start_instance: epoll_wait failed");
> - continue;
> - }
> -
> - for (i = 0; i < nfds; ++i) {
> - epoll_sock = (struct ustcomm_sock *)events[i].data.ptr;
> - if (epoll_sock == instance->listen_sock) {
> - addr_size = sizeof(struct sockaddr);
> - accept_fd = accept(epoll_sock->fd,
> - &addr,
> - (socklen_t *)&addr_size);
> - if (accept_fd == -1) {
> - PERROR("libustd_start_instance: "
> - "accept failed");
> - continue;
> - }
> - ustcomm_init_sock(accept_fd, epoll_fd,
> - &instance->connections);
> - } else {
> - result = ustcomm_recv(epoll_sock->fd, &recv_hdr,
> - recv_buf);
> - if (result < 1) {
> - ustcomm_del_sock(epoll_sock, 0);
> - } else {
> - process_client_cmd(epoll_sock->fd,
> - &recv_hdr, recv_buf,
> - instance);
> - }
> -
> - }
> - }
> -
> - if (instance->quit_program) {
> - pthread_mutex_lock(&instance->mutex);
> - if(instance->active_buffers == 0) {
> - pthread_mutex_unlock(&instance->mutex);
> - break;
> - }
> - pthread_mutex_unlock(&instance->mutex);
> - timeout = 100;
> - }
> - }
> -
> - if(instance->callbacks->on_trace_end)
> - instance->callbacks->on_trace_end(instance);
> -
> - libustd_delete_instance(instance);
> -
> - return 0;
> -}
> -
> -/* FIXME: threads and connections !? */
> -void libustd_delete_instance(struct libustd_instance *instance)
> -{
> - if (instance->is_init) {
> - ustcomm_del_named_sock(instance->listen_sock, 0);
> - close(instance->epoll_fd);
> - }
> -
> - pthread_mutex_destroy(&instance->mutex);
> - free(instance->sock_path);
> - free(instance);
> -}
> -
> -/* FIXME: Do something about the fixed path length, maybe get rid
> - * of the whole concept and use a pipe?
> - */
> -int libustd_stop_instance(struct libustd_instance *instance, int send_msg)
> -{
> - int result;
> - int fd;
> - int bytes = 0;
> -
> - char msg[] = "exit";
> -
> - instance->quit_program = 1;
> -
> - if(!send_msg)
> - return 0;
> -
> - /* Send a message through the socket to force poll to return */
> -
> - struct sockaddr_un addr;
> -
> - result = fd = socket(PF_UNIX, SOCK_STREAM, 0);
> - if(result == -1) {
> - PERROR("socket");
> - return 1;
> - }
> -
> - addr.sun_family = AF_UNIX;
> -
> - strncpy(addr.sun_path, instance->sock_path, UNIX_PATH_MAX);
> - addr.sun_path[UNIX_PATH_MAX-1] = '\0';
> -
> - result = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
> - if(result == -1) {
> - PERROR("connect");
> - }
> -
> - while(bytes != sizeof(msg))
> - bytes += send(fd, msg, sizeof(msg), 0);
> -
> - close(fd);
> -
> - return 0;
> -}
> -
> -struct libustd_instance
> -*libustd_new_instance(struct libustd_callbacks *callbacks,
> - char *sock_path)
> -{
> - struct libustd_instance *instance =
> - zmalloc(sizeof(struct libustd_instance));
> - if(!instance) {
> - return NULL;
> - }
> -
> - instance->callbacks = callbacks;
> - instance->quit_program = 0;
> - instance->is_init = 0;
> - instance->active_buffers = 0;
> - pthread_mutex_init(&instance->mutex, NULL);
> -
> - if (sock_path) {
> - instance->sock_path = strdup(sock_path);
> - } else {
> - instance->sock_path = NULL;
> - }
> -
> - return instance;
> -}
> -
> -static int init_ustd_socket(struct libustd_instance *instance)
> -{
> - char *name;
> -
> - if (instance->sock_path) {
> - if (asprintf(&name, "%s", instance->sock_path) < 0) {
> - ERR("ustcomm_init_ustd : asprintf failed (sock_path %s)",
> - instance->sock_path);
> - return -1;
> - }
> - } else {
> - int result;
> -
> - /* Only check if socket dir exists if we are using the default directory */
> - result = ensure_dir_exists(SOCK_DIR);
> - if (result == -1) {
> - ERR("Unable to create socket directory %s", SOCK_DIR);
> - return -1;
> - }
> -
> - if (asprintf(&name, "%s/%s", SOCK_DIR, "ustd") < 0) {
> - ERR("ustcomm_init_ustd : asprintf failed (%s/ustd)",
> - SOCK_DIR);
> - return -1;
> - }
> - }
> -
> - /* Set up epoll */
> - instance->epoll_fd = epoll_create(MAX_EVENTS);
> - if (instance->epoll_fd == -1) {
> - ERR("epoll_create failed, start instance bailing");
> - goto free_name;
> - }
> -
> - /* Create the named socket */
> - instance->listen_sock = ustcomm_init_named_socket(name,
> - instance->epoll_fd);
> - if(!instance->listen_sock) {
> - ERR("error initializing named socket at %s", name);
> - goto close_epoll;
> - }
> -
> - CDS_INIT_LIST_HEAD(&instance->connections);
> -
> - free(name);
> -
> - return 0;
> -
> -close_epoll:
> - close(instance->epoll_fd);
> -free_name:
> - free(name);
> -
> - return -1;
> -}
> -
> -int libustd_init_instance(struct libustd_instance *instance)
> -{
> - int result;
> - result = init_ustd_socket(instance);
> - if(result == -1) {
> - ERR("failed to initialize socket");
> - return 1;
> - }
> - instance->is_init = 1;
> - return 0;
> -}
> -
> diff --git a/libustd/lowlevel.c b/libustd/lowlevel.c
> deleted file mode 100644
> index a8abf92..0000000
> --- a/libustd/lowlevel.c
> +++ /dev/null
> @@ -1,143 +0,0 @@
> -/* Copyright (C) 2009 Pierre-Marc Fournier
> - *
> - * 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 <stdlib.h>
> -#include <assert.h>
> -#include <byteswap.h>
> -
> -#include "ust/ustd.h"
> -#include "buffers.h"
> -#include "tracer.h"
> -#include "usterr.h"
> -
> -/* This truncates to an offset in the buffer. */
> -#define USTD_BUFFER_TRUNC(offset, bufinfo) \
> - ((offset) & (~(((bufinfo)->subbuf_size*(bufinfo)->n_subbufs)-1)))
> -
> -#define LTT_MAGIC_NUMBER 0x00D6B7ED
> -#define LTT_REV_MAGIC_NUMBER 0xEDB7D600
> -
> -/* Returns the size of a subbuffer size. This is the size that
> - * will need to be written to disk.
> - *
> - * @subbuffer: pointer to the beginning of the subbuffer (the
> - * beginning of its header)
> - */
> -
> -size_t subbuffer_data_size(void *subbuf)
> -{
> - struct ltt_subbuffer_header *header = subbuf;
> - int reverse;
> - u32 data_size;
> -
> - if(header->magic_number == LTT_MAGIC_NUMBER) {
> - reverse = 0;
> - }
> - else if(header->magic_number == LTT_REV_MAGIC_NUMBER) {
> - reverse = 1;
> - }
> - else {
> - return -1;
> - }
> -
> - data_size = header->sb_size;
> - if(reverse)
> - data_size = bswap_32(data_size);
> -
> - return data_size;
> -}
> -
> -
> -void finish_consuming_dead_subbuffer(struct libustd_callbacks *callbacks, struct buffer_info *buf)
> -{
> - struct ust_buffer *ustbuf = buf->bufstruct_mem;
> -
> - long write_offset = uatomic_read(&ustbuf->offset);
> - long consumed_offset = uatomic_read(&ustbuf->consumed);
> -
> - long i_subbuf;
> -
> - DBG("processing dead buffer (%s)", buf->name);
> - DBG("consumed offset is %ld (%s)", consumed_offset, buf->name);
> - DBG("write offset is %ld (%s)", write_offset, buf->name);
> -
> - /* First subbuf that we need to consume now. It is not modulo'd.
> - * Consumed_offset is the next byte to consume. */
> - long first_subbuf = consumed_offset / buf->subbuf_size;
> - /* Last subbuf that we need to consume now. It is not modulo'd.
> - * Write_offset is the next place to write so write_offset-1 is the
> - * last place written. */
> - long last_subbuf = (write_offset - 1) / buf->subbuf_size;
> -
> - DBG("first_subbuf=%ld", first_subbuf);
> - DBG("last_subbuf=%ld", last_subbuf);
> -
> - if(last_subbuf - first_subbuf >= buf->n_subbufs) {
> - DBG("an overflow has occurred, nothing can be recovered");
> - return;
> - }
> -
> - /* Iterate on subbuffers to recover. */
> - for(i_subbuf = first_subbuf % buf->n_subbufs; ; i_subbuf++, i_subbuf %= buf->n_subbufs) {
> - /* commit_seq is the offset in the buffer of the end of the last sequential commit.
> - * Bytes beyond this limit cannot be recovered. This is a free-running counter. */
> - long commit_seq = uatomic_read(&ustbuf->commit_seq[i_subbuf]);
> -
> - unsigned long valid_length = buf->subbuf_size;
> - long n_subbufs_order = get_count_order(buf->n_subbufs);
> - long commit_seq_mask = (~0UL >> n_subbufs_order);
> -
> - struct ltt_subbuffer_header *header = (struct ltt_subbuffer_header *)((char *)buf->mem+i_subbuf*buf->subbuf_size);
> -
> - if((commit_seq & commit_seq_mask) == 0) {
> - /* There is nothing to do. */
> - /* FIXME: is this needed? */
> - break;
> - }
> -
> - /* Check if subbuf was fully written. This is from Mathieu's algorithm/paper. */
> - /* FIXME: not sure data_size = 0xffffffff when the buffer is not full. It might
> - * take the value of the header size initially */
> - if (((commit_seq - buf->subbuf_size) & commit_seq_mask)
> - - (USTD_BUFFER_TRUNC(consumed_offset, buf) >> n_subbufs_order) == 0
> - && header->data_size != 0xffffffff && header->sb_size != 0xffffffff) {
> - /* If it was, we only check the data_size. This is the amount of valid data at
> - * the beginning of the subbuffer. */
> - valid_length = header->data_size;
> - DBG("writing full subbuffer (%d) with valid_length = %ld", i_subbuf, valid_length);
> - }
> - else {
> - /* If the subbuffer was not fully written, then we don't check data_size because
> - * it hasn't been written yet. Instead we check commit_seq and use it to choose
> - * a value for data_size. The viewer will need this value when parsing.
> - */
> -
> - valid_length = commit_seq & (buf->subbuf_size-1);
> - DBG("writing unfull subbuffer (%d) with valid_length = %ld", i_subbuf, valid_length);
> - header->data_size = valid_length;
> - header->sb_size = PAGE_ALIGN(valid_length);
> - assert(i_subbuf == (last_subbuf % buf->n_subbufs));
> - }
> -
> - if(callbacks->on_read_partial_subbuffer)
> - callbacks->on_read_partial_subbuffer(callbacks, buf, i_subbuf, valid_length);
> -
> - if(i_subbuf == last_subbuf % buf->n_subbufs)
> - break;
> - }
> -}
> -
> diff --git a/libustd/lowlevel.h b/libustd/lowlevel.h
> deleted file mode 100644
> index a1d8da5..0000000
> --- a/libustd/lowlevel.h
> +++ /dev/null
> @@ -1,35 +0,0 @@
> -/*
> - * lowlevel libustd header file
> - *
> - * Copyright 2005-2010 -
> - * Mathieu Desnoyers <mathieu.desnoyers at polymtl.ca>
> - * Copyright 2010-
> - * Oumarou Dicko <oumarou.dicko at polymtl.ca>
> - * Michael Sills-Lavoie <michael.sills-lavoie at polymtl.ca>
> - * Alexis Halle <alexis.halle at polymtl.ca>
> - *
> - * 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 LOWLEVEL_H
> -#define LOWLEVEL_H
> -
> -#include <ust/ustd.h>
> -
> -void finish_consuming_dead_subbuffer(struct libustd_callbacks *callbacks, struct buffer_info *buf);
> -size_t subbuffer_data_size(void *subbuf);
> -
> -#endif /* LOWLEVEL_H */
> -
> diff --git a/tests/manual_mode_tracing.sh b/tests/manual_mode_tracing.sh
> index 3f203b1..09f0764 100755
> --- a/tests/manual_mode_tracing.sh
> +++ b/tests/manual_mode_tracing.sh
> @@ -34,11 +34,11 @@ TRACE_DIR="/tmp/ust-testsuite-manual-trace"
> rm -rf "$TRACE_DIR"
> mkdir "$TRACE_DIR"
>
> -pidfilepath="/tmp/ust-testsuite-$USER-$(date +%Y%m%d%H%M%S%N)-ustd-pid"
> +pidfilepath="/tmp/ust-testsuite-$USER-$(date +%Y%m%d%H%M%S%N)-ust-consumerd-pid"
> mkfifo -m 0600 "$pidfilepath"
>
> -ustd --pidfile "$pidfilepath" -o "$TRACE_DIR" >/dev/null 2>&1 &
> -USTD_PID="$(<$pidfilepath)"
> +ust-consumerd --pidfile "$pidfilepath" -o "$TRACE_DIR" >/dev/null 2>&1 &
> +UST_CONSUMERD_PID="$(<$pidfilepath)"
>
> LD_PRELOAD=/usr/local/lib/libust.so.0.0.0:/usr/local/lib/libustinstr-malloc.so find -L / >/dev/null 2>&1 &
> PID=$!
> @@ -54,7 +54,7 @@ sleep 0.5
> okx ustctl --stop-trace $PID
> okx ustctl --destroy-trace $PID
> kill $PID
> -kill -SIGTERM $USTD_PID
> -wait $USTD_PID
> +kill -SIGTERM $UST_CONSUMERD_PID
> +wait $UST_CONSUMERD_PID
>
> trace_matches -N "ust.malloc" "^ust.malloc:" "$TRACE_DIR"
> diff --git a/tests/runtests b/tests/runtests
> index 9560c46..afc1e21 100755
> --- a/tests/runtests
> +++ b/tests/runtests
> @@ -37,7 +37,7 @@ simple_harness_run test-libustinstr-malloc/test-libustinstr-malloc.sh
>
> simple_harness_run ./manual_mode_tracing.sh
>
> -simple_harness_run ./valgrind_ustd.sh
> +simple_harness_run ./valgrind_ust-consumerd.sh
>
> simple_harness_run dlopen/dlopen.sh
>
> diff --git a/tests/valgrind_ust-consumerd.sh b/tests/valgrind_ust-consumerd.sh
> new file mode 100755
> index 0000000..53b1208
> --- /dev/null
> +++ b/tests/valgrind_ust-consumerd.sh
> @@ -0,0 +1,54 @@
> +#!/bin/bash
> +#
> +# Copyright 2010 Ericsson AB
> +#
> +# This file is part of LTTng-UST.
> +#
> +# LTTng-UST 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.
> +#
> +# LTTng-UST 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 LTTng-UST. If not, see <http://www.gnu.org/licenses/>.
> +
> +TESTDIR=$(dirname $0)
> +
> +source $TESTDIR/test_functions.sh
> +source $TESTDIR/tap.sh
> +
> +starttest "ust-consumerd valgrind check"
> +
> +plan_tests 2
> +
> +TRACE_DIR="/tmp/ust-testsuite-ust-consumerdvalgrind-trace"
> +rm -rf "$TRACE_DIR"
> +mkdir "$TRACE_DIR"
> +
> +pidfilepath="/tmp/ust-testsuite-$USER-$(date +%Y%m%d%H%M%S%N)-ust-consumerd-pid"
> +mkfifo -m 0600 "$pidfilepath"
> +
> +VALG_OUT=/tmp/ust-testsuite-valg.txt
> +valgrind --suppressions=$TESTDIR/valgrind_suppress.txt -q ust-consumerd --pidfile "$pidfilepath" -o "$TRACE_DIR" >/dev/null 2>"$VALG_OUT" &
> +VALG_PID=$!
> +UST_CONSUMERD_PID="$(<$pidfilepath)"
> +
> +okx usttrace -s $TESTDIR/basic/.libs/basic
> +
> +kill -SIGTERM $UST_CONSUMERD_PID
> +wait $!
> +
> +echo "Valgrind output is in $VALG_OUT"
> +if [ -z "$(<$VALG_OUT)" ]; then
> + pass "Valgrind found no errors in ust-consumerd"
> +else
> + fail "Valgrind found errors in ust-consumerd:"
> + cat $VALG_OUT | while read; do
> + diag $REPLY
> + done
> +fi
> diff --git a/tests/valgrind_ustd.sh b/tests/valgrind_ustd.sh
> deleted file mode 100755
> index 541d8ca..0000000
> --- a/tests/valgrind_ustd.sh
> +++ /dev/null
> @@ -1,54 +0,0 @@
> -#!/bin/bash
> -#
> -# Copyright 2010 Ericsson AB
> -#
> -# This file is part of LTTng-UST.
> -#
> -# LTTng-UST 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.
> -#
> -# LTTng-UST 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 LTTng-UST. If not, see <http://www.gnu.org/licenses/>.
> -
> -TESTDIR=$(dirname $0)
> -
> -source $TESTDIR/test_functions.sh
> -source $TESTDIR/tap.sh
> -
> -starttest "ustd valgrind check"
> -
> -plan_tests 2
> -
> -TRACE_DIR="/tmp/ust-testsuite-ustdvalgrind-trace"
> -rm -rf "$TRACE_DIR"
> -mkdir "$TRACE_DIR"
> -
> -pidfilepath="/tmp/ust-testsuite-$USER-$(date +%Y%m%d%H%M%S%N)-ustd-pid"
> -mkfifo -m 0600 "$pidfilepath"
> -
> -VALG_OUT=/tmp/ust-testsuite-valg.txt
> -valgrind --suppressions=$TESTDIR/valgrind_suppress.txt -q ustd --pidfile "$pidfilepath" -o "$TRACE_DIR" >/dev/null 2>"$VALG_OUT" &
> -VALG_PID=$!
> -USTD_PID="$(<$pidfilepath)"
> -
> -okx usttrace -s $TESTDIR/basic/.libs/basic
> -
> -kill -SIGTERM $USTD_PID
> -wait $!
> -
> -echo "Valgrind output is in $VALG_OUT"
> -if [ -z "$(<$VALG_OUT)" ]; then
> - pass "Valgrind found no errors in ustd"
> -else
> - fail "Valgrind found errors in ustd:"
> - cat $VALG_OUT | while read; do
> - diag $REPLY
> - done
> -fi
> diff --git a/ust-consumerd/Makefile.am b/ust-consumerd/Makefile.am
> new file mode 100644
> index 0000000..01e3b82
> --- /dev/null
> +++ b/ust-consumerd/Makefile.am
> @@ -0,0 +1,14 @@
> +AM_CPPFLAGS = -I$(top_srcdir)/libust -I$(top_srcdir)/libustcomm \
> + -I$(top_srcdir)/include -I$(top_srcdir)/libustconsumer
> +AM_CFLAGS = -fno-strict-aliasing
> +
> +bin_PROGRAMS = ust-consumerd
> +
> +ust_consumerd_SOURCES = ust-consumerd.c
> +
> +ust_consumerd_LDADD = \
> + $(top_builddir)/snprintf/libustsnprintf.la \
> + $(top_builddir)/libustcomm/libustcomm.la \
> + $(top_builddir)/libustconsumer/libustconsumer.la
> +
> +ust_consumerd_CFLAGS = -DUST_COMPONENT=ust-consumerd -fno-strict-aliasing
> diff --git a/ust-consumerd/README b/ust-consumerd/README
> new file mode 100644
> index 0000000..6df4015
> --- /dev/null
> +++ b/ust-consumerd/README
> @@ -0,0 +1,3 @@
> +This is ust-consumerd, the UST consumer daemon.
> +
> +This daemon is used to collect the traces for the traced programs and write them to disk.
> diff --git a/ust-consumerd/ust-consumerd.c b/ust-consumerd/ust-consumerd.c
> new file mode 100644
> index 0000000..fae4efa
> --- /dev/null
> +++ b/ust-consumerd/ust-consumerd.c
> @@ -0,0 +1,505 @@
> +/* Copyright (C) 2009 Pierre-Marc Fournier
> + * 2010 Alexis Halle
> + *
> + * 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
> + */
> +
> +#define _GNU_SOURCE
> +
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/shm.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <signal.h>
> +
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <errno.h>
> +#include <assert.h>
> +#include <getopt.h>
> +
> +#include "ust/ustconsumer.h"
> +#include "usterr.h"
> +
> +char *sock_path=NULL;
> +char *trace_path=NULL;
> +int daemon_mode = 0;
> +char *pidfile = NULL;
> +
> +struct ustconsumer_instance *instance;
> +
> +struct buffer_info_local {
> + /* output file */
> + int file_fd;
> + /* the offset we must truncate to, to unput the last subbuffer */
> + off_t previous_offset;
> +};
> +
> +static int write_pidfile(const char *file_name, pid_t pid)
> +{
> + FILE *pidfp;
> +
> + pidfp = fopen(file_name, "w");
> + if(!pidfp) {
> + PERROR("fopen (%s)", file_name);
> + WARN("killing child process");
> + return -1;
> + }
> +
> + fprintf(pidfp, "%d\n", pid);
> +
> + fclose(pidfp);
> +
> + return 0;
> +}
> +
> +int create_dir_if_needed(char *dir)
> +{
> + int result;
> + result = mkdir(dir, 0777);
> + if(result == -1) {
> + if(errno != EEXIST) {
> + PERROR("mkdir");
> + return -1;
> + }
> + }
> +
> + return 0;
> +}
> +
> +int unwrite_last_subbuffer(struct buffer_info *buf)
> +{
> + int result;
> + struct buffer_info_local *buf_local = buf->user_data;
> +
> + result = ftruncate(buf_local->file_fd, buf_local->previous_offset);
> + if(result == -1) {
> + PERROR("ftruncate");
> + return -1;
> + }
> +
> + result = lseek(buf_local->file_fd, buf_local->previous_offset, SEEK_SET);
> + if(result == (int)(off_t)-1) {
> + PERROR("lseek");
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +int write_current_subbuffer(struct buffer_info *buf)
> +{
> + int result;
> + struct buffer_info_local *buf_local = buf->user_data;
> +
> + void *subbuf_mem = buf->mem + (buf->consumed_old & (buf->n_subbufs * buf->subbuf_size-1));
> +
> + size_t cur_sb_size = subbuffer_data_size(subbuf_mem);
> +
> + off_t cur_offset = lseek(buf_local->file_fd, 0, SEEK_CUR);
> + if(cur_offset == (off_t)-1) {
> + PERROR("lseek");
> + return -1;
> + }
> +
> + buf_local->previous_offset = cur_offset;
> + DBG("previous_offset: %ld", cur_offset);
> +
> + result = patient_write(buf_local->file_fd, subbuf_mem, cur_sb_size);
> + if(result == -1) {
> + PERROR("write");
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +int on_read_subbuffer(struct ustconsumer_callbacks *data, struct buffer_info *buf)
> +{
> + return write_current_subbuffer(buf);
> +}
> +
> +int on_read_partial_subbuffer(struct ustconsumer_callbacks *data, struct buffer_info *buf,
> + long subbuf_index, unsigned long valid_length)
> +{
> + struct buffer_info_local *buf_local = buf->user_data;
> + char *tmp;
> + int result;
> + unsigned long pad_size;
> +
> + result = patient_write(buf_local->file_fd, buf->mem + subbuf_index * buf->subbuf_size, valid_length);
> + if(result == -1) {
> + ERR("Error writing to buffer file");
> + return;
> + }
> +
> + /* pad with empty bytes */
> + pad_size = PAGE_ALIGN(valid_length)-valid_length;
> + if(pad_size) {
> + tmp = zmalloc(pad_size);
> + result = patient_write(buf_local->file_fd, tmp, pad_size);
> + if(result == -1) {
> + ERR("Error writing to buffer file");
> + return;
> + }
> + free(tmp);
> + }
> +
> +}
> +
> +int on_open_buffer(struct ustconsumer_callbacks *data, struct buffer_info *buf)
> +{
> + char *tmp;
> + int result;
> + int fd;
> + struct buffer_info_local *buf_local =
> + zmalloc(sizeof(struct buffer_info_local));
> +
> + if(!buf_local) {
> + ERR("could not allocate buffer_info_local struct");
> + return 1;
> + }
> +
> + buf->user_data = buf_local;
> +
> + /* open file for output */
> + if(!trace_path) {
> + /* Only create the directory if using the default path, because
> + * of the risk of typo when using trace path override. We don't
> + * want to risk creating plenty of useless directories in that case.
> + */
> + result = create_dir_if_needed(USTCONSUMER_DEFAULT_TRACE_PATH);
> + if(result == -1) {
> + ERR("could not create directory %s", USTCONSUMER_DEFAULT_TRACE_PATH);
> + return 1;
> + }
> +
> + trace_path = USTCONSUMER_DEFAULT_TRACE_PATH;
> + }
> +
> + if (asprintf(&tmp, "%s/%u_%lld", trace_path, buf->pid, buf->pidunique) < 0) {
> + ERR("on_open_buffer : asprintf failed (%s/%u_%lld)",
> + trace_path, buf->pid, buf->pidunique);
> + return 1;
> + }
> + result = create_dir_if_needed(tmp);
> + if(result == -1) {
> + ERR("could not create directory %s", tmp);
> + free(tmp);
> + return 1;
> + }
> + free(tmp);
> +
> + if (asprintf(&tmp, "%s/%u_%lld/%s", trace_path, buf->pid, buf->pidunique, buf->name) < 0) {
> + ERR("on_open_buffer : asprintf failed (%s/%u_%lld/%s)",
> + trace_path, buf->pid, buf->pidunique, buf->name);
> + return 1;
> + }
> + result = fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 00600);
> + if(result == -1) {
> + PERROR("open");
> + ERR("failed opening trace file %s", tmp);
> + return 1;
> + }
> + buf_local->file_fd = fd;
> + free(tmp);
> +
> + return 0;
> +}
> +
> +int on_close_buffer(struct ustconsumer_callbacks *data, struct buffer_info *buf)
> +{
> + struct buffer_info_local *buf_local = buf->user_data;
> + int result = close(buf_local->file_fd);
> + free(buf_local);
> + if(result == -1) {
> + PERROR("close");
> + }
> + return 0;
> +}
> +
> +int on_put_error(struct ustconsumer_callbacks *data, struct buffer_info *buf)
> +{
> + unwrite_last_subbuffer(buf);
> +}
> +
> +struct ustconsumer_callbacks *new_callbacks()
> +{
> + struct ustconsumer_callbacks *callbacks =
> + zmalloc(sizeof(struct ustconsumer_callbacks));
> +
> + if(!callbacks)
> + return NULL;
> +
> + callbacks->on_open_buffer = on_open_buffer;
> + callbacks->on_close_buffer = on_close_buffer;
> + callbacks->on_read_subbuffer = on_read_subbuffer;
> + callbacks->on_read_partial_subbuffer = on_read_partial_subbuffer;
> + callbacks->on_put_error = on_put_error;
> + callbacks->on_new_thread = NULL;
> + callbacks->on_close_thread = NULL;
> + callbacks->on_trace_end = NULL;
> +
> + return callbacks;
> +
> +}
> +
> +int is_directory(const char *dir)
> +{
> + int result;
> + struct stat st;
> +
> + result = stat(dir, &st);
> + if(result == -1) {
> + PERROR("stat");
> + return 0;
> + }
> +
> + if(!S_ISDIR(st.st_mode)) {
> + return 0;
> + }
> +
> + return 1;
> +}
> +
> +void usage(void)
> +{
> + fprintf(stderr, "Usage:\nust-consumerd OPTIONS\n\nOptions:\n"
> + "\t-h\t\tDisplay this usage.\n"
> + "\t-o DIR\t\tSpecify the directory where to output the traces.\n"
> + "\t-s PATH\t\tSpecify the path to use for the daemon socket.\n"
> + "\t-d\t\tStart as a daemon.\n"
> + "\t--pidfile FILE\tWrite the PID in this file (when using -d).\n");
> +}
> +
> +int parse_args(int argc, char **argv)
> +{
> + int c;
> +
> + while (1) {
> + int option_index = 0;
> + static struct option long_options[] = {
> + {"pidfile", 1, 0, 'p'},
> + {"help", 0, 0, 'h'},
> + {"version", 0, 0, 'V'},
> + {0, 0, 0, 0}
> + };
> +
> + c = getopt_long(argc, argv, "hs:o:d", long_options, &option_index);
> + if (c == -1)
> + break;
> +
> + switch (c) {
> + case 0:
> + printf("option %s", long_options[option_index].name);
> + if (optarg)
> + printf(" with arg %s", optarg);
> + printf("\n");
> + break;
> + case 's':
> + sock_path = optarg;
> + break;
> + case 'o':
> + trace_path = optarg;
> + if(!is_directory(trace_path)) {
> + ERR("Not a valid directory. (%s)", trace_path);
> + return -1;
> + }
> + break;
> + case 'd':
> + daemon_mode = 1;
> + break;
> + case 'p':
> + pidfile = strdup(optarg);
> + break;
> + case 'h':
> + usage();
> + exit(0);
> + case 'V':
> + printf("Version 0.0\n");
> + break;
> +
> + default:
> + /* unknown option or other error; error is
> + printed by getopt, just return */
> + return -1;
> + }
> + }
> +
> + return 0;
> +}
> +
> +void sigterm_handler(int sig)
> +{
> + ustconsumer_stop_instance(instance, 0);
> +}
> +
> +int start_ustconsumer(int fd)
> +{
> + int result;
> + sigset_t sigset;
> + struct sigaction sa;
> +
> + struct ustconsumer_callbacks *callbacks = new_callbacks();
> + if(!callbacks) {
> + PERROR("new_callbacks");
> + return 1;
> + }
> +
> + result = sigemptyset(&sigset);
> + if(result == -1) {
> + PERROR("sigemptyset");
> + return 1;
> + }
> + sa.sa_handler = sigterm_handler;
> + sa.sa_mask = sigset;
> + sa.sa_flags = 0;
> + result = sigaction(SIGTERM, &sa, NULL);
> + if(result == -1) {
> + PERROR("sigaction");
> + return 1;
> + }
> + result = sigaction(SIGINT, &sa, NULL);
> + if(result == -1) {
> + PERROR("sigaction");
> + return 1;
> + }
> +
> + instance = ustconsumer_new_instance(callbacks, sock_path);
> + if(!instance) {
> + ERR("failed to create ustconsumer instance");
> + return 1;
> + }
> +
> + result = ustconsumer_init_instance(instance);
> + if(result) {
> + ERR("failed to initialize ustconsumer instance");
> + return 1;
> + }
> +
> + /* setup handler for SIGPIPE */
> + result = sigemptyset(&sigset);
> + if(result == -1) {
> + PERROR("sigemptyset");
> + return 1;
> + }
> + result = sigaddset(&sigset, SIGPIPE);
> + if(result == -1) {
> + PERROR("sigaddset");
> + return 1;
> + }
> + result = sigprocmask(SIG_BLOCK, &sigset, NULL);
> + if(result == -1) {
> + PERROR("sigprocmask");
> + return 1;
> + }
> +
> + /* Write pidfile */
> + if(pidfile) {
> + result = write_pidfile(pidfile, getpid());
> + if(result == -1) {
> + ERR("failed to write pidfile");
> + return 1;
> + }
> + }
> +
> + /* Notify parent that we are successfully started. */
> + if(fd != -1) {
> + /* write any one character */
> + result = write(fd, "!", 1);
> + if(result == -1) {
> + PERROR("write");
> + return -1;
> + }
> + if(result != 1) {
> + ERR("Problem sending confirmation of daemon start to parent");
> + return -1;
> + }
> + result = close(fd);
> + if(result == -1) {
> + PERROR("close");
> + }
> + }
> +
> + ustconsumer_start_instance(instance);
> +
> + free(callbacks);
> +
> + return 0;
> +}
> +
> +int start_ustconsumer_daemon()
> +{
> + int result;
> + int fd[2];
> + pid_t child_pid;
> +
> + result = pipe(fd);
> +
> + result = child_pid = fork();
> + if(result == -1) {
> + PERROR("fork");
> + return -1;
> + }
> + else if(result == 0) {
> + return start_ustconsumer(fd[1]);
> + }
> + else {
> + char buf;
> +
> + result = read(fd[0], &buf, 1);
> + if(result == -1) {
> + PERROR("read");
> + return -1;
> + }
> + if(result != 1) {
> + ERR("did not receive valid confirmation that the daemon is started");
> + return -1;
> + }
> +
> + result = close(fd[0]);
> + if(result == -1) {
> + PERROR("close");
> + }
> +
> + DBG("The daemon is now successfully started");
> + }
> +
> + /* Wait for confirmation that the server is ready. */
> +
> +
> + return 0;
> +}
> +
> +int main(int argc, char **argv)
> +{
> + int result;
> +
> + result = parse_args(argc, argv);
> + if(result == -1) {
> + exit(1);
> + }
> +
> + if(daemon_mode) {
> + result = start_ustconsumer_daemon();
> + }
> + else {
> + result = start_ustconsumer(-1);
> + }
> +
> + return result;
> +}
> diff --git a/ustd/Makefile.am b/ustd/Makefile.am
> deleted file mode 100644
> index 991c717..0000000
> --- a/ustd/Makefile.am
> +++ /dev/null
> @@ -1,14 +0,0 @@
> -AM_CPPFLAGS = -I$(top_srcdir)/libust -I$(top_srcdir)/libustcomm \
> - -I$(top_srcdir)/include -I$(top_srcdir)/libustd
> -AM_CFLAGS = -fno-strict-aliasing
> -
> -bin_PROGRAMS = ustd
> -
> -ustd_SOURCES = ustd.c
> -
> -ustd_LDADD = \
> - $(top_builddir)/snprintf/libustsnprintf.la \
> - $(top_builddir)/libustcomm/libustcomm.la \
> - $(top_builddir)/libustd/libustd.la
> -
> -ustd_CFLAGS = -DUST_COMPONENT=ustd -fno-strict-aliasing
> diff --git a/ustd/README b/ustd/README
> deleted file mode 100644
> index 8fcd218..0000000
> --- a/ustd/README
> +++ /dev/null
> @@ -1,3 +0,0 @@
> -This is ustd, the UST daemon.
> -
> -This daemon is used to collect the traces for the traced programs.
> diff --git a/ustd/ustd.c b/ustd/ustd.c
> deleted file mode 100644
> index e75fd9d..0000000
> --- a/ustd/ustd.c
> +++ /dev/null
> @@ -1,505 +0,0 @@
> -/* Copyright (C) 2009 Pierre-Marc Fournier
> - * 2010 Alexis Halle
> - *
> - * 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
> - */
> -
> -#define _GNU_SOURCE
> -
> -#include <sys/types.h>
> -#include <sys/stat.h>
> -#include <sys/shm.h>
> -#include <fcntl.h>
> -#include <unistd.h>
> -#include <signal.h>
> -
> -#include <stdlib.h>
> -#include <stdio.h>
> -#include <string.h>
> -#include <errno.h>
> -#include <assert.h>
> -#include <getopt.h>
> -
> -#include "ust/ustd.h"
> -#include "usterr.h"
> -
> -char *sock_path=NULL;
> -char *trace_path=NULL;
> -int daemon_mode = 0;
> -char *pidfile = NULL;
> -
> -struct libustd_instance *instance;
> -
> -struct buffer_info_local {
> - /* output file */
> - int file_fd;
> - /* the offset we must truncate to, to unput the last subbuffer */
> - off_t previous_offset;
> -};
> -
> -static int write_pidfile(const char *file_name, pid_t pid)
> -{
> - FILE *pidfp;
> -
> - pidfp = fopen(file_name, "w");
> - if(!pidfp) {
> - PERROR("fopen (%s)", file_name);
> - WARN("killing child process");
> - return -1;
> - }
> -
> - fprintf(pidfp, "%d\n", pid);
> -
> - fclose(pidfp);
> -
> - return 0;
> -}
> -
> -int create_dir_if_needed(char *dir)
> -{
> - int result;
> - result = mkdir(dir, 0777);
> - if(result == -1) {
> - if(errno != EEXIST) {
> - PERROR("mkdir");
> - return -1;
> - }
> - }
> -
> - return 0;
> -}
> -
> -int unwrite_last_subbuffer(struct buffer_info *buf)
> -{
> - int result;
> - struct buffer_info_local *buf_local = buf->user_data;
> -
> - result = ftruncate(buf_local->file_fd, buf_local->previous_offset);
> - if(result == -1) {
> - PERROR("ftruncate");
> - return -1;
> - }
> -
> - result = lseek(buf_local->file_fd, buf_local->previous_offset, SEEK_SET);
> - if(result == (int)(off_t)-1) {
> - PERROR("lseek");
> - return -1;
> - }
> -
> - return 0;
> -}
> -
> -int write_current_subbuffer(struct buffer_info *buf)
> -{
> - int result;
> - struct buffer_info_local *buf_local = buf->user_data;
> -
> - void *subbuf_mem = buf->mem + (buf->consumed_old & (buf->n_subbufs * buf->subbuf_size-1));
> -
> - size_t cur_sb_size = subbuffer_data_size(subbuf_mem);
> -
> - off_t cur_offset = lseek(buf_local->file_fd, 0, SEEK_CUR);
> - if(cur_offset == (off_t)-1) {
> - PERROR("lseek");
> - return -1;
> - }
> -
> - buf_local->previous_offset = cur_offset;
> - DBG("previous_offset: %ld", cur_offset);
> -
> - result = patient_write(buf_local->file_fd, subbuf_mem, cur_sb_size);
> - if(result == -1) {
> - PERROR("write");
> - return -1;
> - }
> -
> - return 0;
> -}
> -
> -int on_read_subbuffer(struct libustd_callbacks *data, struct buffer_info *buf)
> -{
> - return write_current_subbuffer(buf);
> -}
> -
> -int on_read_partial_subbuffer(struct libustd_callbacks *data, struct buffer_info *buf,
> - long subbuf_index, unsigned long valid_length)
> -{
> - struct buffer_info_local *buf_local = buf->user_data;
> - char *tmp;
> - int result;
> - unsigned long pad_size;
> -
> - result = patient_write(buf_local->file_fd, buf->mem + subbuf_index * buf->subbuf_size, valid_length);
> - if(result == -1) {
> - ERR("Error writing to buffer file");
> - return;
> - }
> -
> - /* pad with empty bytes */
> - pad_size = PAGE_ALIGN(valid_length)-valid_length;
> - if(pad_size) {
> - tmp = zmalloc(pad_size);
> - result = patient_write(buf_local->file_fd, tmp, pad_size);
> - if(result == -1) {
> - ERR("Error writing to buffer file");
> - return;
> - }
> - free(tmp);
> - }
> -
> -}
> -
> -int on_open_buffer(struct libustd_callbacks *data, struct buffer_info *buf)
> -{
> - char *tmp;
> - int result;
> - int fd;
> - struct buffer_info_local *buf_local =
> - zmalloc(sizeof(struct buffer_info_local));
> -
> - if(!buf_local) {
> - ERR("could not allocate buffer_info_local struct");
> - return 1;
> - }
> -
> - buf->user_data = buf_local;
> -
> - /* open file for output */
> - if(!trace_path) {
> - /* Only create the directory if using the default path, because
> - * of the risk of typo when using trace path override. We don't
> - * want to risk creating plenty of useless directories in that case.
> - */
> - result = create_dir_if_needed(USTD_DEFAULT_TRACE_PATH);
> - if(result == -1) {
> - ERR("could not create directory %s", USTD_DEFAULT_TRACE_PATH);
> - return 1;
> - }
> -
> - trace_path = USTD_DEFAULT_TRACE_PATH;
> - }
> -
> - if (asprintf(&tmp, "%s/%u_%lld", trace_path, buf->pid, buf->pidunique) < 0) {
> - ERR("on_open_buffer : asprintf failed (%s/%u_%lld)",
> - trace_path, buf->pid, buf->pidunique);
> - return 1;
> - }
> - result = create_dir_if_needed(tmp);
> - if(result == -1) {
> - ERR("could not create directory %s", tmp);
> - free(tmp);
> - return 1;
> - }
> - free(tmp);
> -
> - if (asprintf(&tmp, "%s/%u_%lld/%s", trace_path, buf->pid, buf->pidunique, buf->name) < 0) {
> - ERR("on_open_buffer : asprintf failed (%s/%u_%lld/%s)",
> - trace_path, buf->pid, buf->pidunique, buf->name);
> - return 1;
> - }
> - result = fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 00600);
> - if(result == -1) {
> - PERROR("open");
> - ERR("failed opening trace file %s", tmp);
> - return 1;
> - }
> - buf_local->file_fd = fd;
> - free(tmp);
> -
> - return 0;
> -}
> -
> -int on_close_buffer(struct libustd_callbacks *data, struct buffer_info *buf)
> -{
> - struct buffer_info_local *buf_local = buf->user_data;
> - int result = close(buf_local->file_fd);
> - free(buf_local);
> - if(result == -1) {
> - PERROR("close");
> - }
> - return 0;
> -}
> -
> -int on_put_error(struct libustd_callbacks *data, struct buffer_info *buf)
> -{
> - unwrite_last_subbuffer(buf);
> -}
> -
> -struct libustd_callbacks *new_callbacks()
> -{
> - struct libustd_callbacks *callbacks =
> - zmalloc(sizeof(struct libustd_callbacks));
> -
> - if(!callbacks)
> - return NULL;
> -
> - callbacks->on_open_buffer = on_open_buffer;
> - callbacks->on_close_buffer = on_close_buffer;
> - callbacks->on_read_subbuffer = on_read_subbuffer;
> - callbacks->on_read_partial_subbuffer = on_read_partial_subbuffer;
> - callbacks->on_put_error = on_put_error;
> - callbacks->on_new_thread = NULL;
> - callbacks->on_close_thread = NULL;
> - callbacks->on_trace_end = NULL;
> -
> - return callbacks;
> -
> -}
> -
> -int is_directory(const char *dir)
> -{
> - int result;
> - struct stat st;
> -
> - result = stat(dir, &st);
> - if(result == -1) {
> - PERROR("stat");
> - return 0;
> - }
> -
> - if(!S_ISDIR(st.st_mode)) {
> - return 0;
> - }
> -
> - return 1;
> -}
> -
> -void usage(void)
> -{
> - fprintf(stderr, "Usage:\nustd OPTIONS\n\nOptions:\n"
> - "\t-h\t\tDisplay this usage.\n"
> - "\t-o DIR\t\tSpecify the directory where to output the traces.\n"
> - "\t-s PATH\t\tSpecify the path to use for the daemon socket.\n"
> - "\t-d\t\tStart as a daemon.\n"
> - "\t--pidfile FILE\tWrite the PID in this file (when using -d).\n");
> -}
> -
> -int parse_args(int argc, char **argv)
> -{
> - int c;
> -
> - while (1) {
> - int option_index = 0;
> - static struct option long_options[] = {
> - {"pidfile", 1, 0, 'p'},
> - {"help", 0, 0, 'h'},
> - {"version", 0, 0, 'V'},
> - {0, 0, 0, 0}
> - };
> -
> - c = getopt_long(argc, argv, "hs:o:d", long_options, &option_index);
> - if (c == -1)
> - break;
> -
> - switch (c) {
> - case 0:
> - printf("option %s", long_options[option_index].name);
> - if (optarg)
> - printf(" with arg %s", optarg);
> - printf("\n");
> - break;
> - case 's':
> - sock_path = optarg;
> - break;
> - case 'o':
> - trace_path = optarg;
> - if(!is_directory(trace_path)) {
> - ERR("Not a valid directory. (%s)", trace_path);
> - return -1;
> - }
> - break;
> - case 'd':
> - daemon_mode = 1;
> - break;
> - case 'p':
> - pidfile = strdup(optarg);
> - break;
> - case 'h':
> - usage();
> - exit(0);
> - case 'V':
> - printf("Version 0.0\n");
> - break;
> -
> - default:
> - /* unknown option or other error; error is
> - printed by getopt, just return */
> - return -1;
> - }
> - }
> -
> - return 0;
> -}
> -
> -void sigterm_handler(int sig)
> -{
> - libustd_stop_instance(instance, 0);
> -}
> -
> -int start_ustd(int fd)
> -{
> - int result;
> - sigset_t sigset;
> - struct sigaction sa;
> -
> - struct libustd_callbacks *callbacks = new_callbacks();
> - if(!callbacks) {
> - PERROR("new_callbacks");
> - return 1;
> - }
> -
> - result = sigemptyset(&sigset);
> - if(result == -1) {
> - PERROR("sigemptyset");
> - return 1;
> - }
> - sa.sa_handler = sigterm_handler;
> - sa.sa_mask = sigset;
> - sa.sa_flags = 0;
> - result = sigaction(SIGTERM, &sa, NULL);
> - if(result == -1) {
> - PERROR("sigaction");
> - return 1;
> - }
> - result = sigaction(SIGINT, &sa, NULL);
> - if(result == -1) {
> - PERROR("sigaction");
> - return 1;
> - }
> -
> - instance = libustd_new_instance(callbacks, sock_path);
> - if(!instance) {
> - ERR("failed to create libustd instance");
> - return 1;
> - }
> -
> - result = libustd_init_instance(instance);
> - if(result) {
> - ERR("failed to initialize libustd instance");
> - return 1;
> - }
> -
> - /* setup handler for SIGPIPE */
> - result = sigemptyset(&sigset);
> - if(result == -1) {
> - PERROR("sigemptyset");
> - return 1;
> - }
> - result = sigaddset(&sigset, SIGPIPE);
> - if(result == -1) {
> - PERROR("sigaddset");
> - return 1;
> - }
> - result = sigprocmask(SIG_BLOCK, &sigset, NULL);
> - if(result == -1) {
> - PERROR("sigprocmask");
> - return 1;
> - }
> -
> - /* Write pidfile */
> - if(pidfile) {
> - result = write_pidfile(pidfile, getpid());
> - if(result == -1) {
> - ERR("failed to write pidfile");
> - return 1;
> - }
> - }
> -
> - /* Notify parent that we are successfully started. */
> - if(fd != -1) {
> - /* write any one character */
> - result = write(fd, "!", 1);
> - if(result == -1) {
> - PERROR("write");
> - return -1;
> - }
> - if(result != 1) {
> - ERR("Problem sending confirmation of daemon start to parent");
> - return -1;
> - }
> - result = close(fd);
> - if(result == -1) {
> - PERROR("close");
> - }
> - }
> -
> - libustd_start_instance(instance);
> -
> - free(callbacks);
> -
> - return 0;
> -}
> -
> -int start_ustd_daemon()
> -{
> - int result;
> - int fd[2];
> - pid_t child_pid;
> -
> - result = pipe(fd);
> -
> - result = child_pid = fork();
> - if(result == -1) {
> - PERROR("fork");
> - return -1;
> - }
> - else if(result == 0) {
> - return start_ustd(fd[1]);
> - }
> - else {
> - char buf;
> -
> - result = read(fd[0], &buf, 1);
> - if(result == -1) {
> - PERROR("read");
> - return -1;
> - }
> - if(result != 1) {
> - ERR("did not receive valid confirmation that the daemon is started");
> - return -1;
> - }
> -
> - result = close(fd[0]);
> - if(result == -1) {
> - PERROR("close");
> - }
> -
> - DBG("The daemon is now successfully started");
> - }
> -
> - /* Wait for confirmation that the server is ready. */
> -
> -
> - return 0;
> -}
> -
> -int main(int argc, char **argv)
> -{
> - int result;
> -
> - result = parse_args(argc, argv);
> - if(result == -1) {
> - exit(1);
> - }
> -
> - if(daemon_mode) {
> - result = start_ustd_daemon();
> - }
> - else {
> - result = start_ustd(-1);
> - }
> -
> - return result;
> -}
> diff --git a/usttrace b/usttrace
> index 94404dd..5d6729e 100755
> --- a/usttrace
> +++ b/usttrace
> @@ -9,14 +9,14 @@ function error() {
>
> function sighandler() {
> echo "Caught Ctrl-C"
> - if [ -z "$USTDPID" ]; then
> - USTDPID="$(<$pidfilepath)"
> + if [ -z "$UST_CONSUMERDPID" ]; then
> + UST_CONSUMERDPID="$(<$pidfilepath)"
> fi
> # Tell the daemon to die
> - kill -SIGTERM "$USTDPID"
> + kill -SIGTERM "$UST_CONSUMERDPID"
>
> - echo "Waiting for ustd to shutdown..."
> - wait "$USTDPID"
> + echo "Waiting for ust-consumerd to shutdown..."
> + wait "$UST_CONSUMERDPID"
>
> rm "$pidfilepath"
>
> @@ -24,17 +24,17 @@ function sighandler() {
> }
>
> USTTRACE_DIR="$(dirname $0)"
> -if [ -x "${USTTRACE_DIR}/ustd/ustd" ] ; then
> +if [ -x "${USTTRACE_DIR}/ust-consumerd/ust-consumerd" ] ; then
> # Use the not installed libraries instead
> - USTD="${USTTRACE_DIR}/ustd/ustd"
> + UST_CONSUMERD="${USTTRACE_DIR}/ust-consumerd/ust-consumerd"
> LIBINTERFORK_PATH="${USTTRACE_DIR}/libustfork/.libs/libustfork.so"
> LIBMALLOCWRAP_PATH="${USTTRACE_DIR}/libustinstr-malloc/.libs/libustinstr-malloc.so"
> LIBUST_PATH="${USTTRACE_DIR}/libust/.libs/libust.so"
> else
> # Use the libraries that the dynamic link finds
> - USTD="ustd"
> - if [ ! -x "$(which ustd 2>/dev/null)" ]; then
> - error "cannot find an executable ustd; make sure its location is in the PATH"
> + UST_CONSUMERD="ust-consumerd"
> + if [ ! -x "$(which ust-consumerd 2>/dev/null)" ]; then
> + error "cannot find an executable ust-consumerd; make sure its location is in the PATH"
> exit 1
> fi
> LIBINTERFORK_PATH="libustfork.so"
> @@ -117,25 +117,25 @@ if [ ! -d "$OUTDIR" ]; then
> fi
> fi
>
> -# Choose ustd socket path
> -USTDSOCKPATH="/tmp/ustd-sock-$$"
> +# Choose ust-consumerd socket path
> +UST_CONSUMERDSOCKPATH="/tmp/ust-consumerd-sock-$$"
>
> if [ "$arg_syswide_daemon" != "1" ];
> then
> - pidfilepath="/tmp/usttrace-$USER-$(date +%Y%m%d%H%M%S%N)-ustd-pid"
> + pidfilepath="/tmp/usttrace-$USER-$(date +%Y%m%d%H%M%S%N)-ust-consumerd-pid"
> trap "sighandler $pidfilepath" SIGINT
> mkfifo -m 0600 "$pidfilepath"
> # Start daemon
> - $USTD --pidfile "$pidfilepath" -s "$USTDSOCKPATH" -o "$OUTDIR" >"$OUTDIR/ustd.log" 2>&1 &
> - # ustd sets up its server socket
> - # ustd opens the pidfile, blocks because no one has opened it
> + $UST_CONSUMERD --pidfile "$pidfilepath" -s "$UST_CONSUMERDSOCKPATH" -o "$OUTDIR" >"$OUTDIR/ust-consumerd.log" 2>&1 &
> + # ust-consumerd sets up its server socket
> + # ust-consumerd opens the pidfile, blocks because no one has opened it
> # we open pidfile
> # we block reading pidfile
> - # ustd writes to pidfile
> - # ustd closes pidfile
> + # ust-consumerd writes to pidfile
> + # ust-consumerd closes pidfile
> # we unblock reading pidfile
> - USTDPID="$(<$pidfilepath)"
> - export UST_DAEMON_SOCKET="$USTDSOCKPATH"
> + UST_CONSUMERDPID="$(<$pidfilepath)"
> + export UST_DAEMON_SOCKET="$UST_CONSUMERDSOCKPATH"
> fi
>
> # Establish the environment for the command
> @@ -206,10 +206,10 @@ fi
> if [ "$arg_syswide_daemon" != "1" ];
> then
> # Tell the daemon to die
> - kill -SIGTERM "$USTDPID"
> + kill -SIGTERM "$UST_CONSUMERDPID"
>
> - echo "Waiting for ustd to shutdown..."
> - wait "$USTDPID"
> + echo "Waiting for ust-consumerd to shutdown..."
> + wait "$UST_CONSUMERDPID"
>
> rm "$pidfilepath"
> fi
> --
> 1.7.1
>
>
More information about the lttng-dev
mailing list