[ltt-dev] [UST PATCH] Rename libustd to libustconsumer and ustd to ust-consumerd

Nils Carlson nils.carlson at ericsson.com
Wed Jan 5 09:10:12 EST 2011


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