* GitWeb: http://lttng.org/cgi-bin/gitweb.cgi?p=userspace-rcu.git;a=summary
* Git: git://lttng.org/userspace-rcu.git
- - libuuid (for Linux)
- * Debian/Ubuntu package: libuuid1, uuid-dev
- * Fedora package: libuuid-devel
-
For developers using the git tree:
This source tree is based on the autotools suite from GNU to simplify
AC_CHECK_LIB([pthread], [pthread_create])
-# Check for libuuid
-AC_CHECK_LIB([uuid], [uuid_generate],
-[
- AC_DEFINE_UNQUOTED([LTTNG_UST_HAVE_LIBUUID], 1, [Has libuuid support.])
- have_libuuid=yes
-],
-[
- # libuuid not found, check for uuid_create in libc.
- AC_CHECK_LIB([c], [uuid_create],
- [
- AC_DEFINE_UNQUOTED([LTTNG_UST_HAVE_LIBC_UUID], 1, [Has libc uuid support.])
- have_libc_uuid=yes
- ],
- [
- AC_MSG_ERROR([Cannot find libuuid uuid_generate nor libc uuid_create. Use [LDFLAGS]=-Ldir to specify their location.])
- ])
-]
-)
-AM_CONDITIONAL([LTTNG_UST_BUILD_WITH_LIBUUID], [test "x$have_libuuid" = "xyes"])
-AM_CONDITIONAL([LTTNG_UST_BUILD_WITH_LIBC_UUID], [test "x$have_libc_uuid" = "xyes"])
-
# Checks for header files.
#AC_CHECK_HEADERS([fcntl.h stdint.h stdlib.h string.h sys/socket.h sys/time.h unistd.h])
LTTNG_UST_MMAP = 0,
};
+enum lttng_ust_chan_type {
+ LTTNG_UST_CHAN_PER_CPU = 0,
+ LTTNG_UST_CHAN_METADATA = 1,
+};
+
struct lttng_ust_tracer_version {
uint32_t major;
uint32_t minor;
uint32_t patchlevel;
} LTTNG_PACKED;
-#define LTTNG_UST_CHANNEL_PADDING LTTNG_UST_SYM_NAME_LEN + 32
+#define LTTNG_UST_CHANNEL_PADDING (LTTNG_UST_SYM_NAME_LEN + 32)
+/*
+ * Given that the consumerd is limited to 64k file descriptors, we
+ * cannot expect much more than 1MB channel structure size. This size is
+ * depends on the number of streams within a channel, which depends on
+ * the number of possible CPUs on the system.
+ */
+#define LTTNG_UST_CHANNEL_DATA_MAX_LEN 1048576U
struct lttng_ust_channel {
- uint64_t subbuf_size; /* in bytes */
- uint64_t num_subbuf;
- int overwrite; /* 1: overwrite, 0: discard */
- unsigned int switch_timer_interval; /* usecs */
- unsigned int read_timer_interval; /* usecs */
- enum lttng_ust_output output; /* output mode */
+ uint64_t len;
+ enum lttng_ust_chan_type type;
char padding[LTTNG_UST_CHANNEL_PADDING];
+ char data[]; /* variable sized data */
} LTTNG_PACKED;
-#define LTTNG_UST_STREAM_PADDING1 16
-#define LTTNG_UST_STREAM_PADDING2 LTTNG_UST_SYM_NAME_LEN + 32
+#define LTTNG_UST_STREAM_PADDING1 (LTTNG_UST_SYM_NAME_LEN + 32)
struct lttng_ust_stream {
+ uint64_t len; /* shm len */
+ uint32_t stream_nr; /* stream number */
char padding[LTTNG_UST_STREAM_PADDING1];
-
- union {
- char padding[LTTNG_UST_STREAM_PADDING2];
- } u;
+ /*
+ * shm_fd and wakeup_fd are send over unix socket as file
+ * descriptors after this structure.
+ */
} LTTNG_PACKED;
#define LTTNG_UST_EVENT_PADDING1 16
-#define LTTNG_UST_EVENT_PADDING2 LTTNG_UST_SYM_NAME_LEN + 32
+#define LTTNG_UST_EVENT_PADDING2 (LTTNG_UST_SYM_NAME_LEN + 32)
struct lttng_ust_event {
enum lttng_ust_instrumentation instrumentation;
char name[LTTNG_UST_SYM_NAME_LEN]; /* event name */
LTTNG_UST_FIELD_STRING = 4,
};
-#define LTTNG_UST_FIELD_ITER_PADDING LTTNG_UST_SYM_NAME_LEN + 28
+#define LTTNG_UST_FIELD_ITER_PADDING (LTTNG_UST_SYM_NAME_LEN + 28)
struct lttng_ust_field_iter {
char event_name[LTTNG_UST_SYM_NAME_LEN];
char field_name[LTTNG_UST_SYM_NAME_LEN];
};
#define LTTNG_UST_CONTEXT_PADDING1 16
-#define LTTNG_UST_CONTEXT_PADDING2 LTTNG_UST_SYM_NAME_LEN + 32
+#define LTTNG_UST_CONTEXT_PADDING2 (LTTNG_UST_SYM_NAME_LEN + 32)
struct lttng_ust_context {
enum lttng_ust_context_type ctx;
char padding[LTTNG_UST_CONTEXT_PADDING1];
/*
* Tracer channel attributes.
*/
-#define LTTNG_UST_CHANNEL_ATTR_PADDING LTTNG_UST_SYM_NAME_LEN + 32
+#define LTTNG_UST_CHANNEL_ATTR_PADDING (LTTNG_UST_SYM_NAME_LEN + 32)
struct lttng_ust_channel_attr {
uint64_t subbuf_size; /* bytes */
uint64_t num_subbuf; /* power of 2 */
char padding[LTTNG_UST_TRACEPOINT_ITER_PADDING];
} LTTNG_PACKED;
-#define LTTNG_UST_OBJECT_DATA_PADDING LTTNG_UST_SYM_NAME_LEN + 32
+enum lttng_ust_object_type {
+ LTTNG_UST_OBJECT_TYPE_UNKNOWN = -1,
+ LTTNG_UST_OBJECT_TYPE_CHANNEL = 0,
+ LTTNG_UST_OBJECT_TYPE_STREAM = 1,
+};
+
+#define LTTNG_UST_OBJECT_DATA_PADDING1 32
+#define LTTNG_UST_OBJECT_DATA_PADDING2 (LTTNG_UST_SYM_NAME_LEN + 32)
+
struct lttng_ust_object_data {
- uint64_t memory_map_size;
+ enum lttng_ust_object_type type;
int handle;
- int shm_fd;
- int wait_fd;
- char padding[LTTNG_UST_OBJECT_DATA_PADDING];
+ uint64_t size;
+ char padding1[LTTNG_UST_OBJECT_DATA_PADDING1];
+ union {
+ struct {
+ void *data;
+ enum lttng_ust_chan_type type;
+ } channel;
+ struct {
+ int shm_fd;
+ int wakeup_fd;
+ uint32_t stream_nr;
+ } stream;
+ char padding2[LTTNG_UST_OBJECT_DATA_PADDING2];
+ } u;
} LTTNG_PACKED;
enum lttng_ust_calibrate_type {
};
#define LTTNG_UST_CALIBRATE_PADDING1 16
-#define LTTNG_UST_CALIBRATE_PADDING2 LTTNG_UST_SYM_NAME_LEN + 32
+#define LTTNG_UST_CALIBRATE_PADDING2 (LTTNG_UST_SYM_NAME_LEN + 32)
struct lttng_ust_calibrate {
enum lttng_ust_calibrate_type type; /* type (input) */
char padding[LTTNG_UST_CALIBRATE_PADDING1];
#define LTTNG_UST_TRACEPOINT_FIELD_LIST _UST_CMD(0x45)
/* Session FD commands */
-#define LTTNG_UST_METADATA \
- _UST_CMDW(0x50, struct lttng_ust_channel)
#define LTTNG_UST_CHANNEL \
_UST_CMDW(0x51, struct lttng_ust_channel)
#define LTTNG_UST_SESSION_START _UST_CMD(0x52)
union ust_args {
struct {
- int *shm_fd;
- int *wait_fd;
- uint64_t *memory_map_size;
+ void *chan_data;
} channel;
struct {
- int *shm_fd;
- int *wait_fd;
- uint64_t *memory_map_size;
+ int shm_fd;
+ int wakeup_fd;
} stream;
struct {
struct lttng_ust_field_iter entry;
/*
* Copyright (C) 2011 - Julien Desfossez <julien.desfossez@polymtl.ca>
- * Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright (C) 2011-2013 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include <lttng/ust-abi.h>
+#ifndef LTTNG_PACKED
+#define LTTNG_PACKED __attribute__((packed))
+#endif
+
+#ifndef LTTNG_UST_UUID_LEN
+#define LTTNG_UST_UUID_LEN 16
+#endif
+
+struct lttng_ust_shm_handle;
+struct lttng_ust_lib_ring_buffer;
+
+struct ustctl_consumer_channel_attr {
+ enum lttng_ust_chan_type type;
+ uint64_t subbuf_size; /* bytes */
+ uint64_t num_subbuf; /* power of 2 */
+ int overwrite; /* 1: overwrite, 0: discard */
+ unsigned int switch_timer_interval; /* usec */
+ unsigned int read_timer_interval; /* usec */
+ enum lttng_ust_output output; /* splice, mmap */
+ unsigned char uuid[LTTNG_UST_UUID_LEN]; /* Trace session unique ID */
+} LTTNG_PACKED;
+
+/*
+ * API used by sessiond.
+ */
+
/*
* Error values: all the following functions return:
* >= 0: Success (LTTNG_UST_OK)
*/
int ustctl_register_done(int sock);
int ustctl_create_session(int sock);
-int ustctl_open_metadata(int sock, int session_handle,
- struct lttng_ust_channel_attr *chops,
- struct lttng_ust_object_data **metadata_data);
-int ustctl_create_channel(int sock, int session_handle,
- struct lttng_ust_channel_attr *chops,
- struct lttng_ust_object_data **channel_data);
int ustctl_create_event(int sock, struct lttng_ust_event *ev,
struct lttng_ust_object_data *channel_data,
struct lttng_ust_object_data **event_data);
int ustctl_start_session(int sock, int handle);
int ustctl_stop_session(int sock, int handle);
-/*
- * Return -LTTNG_UST_ERR_NOENT if no more stream is available for creation.
- * Return 0 on success.
- * Return negative error value on system error.
- * Return positive error value on UST error.
- */
-int ustctl_create_stream(int sock, struct lttng_ust_object_data *channel_data,
- struct lttng_ust_object_data **stream_data);
-
/*
* ustctl_tracepoint_list returns a tracepoint list handle, or negative
* error value.
*/
int ustctl_tracepoint_list(int sock);
+
/*
* ustctl_tracepoint_list_get is used to iterate on the tp list
* handle. End is iteration is reached when -LTTNG_UST_ERR_NOENT is
int ustctl_calibrate(int sock, struct lttng_ust_calibrate *calibrate);
+/* Release object created by members of this API. */
+int ustctl_release_object(int sock, struct lttng_ust_object_data *data);
+/* Release handle returned by create session. */
+int ustctl_release_handle(int sock, int handle);
+
+int ustctl_recv_channel_from_consumer(int sock,
+ struct lttng_ust_object_data **channel_data);
+int ustctl_recv_stream_from_consumer(int sock,
+ struct lttng_ust_object_data **stream_data);
+int ustctl_send_channel_to_ust(int sock, int session_handle,
+ struct lttng_ust_object_data *channel_data);
+int ustctl_send_stream_to_ust(int sock,
+ struct lttng_ust_object_data *channel_data,
+ struct lttng_ust_object_data *stream_data);
+
/*
- * Map channel lttng_ust_shm_handle and add streams. Typically performed by the
- * consumer to map the objects into its memory space.
+ * API used by consumer.
*/
-struct lttng_ust_shm_handle *ustctl_map_channel(struct lttng_ust_object_data *chan_data);
-int ustctl_add_stream(struct lttng_ust_shm_handle *lttng_ust_shm_handle,
- struct lttng_ust_object_data *stream_data);
+
+struct ustctl_consumer_channel;
+struct ustctl_consumer_stream;
+struct ustctl_consumer_channel_attr;
+
+struct ustctl_consumer_channel *
+ ustctl_create_channel(struct ustctl_consumer_channel_attr *attr);
/*
- * Note: the lttng_ust_object_data from which the lttng_ust_shm_handle is derived can only
- * be released after unmapping the handle.
+ * Each stream created needs to be destroyed before calling
+ * ustctl_destroy_channel().
*/
-void ustctl_unmap_channel(struct lttng_ust_shm_handle *lttng_ust_shm_handle);
+void ustctl_destroy_channel(struct ustctl_consumer_channel *chan);
-/* Buffer operations */
+int ustctl_send_channel_to_sessiond(int sock,
+ struct ustctl_consumer_channel *channel);
+/*
+ * Send a NULL stream to finish iteration over all streams of a given
+ * channel.
+ */
+int ustctl_send_stream_to_sessiond(int sock,
+ struct ustctl_consumer_stream *stream);
+int ustctl_stream_close_wait_fd(struct ustctl_consumer_stream *stream);
+int ustctl_stream_close_wakeup_fd(struct ustctl_consumer_stream *stream);
-struct lttng_ust_shm_handle;
-struct lttng_ust_lib_ring_buffer;
+/* Create/destroy stream buffers for read */
+struct ustctl_consumer_stream *
+ ustctl_create_stream(struct ustctl_consumer_channel *channel,
+ int cpu);
+void ustctl_destroy_stream(struct ustctl_consumer_stream *stream);
-/* Open/close stream buffers for read */
-struct lttng_ust_lib_ring_buffer *ustctl_open_stream_read(struct lttng_ust_shm_handle *handle,
- int cpu);
-void ustctl_close_stream_read(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf);
+int ustctl_get_wait_fd(struct ustctl_consumer_stream *stream);
+int ustctl_get_wakeup_fd(struct ustctl_consumer_stream *stream);
/* For mmap mode, readable without "get" operation */
-int ustctl_get_mmap_len(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf,
+int ustctl_get_mmap_len(struct ustctl_consumer_stream *stream,
unsigned long *len);
-int ustctl_get_max_subbuf_size(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf,
+int ustctl_get_max_subbuf_size(struct ustctl_consumer_stream *stream,
unsigned long *len);
/*
* For mmap mode, operate on the current packet (between get/put or
* get_next/put_next).
*/
-void *ustctl_get_mmap_base(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf);
-int ustctl_get_mmap_read_offset(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf, unsigned long *off);
-int ustctl_get_subbuf_size(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf, unsigned long *len);
-int ustctl_get_padded_subbuf_size(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf, unsigned long *len);
-int ustctl_get_next_subbuf(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf);
-int ustctl_put_next_subbuf(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf);
+void *ustctl_get_mmap_base(struct ustctl_consumer_stream *stream);
+int ustctl_get_mmap_read_offset(struct ustctl_consumer_stream *stream,
+ unsigned long *off);
+int ustctl_get_subbuf_size(struct ustctl_consumer_stream *stream,
+ unsigned long *len);
+int ustctl_get_padded_subbuf_size(struct ustctl_consumer_stream *stream,
+ unsigned long *len);
+int ustctl_get_next_subbuf(struct ustctl_consumer_stream *stream);
+int ustctl_put_next_subbuf(struct ustctl_consumer_stream *stream);
/* snapshot */
-int ustctl_snapshot(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf);
-int ustctl_snapshot_get_consumed(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf, unsigned long *pos);
-int ustctl_snapshot_get_produced(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf, unsigned long *pos);
-int ustctl_get_subbuf(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf, unsigned long *pos);
-int ustctl_put_subbuf(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf);
-
-void ustctl_flush_buffer(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf,
- int producer_active);
+int ustctl_snapshot(struct ustctl_consumer_stream *stream);
+int ustctl_snapshot_get_consumed(struct ustctl_consumer_stream *stream,
+ unsigned long *pos);
+int ustctl_snapshot_get_produced(struct ustctl_consumer_stream *stream,
+ unsigned long *pos);
+int ustctl_get_subbuf(struct ustctl_consumer_stream *stream,
+ unsigned long *pos);
+int ustctl_put_subbuf(struct ustctl_consumer_stream *stream);
-/* Release object created by members of this API. */
-int ustctl_release_object(int sock, struct lttng_ust_object_data *data);
-/* Release handle returned by create session. */
-int ustctl_release_handle(int sock, int handle);
+void ustctl_flush_buffer(struct ustctl_consumer_stream *stream,
+ int producer_active);
#endif /* _LTTNG_UST_CTL_H */
LTTNG_UST_ERR_INVAL = 1027, /* Invalid argument */
LTTNG_UST_ERR_PERM = 1028, /* Permission denied */
LTTNG_UST_ERR_NOSYS = 1029, /* Not implemented */
+ LTTNG_UST_ERR_EXITING = 1030, /* Process is exiting */
/* MUST be last element */
LTTNG_UST_ERR_NR, /* Last element */
*/
struct lttng_channel_ops {
struct lttng_channel *(*channel_create)(const char *name,
- void *buf_addr,
- size_t subbuf_size, size_t num_subbuf,
- unsigned int switch_timer_interval,
- unsigned int read_timer_interval,
- int **shm_fd, int **wait_fd,
- uint64_t **memory_map_size,
- struct lttng_channel *chan_priv_init);
- void (*channel_destroy)(struct lttng_channel *lttng_chan);
- struct lttng_ust_lib_ring_buffer *(*buffer_read_open)(struct channel *chan,
- struct lttng_ust_shm_handle *handle,
- int **shm_fd, int **wait_fd,
- uint64_t **memory_map_size);
- void (*buffer_read_close)(struct lttng_ust_lib_ring_buffer *buf,
- struct lttng_ust_shm_handle *handle);
+ void *buf_addr,
+ size_t subbuf_size, size_t num_subbuf,
+ unsigned int switch_timer_interval,
+ unsigned int read_timer_interval,
+ unsigned char *uuid);
+ void (*channel_destroy)(struct lttng_channel *chan);
int (*event_reserve)(struct lttng_ust_lib_ring_buffer_ctx *ctx,
uint32_t event_id);
void (*event_commit)(struct lttng_ust_lib_ring_buffer_ctx *ctx);
- void (*event_write)(struct lttng_ust_lib_ring_buffer_ctx *ctx, const void *src,
- size_t len);
+ void (*event_write)(struct lttng_ust_lib_ring_buffer_ctx *ctx,
+ const void *src, size_t len);
/*
* packet_avail_size returns the available size in the current
* packet. Note that the size returned is only a hint, since it
unsigned int free_event_id; /* Next event ID to allocate */
unsigned int used_event_id; /* Max allocated event IDs */
struct cds_list_head node; /* Channel list in session */
- struct lttng_channel_ops *ops;
+ const struct lttng_channel_ops *ops;
int header_type; /* 0: unset, 1: compact, 2: large */
struct lttng_ust_shm_handle *handle; /* shared-memory handle */
unsigned int metadata_dumped:1;
- /* Channel ID, available for consumer too */
+ /* Channel ID */
unsigned int id;
- /* Copy of session UUID for consumer (availability through shm) */
+ enum lttng_ust_chan_type type;
unsigned char uuid[LTTNG_UST_UUID_LEN]; /* Trace session unique ID */
};
struct cds_list_head _deprecated1;
struct cds_list_head node; /* Session list */
unsigned int free_chan_id; /* Next chan ID to allocate */
- unsigned char uuid[LTTNG_UST_UUID_LEN]; /* Trace session unique ID */
unsigned int metadata_dumped:1;
/* New UST 2.1 */
char *name;
struct cds_list_head node;
struct lttng_channel_ops ops;
+ const struct lttng_ust_lib_ring_buffer_config *client_config;
};
struct lttng_session *lttng_session_create(void);
int **shm_fd, int **wait_fd,
uint64_t **memory_map_size,
struct lttng_channel *chan_priv_init);
-struct lttng_channel *lttng_global_channel_create(struct lttng_session *session,
- int overwrite, void *buf_addr,
- size_t subbuf_size, size_t num_subbuf,
- unsigned int switch_timer_interval,
- unsigned int read_timer_interval,
- int **shm_fd, int **wait_fd,
- uint64_t **memory_map_size);
int lttng_channel_enable(struct lttng_channel *channel);
int lttng_channel_disable(struct lttng_channel *channel);
extern int ustcomm_accept_unix_sock(int sock);
extern int ustcomm_listen_unix_sock(int sock);
extern int ustcomm_close_unix_sock(int sock);
-/* Send fd(s) over a unix socket. */
-extern ssize_t ustcomm_send_fds_unix_sock(int sock, void *buf, int *fds,
- size_t nb_fd, size_t len);
+
extern ssize_t ustcomm_recv_unix_sock(int sock, void *buf, size_t len);
extern ssize_t ustcomm_send_unix_sock(int sock, void *buf, size_t len);
+extern ssize_t ustcomm_send_fds_unix_sock(int sock, int *fds, size_t nb_fd);
+extern ssize_t ustcomm_recv_fds_unix_sock(int sock, int *fds, size_t nb_fd);
+
extern const char *ustcomm_get_readable_code(int code);
extern int ustcomm_send_app_msg(int sock, struct ustcomm_ust_msg *lum);
extern int ustcomm_recv_app_reply(int sock, struct ustcomm_ust_reply *lur,
struct ustcomm_ust_reply *lur);
int ustcomm_recv_fd(int sock);
+ssize_t ustcomm_recv_channel_from_sessiond(int sock,
+ void **chan_data, uint64_t len);
+int ustcomm_recv_stream_from_sessiond(int sock,
+ uint64_t *memory_map_size,
+ int *shm_fd, int *wakeup_fd);
+
#endif /* _LTTNG_UST_COMM_H */
/*
* Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
- * Copyright (C) 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright (C) 2011-2013 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
#include <fcntl.h>
#include <ust-comm.h>
+#include <helper.h>
#include <lttng/ust-error.h>
#define USTCOMM_CODE_OFFSET(code) \
(code == LTTNG_UST_OK ? 0 : (code - LTTNG_UST_ERR + 1))
+#define USTCOMM_MAX_SEND_FDS 4
+
/*
* Human readable error message.
*/
[ USTCOMM_CODE_OFFSET(LTTNG_UST_ERR_INVAL) ] = "Invalid argument",
[ USTCOMM_CODE_OFFSET(LTTNG_UST_ERR_PERM) ] = "Permission denied",
[ USTCOMM_CODE_OFFSET(LTTNG_UST_ERR_NOSYS) ] = "Not implemented",
+ [ USTCOMM_CODE_OFFSET(LTTNG_UST_ERR_EXITING) ] = "Process is exiting",
};
/*
}
/*
- * ustcomm_connect_unix_sock
+ * ustcomm_connect_unix_sock
*
- * Connect to unix socket using the path name.
+ * Connect to unix socket using the path name.
*/
int ustcomm_connect_unix_sock(const char *pathname)
{
}
/*
- * ustcomm_accept_unix_sock
+ * ustcomm_accept_unix_sock
*
- * Do an accept(2) on the sock and return the
- * new file descriptor. The socket MUST be bind(2) before.
+ * Do an accept(2) on the sock and return the
+ * new file descriptor. The socket MUST be bind(2) before.
*/
int ustcomm_accept_unix_sock(int sock)
{
}
/*
- * ustcomm_create_unix_sock
+ * ustcomm_create_unix_sock
*
- * Creates a AF_UNIX local socket using pathname
- * bind the socket upon creation and return the fd.
+ * Creates a AF_UNIX local socket using pathname
+ * bind the socket upon creation and return the fd.
*/
int ustcomm_create_unix_sock(const char *pathname)
{
}
/*
- * ustcomm_listen_unix_sock
+ * ustcomm_listen_unix_sock
*
- * Make the socket listen using LTTNG_UST_COMM_MAX_LISTEN.
+ * Make the socket listen using LTTNG_UST_COMM_MAX_LISTEN.
*/
int ustcomm_listen_unix_sock(int sock)
{
}
/*
- * ustcomm_recv_unix_sock
+ * ustcomm_close_unix_sock
+ *
+ * Shutdown cleanly a unix socket.
+ */
+int ustcomm_close_unix_sock(int sock)
+{
+ int ret;
+
+ ret = close(sock);
+ if (ret < 0) {
+ perror("close");
+ ret = -errno;
+ }
+
+ return ret;
+}
+
+/*
+ * ustcomm_recv_unix_sock
*
- * Receive data of size len in put that data into
- * the buf param. Using recvmsg API.
- * Return the size of received data.
+ * Receive data of size len in put that data into
+ * the buf param. Using recvmsg API.
+ * Return the size of received data.
+ * Return 0 on orderly shutdown.
*/
ssize_t ustcomm_recv_unix_sock(int sock, void *buf, size_t len)
{
if (ret < 0) {
int shutret;
- if (errno != EPIPE)
+ if (errno != EPIPE && errno != ECONNRESET)
perror("recvmsg");
ret = -errno;
}
/*
- * ustcomm_send_unix_sock
+ * ustcomm_send_unix_sock
*
- * Send buf data of size len. Using sendmsg API.
- * Return the size of sent data.
+ * Send buf data of size len. Using sendmsg API.
+ * Return the size of sent data.
*/
ssize_t ustcomm_send_unix_sock(int sock, void *buf, size_t len)
{
if (ret < 0) {
int shutret;
- if (errno != EPIPE)
- perror("recvmsg");
+ if (errno != EPIPE && errno != ECONNRESET)
+ perror("sendmsg");
ret = -errno;
shutret = shutdown(sock, SHUT_RDWR);
}
/*
- * ustcomm_close_unix_sock
+ * Send a message accompanied by fd(s) over a unix socket.
*
- * Shutdown cleanly a unix socket.
+ * Returns the size of data sent, or negative error value.
*/
-int ustcomm_close_unix_sock(int sock)
-{
- int ret;
-
- ret = close(sock);
- if (ret < 0) {
- perror("close");
- ret = -errno;
- }
-
- return ret;
-}
-
-/*
- * ustcomm_send_fds_unix_sock
- *
- * Send multiple fds on a unix socket.
- */
-ssize_t ustcomm_send_fds_unix_sock(int sock, void *buf, int *fds, size_t nb_fd, size_t len)
+ssize_t ustcomm_send_fds_unix_sock(int sock, int *fds, size_t nb_fd)
{
struct msghdr msg;
struct cmsghdr *cmptr;
ssize_t ret = -1;
unsigned int sizeof_fds = nb_fd * sizeof(int);
char tmp[CMSG_SPACE(sizeof_fds)];
+ char dummy = 0;
memset(&msg, 0, sizeof(msg));
+ memset(tmp, 0, CMSG_SPACE(sizeof_fds) * sizeof(char));
- /*
- * Note: we currently only support sending a single FD per
- * message.
- */
- assert(nb_fd == 1);
+ if (nb_fd > USTCOMM_MAX_SEND_FDS)
+ return -EINVAL;
msg.msg_control = (caddr_t)tmp;
msg.msg_controllen = CMSG_LEN(sizeof_fds);
/* Sum of the length of all control messages in the buffer: */
msg.msg_controllen = cmptr->cmsg_len;
- iov[0].iov_base = buf;
- iov[0].iov_len = len;
+ iov[0].iov_base = &dummy;
+ iov[0].iov_len = 1;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
do {
- ret = sendmsg(sock, &msg, MSG_NOSIGNAL);
+ ret = sendmsg(sock, &msg, 0);
} while (ret < 0 && errno == EINTR);
-
if (ret < 0) {
- int shutret;
+ /*
+ * We consider EPIPE and ECONNRESET as expected.
+ */
+ if (errno != EPIPE && errno != ECONNRESET) {
+ perror("sendmsg");
+ }
+ }
+ return ret;
+}
- if (errno != EPIPE)
- perror("recvmsg");
- ret = -errno;
+/*
+ * Recv a message accompanied by fd(s) from a unix socket.
+ *
+ * Returns the size of received data, or negative error value.
+ *
+ * Expect at most "nb_fd" file descriptors. Returns the number of fd
+ * actually received in nb_fd.
+ * Returns -EPIPE on orderly shutdown.
+ */
+ssize_t ustcomm_recv_fds_unix_sock(int sock, int *fds, size_t nb_fd)
+{
+ struct iovec iov[1];
+ ssize_t ret = 0;
+ struct cmsghdr *cmsg;
+ size_t sizeof_fds = nb_fd * sizeof(int);
+ char recv_fd[CMSG_SPACE(sizeof_fds)];
+ struct msghdr msg;
+ char dummy;
- shutret = shutdown(sock, SHUT_RDWR);
- if (shutret)
- fprintf(stderr, "Socket shutdown error");
- }
+ memset(&msg, 0, sizeof(msg));
+ /* Prepare to receive the structures */
+ iov[0].iov_base = &dummy;
+ iov[0].iov_len = 1;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = recv_fd;
+ msg.msg_controllen = sizeof(recv_fd);
+
+ do {
+ ret = recvmsg(sock, &msg, 0);
+ } while (ret < 0 && errno == EINTR);
+ if (ret < 0) {
+ if (errno != EPIPE && errno != ECONNRESET) {
+ perror("recvmsg fds");
+ }
+ if (errno == EPIPE || errno == ECONNRESET)
+ ret = -errno;
+ goto end;
+ }
+ if (ret == 0) {
+ /* orderly shutdown */
+ ret = -EPIPE;
+ goto end;
+ }
+ if (ret != 1) {
+ fprintf(stderr, "Error: Received %zd bytes, expected %d\n",
+ ret, 1);
+ goto end;
+ }
+ if (msg.msg_flags & MSG_CTRUNC) {
+ fprintf(stderr, "Error: Control message truncated.\n");
+ ret = -1;
+ goto end;
+ }
+ cmsg = CMSG_FIRSTHDR(&msg);
+ if (!cmsg) {
+ fprintf(stderr, "Error: Invalid control message header\n");
+ ret = -1;
+ goto end;
+ }
+ if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
+ fprintf(stderr, "Didn't received any fd\n");
+ ret = -1;
+ goto end;
+ }
+ if (cmsg->cmsg_len != CMSG_LEN(sizeof_fds)) {
+ fprintf(stderr, "Error: Received %zu bytes of ancillary data, expected %zu\n",
+ (size_t) cmsg->cmsg_len, (size_t) CMSG_LEN(sizeof_fds));
+ ret = -1;
+ goto end;
+ }
+ memcpy(fds, CMSG_DATA(cmsg), sizeof_fds);
+ ret = sizeof_fds;
+end:
return ret;
}
break;
default:
if (len < 0) {
- if (len == -ECONNRESET)
- fprintf(stderr, "remote end closed connection\n");
return len;
} else {
fprintf(stderr, "incorrect message size: %zd\n", len);
len = ustcomm_recv_unix_sock(sock, lur, sizeof(*lur));
switch (len) {
case 0: /* orderly shutdown */
- return -EINVAL;
+ return -EPIPE;
case sizeof(*lur):
if (lur->handle != expected_handle) {
- fprintf(stderr, "Unexpected result message handle\n");
+ fprintf(stderr, "Unexpected result message handle: "
+ "expected: %u vs received: %u\n",
+ expected_handle, lur->handle);
return -EINVAL;
}
if (lur->cmd != expected_cmd) {
- fprintf(stderr, "Unexpected result message command\n");
+ fprintf(stderr, "Unexpected result message command "
+ "expected: %u vs received: %u\n",
+ expected_cmd, lur->cmd);
return -EINVAL;
}
return lur->ret_code;
default:
if (len < 0) {
/* Transport level error */
- if (len == -ECONNRESET)
- fprintf(stderr, "remote end closed connection\n");
+ if (errno == EPIPE || errno == ECONNRESET)
+ len = -errno;
return len;
} else {
fprintf(stderr, "incorrect message size: %zd\n", len);
}
/*
- * Receives a single fd from socket.
- *
- * Returns negative error value on error, or file descriptor number on
- * success.
+ * chan_data is allocated internally if this function returns the
+ * expected var_len.
*/
-int ustcomm_recv_fd(int sock)
+ssize_t ustcomm_recv_channel_from_sessiond(int sock,
+ void **_chan_data, uint64_t var_len)
{
- struct iovec iov[1];
- int ret = 0;
- int data_fd;
- struct cmsghdr *cmsg;
- char recv_fd[CMSG_SPACE(sizeof(int))];
- struct msghdr msg;
- union {
- unsigned char vc[4];
- int vi;
- } tmp;
- int i;
-
- memset(&msg, 0, sizeof(msg));
-
- /* Prepare to receive the structures */
- iov[0].iov_base = &data_fd;
- iov[0].iov_len = sizeof(data_fd);
- msg.msg_iov = iov;
- msg.msg_iovlen = 1;
- msg.msg_control = recv_fd;
- msg.msg_controllen = sizeof(recv_fd);
+ void *chan_data;
+ ssize_t len;
- do {
- ret = recvmsg(sock, &msg, 0);
- } while (ret < 0 && errno == EINTR);
- if (ret < 0) {
- if (errno != EPIPE) {
- perror("recvmsg");
- }
- ret = -errno;
- goto end;
- }
- if (ret != sizeof(data_fd)) {
- fprintf(stderr, "Received %d bytes, expected %zd", ret, sizeof(data_fd));
- ret = -EINVAL;
- goto end;
+ if (var_len > LTTNG_UST_CHANNEL_DATA_MAX_LEN) {
+ len = -EINVAL;
+ goto error_check;
}
- cmsg = CMSG_FIRSTHDR(&msg);
- if (!cmsg) {
- fprintf(stderr, "Invalid control message header\n");
- ret = -EINVAL;
- goto end;
+ /* Receive variable length data */
+ chan_data = zmalloc(var_len);
+ if (!chan_data) {
+ len = -ENOMEM;
+ goto error_alloc;
}
- if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
- fprintf(stderr, "Didn't received any fd\n");
- ret = -EINVAL;
- goto end;
+ len = ustcomm_recv_unix_sock(sock, chan_data, var_len);
+ if (len != var_len) {
+ goto error_recv;
}
- /* this is our fd */
- for (i = 0; i < sizeof(int); i++)
- tmp.vc[i] = CMSG_DATA(cmsg)[i];
- ret = tmp.vi;
- /*
- * Useful for fd leak debug.
- * fprintf(stderr, "received fd %d\n", ret);
- */
-end:
- if (ret < 0) {
- int shutret;
+ *_chan_data = chan_data;
+ return len;
+
+error_recv:
+ free(chan_data);
+error_alloc:
+error_check:
+ return len;
+}
- shutret = shutdown(sock, SHUT_RDWR);
- if (shutret)
- fprintf(stderr, "Socket shutdown error");
+int ustcomm_recv_stream_from_sessiond(int sock,
+ uint64_t *memory_map_size,
+ int *shm_fd, int *wakeup_fd)
+{
+ ssize_t len;
+ int ret;
+ int fds[2];
+
+ /* recv shm fd and wakeup fd */
+ len = ustcomm_recv_fds_unix_sock(sock, fds, 2);
+ if (len <= 0) {
+ if (len < 0) {
+ ret = len;
+ goto error;
+ } else {
+ ret = -EIO;
+ goto error;
+ }
}
+ *shm_fd = fds[0];
+ *wakeup_fd = fds[1];
+ return 0;
+
+error:
return ret;
}
lib_LTLIBRARIES = liblttng-ust-ctl.la
-liblttng_ust_ctl_la_SOURCES = ustctl.c
+liblttng_ust_ctl_la_SOURCES = ustctl.c ust-ctl-private.h
liblttng_ust_ctl_la_LDFLAGS = \
-version-info $(LTTNG_UST_CTL_LIBRARY_VERSION)
--- /dev/null
+/*
+ * Copyright (C) 2011 - Julien Desfossez <julien.desfossez@polymtl.ca>
+ * Copyright (C) 2011-2013 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License only.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _LTTNG_UST_CTL_PRIVATE_H
+#define _LTTNG_UST_CTL_PRIVATE_H
+
+#include <lttng/ust-ctl.h>
+
+/*
+ * Map channel lttng_ust_shm_handle and add streams. Typically performed
+ * by the application to map the objects into its memory space.
+ */
+struct lttng_ust_shm_handle *
+ ustctl_map_channel(struct lttng_ust_object_data *chan_data);
+int ustctl_add_stream(struct lttng_ust_shm_handle *lttng_ust_shm_handle,
+ struct lttng_ust_object_data *stream_data);
+/*
+ * Note: the lttng_ust_object_data from which the lttng_ust_shm_handle
+ * is derived can only be released after unmapping the handle.
+ */
+void ustctl_unmap_channel(struct lttng_ust_shm_handle *lttng_ust_shm_handle);
+
+#endif /* _LTTNG_UST_CTL_PRIVATE_H */
/*
* Copyright (C) 2011 - Julien Desfossez <julien.desfossez@polymtl.ca>
- * Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright (C) 2011-2013 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include <usterr-signal-safe.h>
#include <ust-comm.h>
+#include <helper.h>
#include "../libringbuffer/backend.h"
#include "../libringbuffer/frontend.h"
-volatile enum ust_loglevel ust_loglevel;
+/*
+ * Channel representation within consumer.
+ */
+struct ustctl_consumer_channel {
+ struct lttng_channel *chan; /* lttng channel buffers */
-static
-void init_object(struct lttng_ust_object_data *data)
-{
- data->handle = -1;
- data->shm_fd = -1;
- data->wait_fd = -1;
- data->memory_map_size = 0;
-}
+ /* initial attributes */
+ struct ustctl_consumer_channel_attr attr;
+};
+
+/*
+ * Stream representation within consumer.
+ */
+struct ustctl_consumer_stream {
+ struct lttng_ust_shm_handle *handle; /* shared-memory handle */
+ struct lttng_ust_lib_ring_buffer *buf;
+ struct ustctl_consumer_channel *chan;
+ int shm_fd, wait_fd, wakeup_fd;
+ int cpu;
+ uint64_t memory_map_size;
+};
+
+extern void lttng_ring_buffer_client_overwrite_init(void);
+extern void lttng_ring_buffer_client_discard_init(void);
+extern void lttng_ring_buffer_metadata_client_init(void);
+extern void lttng_ring_buffer_client_overwrite_exit(void);
+extern void lttng_ring_buffer_client_discard_exit(void);
+extern void lttng_ring_buffer_metadata_client_exit(void);
+
+volatile enum ust_loglevel ust_loglevel;
int ustctl_release_handle(int sock, int handle)
{
struct ustcomm_ust_msg lum;
struct ustcomm_ust_reply lur;
- int ret;
- if (sock >= 0) {
- memset(&lum, 0, sizeof(lum));
- lum.handle = handle;
- lum.cmd = LTTNG_UST_RELEASE;
- ret = ustcomm_send_app_cmd(sock, &lum, &lur);
- if (ret)
- return ret;
- }
- return 0;
+ if (sock < 0 || handle < 0)
+ return 0;
+ memset(&lum, 0, sizeof(lum));
+ lum.handle = handle;
+ lum.cmd = LTTNG_UST_RELEASE;
+ return ustcomm_send_app_cmd(sock, &lum, &lur);
}
+
/*
* If sock is negative, it means we don't have to notify the other side
* (e.g. application has already vanished).
if (!data)
return -EINVAL;
- if (data->shm_fd >= 0) {
- ret = close(data->shm_fd);
- if (ret < 0) {
- ret = -errno;
- return ret;
+ switch (data->type) {
+ case LTTNG_UST_OBJECT_TYPE_CHANNEL:
+ free(data->u.channel.data);
+ break;
+ case LTTNG_UST_OBJECT_TYPE_STREAM:
+ if (data->u.stream.shm_fd >= 0) {
+ ret = close(data->u.stream.shm_fd);
+ if (ret < 0) {
+ ret = -errno;
+ return ret;
+ }
}
- }
- if (data->wait_fd >= 0) {
- ret = close(data->wait_fd);
- if (ret < 0) {
- ret = -errno;
- return ret;
+ if (data->u.stream.wakeup_fd >= 0) {
+ ret = close(data->u.stream.wakeup_fd);
+ if (ret < 0) {
+ ret = -errno;
+ return ret;
+ }
}
+ break;
+ default:
+ assert(0);
}
return ustctl_release_handle(sock, data->handle);
}
return session_handle;
}
-/* open the metadata global channel */
-int ustctl_open_metadata(int sock, int session_handle,
- struct lttng_ust_channel_attr *chops,
- struct lttng_ust_object_data **_metadata_data)
-{
- struct ustcomm_ust_msg lum;
- struct ustcomm_ust_reply lur;
- struct lttng_ust_object_data *metadata_data;
- int ret, err = 0;
-
- if (!chops || !_metadata_data)
- return -EINVAL;
-
- metadata_data = malloc(sizeof(*metadata_data));
- if (!metadata_data)
- return -ENOMEM;
- init_object(metadata_data);
- /* Create metadata channel */
- memset(&lum, 0, sizeof(lum));
- lum.handle = session_handle;
- lum.cmd = LTTNG_UST_METADATA;
- lum.u.channel.overwrite = chops->overwrite;
- lum.u.channel.subbuf_size = chops->subbuf_size;
- lum.u.channel.num_subbuf = chops->num_subbuf;
- lum.u.channel.switch_timer_interval = chops->switch_timer_interval;
- lum.u.channel.read_timer_interval = chops->read_timer_interval;
- lum.u.channel.output = chops->output;
- ret = ustcomm_send_app_cmd(sock, &lum, &lur);
- if (ret) {
- free(metadata_data);
- return ret;
- }
- metadata_data->handle = lur.ret_val;
- DBG("received metadata handle %u", metadata_data->handle);
- metadata_data->memory_map_size = lur.u.channel.memory_map_size;
- /* get shm fd */
- ret = ustcomm_recv_fd(sock);
- if (ret < 0)
- err = ret;
- else
- metadata_data->shm_fd = ret;
- /*
- * We need to get the second FD even if the first fails, because
- * libust expects us to read the two FDs.
- */
- /* get wait fd */
- ret = ustcomm_recv_fd(sock);
- if (ret < 0)
- err = ret;
- else
- metadata_data->wait_fd = ret;
- if (err)
- goto error;
- *_metadata_data = metadata_data;
- return 0;
-
-error:
- (void) ustctl_release_object(sock, metadata_data);
- free(metadata_data);
- return err;
-}
-
-int ustctl_create_channel(int sock, int session_handle,
- struct lttng_ust_channel_attr *chops,
- struct lttng_ust_object_data **_channel_data)
-{
- struct ustcomm_ust_msg lum;
- struct ustcomm_ust_reply lur;
- struct lttng_ust_object_data *channel_data;
- int ret, err = 0;
-
- if (!chops || !_channel_data)
- return -EINVAL;
-
- channel_data = malloc(sizeof(*channel_data));
- if (!channel_data)
- return -ENOMEM;
- init_object(channel_data);
- /* Create metadata channel */
- memset(&lum, 0, sizeof(lum));
- lum.handle = session_handle;
- lum.cmd = LTTNG_UST_CHANNEL;
- lum.u.channel.overwrite = chops->overwrite;
- lum.u.channel.subbuf_size = chops->subbuf_size;
- lum.u.channel.num_subbuf = chops->num_subbuf;
- lum.u.channel.switch_timer_interval = chops->switch_timer_interval;
- lum.u.channel.read_timer_interval = chops->read_timer_interval;
- lum.u.channel.output = chops->output;
- ret = ustcomm_send_app_cmd(sock, &lum, &lur);
- if (ret) {
- free(channel_data);
- return ret;
- }
- channel_data->handle = lur.ret_val;
- DBG("received channel handle %u", channel_data->handle);
- channel_data->memory_map_size = lur.u.channel.memory_map_size;
- /* get shm fd */
- ret = ustcomm_recv_fd(sock);
- if (ret < 0)
- err = ret;
- else
- channel_data->shm_fd = ret;
- /*
- * We need to get the second FD even if the first fails, because
- * libust expects us to read the two FDs.
- */
- /* get wait fd */
- ret = ustcomm_recv_fd(sock);
- if (ret < 0)
- err = ret;
- else
- channel_data->wait_fd = ret;
- if (err)
- goto error;
- *_channel_data = channel_data;
- return 0;
-
-error:
- (void) ustctl_release_object(sock, channel_data);
- free(channel_data);
- return err;
-}
-
-/*
- * Return -LTTNG_UST_ERR_NOENT if no more stream is available for creation.
- * Return 0 on success.
- * Return negative error value on system error.
- * Return positive error value on UST error.
- */
-int ustctl_create_stream(int sock, struct lttng_ust_object_data *channel_data,
- struct lttng_ust_object_data **_stream_data)
-{
- struct ustcomm_ust_msg lum;
- struct ustcomm_ust_reply lur;
- struct lttng_ust_object_data *stream_data;
- int ret, fd, err = 0;
-
- if (!channel_data || !_stream_data)
- return -EINVAL;
-
- stream_data = malloc(sizeof(*stream_data));
- if (!stream_data)
- return -ENOMEM;
- init_object(stream_data);
- memset(&lum, 0, sizeof(lum));
- lum.handle = channel_data->handle;
- lum.cmd = LTTNG_UST_STREAM;
- ret = ustcomm_send_app_cmd(sock, &lum, &lur);
- if (ret) {
- free(stream_data);
- return ret;
- }
- stream_data->handle = lur.ret_val;
- DBG("received stream handle %u", stream_data->handle);
- stream_data->memory_map_size = lur.u.stream.memory_map_size;
- /* get shm fd */
- fd = ustcomm_recv_fd(sock);
- if (fd < 0)
- err = fd;
- else
- stream_data->shm_fd = fd;
- /*
- * We need to get the second FD even if the first fails, because
- * libust expects us to read the two FDs.
- */
- /* get wait fd */
- fd = ustcomm_recv_fd(sock);
- if (fd < 0)
- err = fd;
- else
- stream_data->wait_fd = fd;
- if (err)
- goto error;
- *_stream_data = stream_data;
- return ret;
-
-error:
- (void) ustctl_release_object(sock, stream_data);
- free(stream_data);
- return err;
-}
-
int ustctl_create_event(int sock, struct lttng_ust_event *ev,
struct lttng_ust_object_data *channel_data,
struct lttng_ust_object_data **_event_data)
if (!channel_data || !_event_data)
return -EINVAL;
- event_data = malloc(sizeof(*event_data));
+ event_data = zmalloc(sizeof(*event_data));
if (!event_data)
return -ENOMEM;
- init_object(event_data);
memset(&lum, 0, sizeof(lum));
lum.handle = channel_data->handle;
lum.cmd = LTTNG_UST_EVENT;
if (!obj_data || !_context_data)
return -EINVAL;
- context_data = malloc(sizeof(*context_data));
+ context_data = zmalloc(sizeof(*context_data));
if (!context_data)
return -ENOMEM;
- init_object(context_data);
memset(&lum, 0, sizeof(lum));
lum.handle = obj_data->handle;
lum.cmd = LTTNG_UST_CONTEXT;
return 0;
}
-/* Buffer operations */
+static
+int ustctl_send_channel(int sock,
+ enum lttng_ust_chan_type type,
+ void *data,
+ uint64_t size,
+ int send_fd_only)
+{
+ ssize_t len;
+
+ if (!send_fd_only) {
+ /* Send mmap size */
+ len = ustcomm_send_unix_sock(sock, &size, sizeof(size));
+ if (len != sizeof(size)) {
+ if (len < 0)
+ return len;
+ else
+ return -EIO;
+ }
+
+ /* Send channel type */
+ len = ustcomm_send_unix_sock(sock, &type, sizeof(type));
+ if (len != sizeof(type)) {
+ if (len < 0)
+ return len;
+ else
+ return -EIO;
+ }
+ }
+
+ /* Send channel data */
+ len = ustcomm_send_unix_sock(sock, data, size);
+ if (len != size) {
+ if (len < 0)
+ return len;
+ else
+ return -EIO;
+ }
-/* Map channel shm into process memory */
-struct lttng_ust_shm_handle *ustctl_map_channel(struct lttng_ust_object_data *chan_data)
+ return 0;
+}
+
+static
+int ustctl_send_stream(int sock,
+ uint32_t stream_nr,
+ uint64_t memory_map_size,
+ int shm_fd, int wakeup_fd,
+ int send_fd_only)
{
- struct lttng_ust_shm_handle *handle;
- struct channel *chan;
- size_t chan_size;
- struct lttng_ust_lib_ring_buffer_config *config;
+ ssize_t len;
+ int fds[2];
+
+ if (!send_fd_only) {
+ if (shm_fd < 0) {
+ /* finish iteration */
+ uint64_t v = -1;
+
+ len = ustcomm_send_unix_sock(sock, &v, sizeof(v));
+ if (len != sizeof(v)) {
+ if (len < 0)
+ return len;
+ else
+ return -EIO;
+ }
+ return 0;
+ }
+
+ /* Send mmap size */
+ len = ustcomm_send_unix_sock(sock, &memory_map_size,
+ sizeof(memory_map_size));
+ if (len != sizeof(memory_map_size)) {
+ if (len < 0)
+ return len;
+ else
+ return -EIO;
+ }
+
+ /* Send stream nr */
+ len = ustcomm_send_unix_sock(sock, &stream_nr,
+ sizeof(stream_nr));
+ if (len != sizeof(stream_nr)) {
+ if (len < 0)
+ return len;
+ else
+ return -EIO;
+ }
+ }
+
+ /* Send shm fd and wakeup fd */
+ fds[0] = shm_fd;
+ fds[1] = wakeup_fd;
+ len = ustcomm_send_fds_unix_sock(sock, fds, 2);
+ if (len <= 0) {
+ if (len < 0)
+ return len;
+ else
+ return -EIO;
+ }
+ return 0;
+}
+
+int ustctl_recv_channel_from_consumer(int sock,
+ struct lttng_ust_object_data **_channel_data)
+{
+ struct lttng_ust_object_data *channel_data;
+ ssize_t len;
int ret;
- if (!chan_data)
- return NULL;
+ channel_data = zmalloc(sizeof(*channel_data));
+ if (!channel_data) {
+ ret = -ENOMEM;
+ goto error_alloc;
+ }
+ channel_data->type = LTTNG_UST_OBJECT_TYPE_CHANNEL;
+
+ /* recv mmap size */
+ len = ustcomm_recv_unix_sock(sock, &channel_data->size,
+ sizeof(channel_data->size));
+ if (len != sizeof(channel_data->size)) {
+ if (len < 0)
+ ret = len;
+ else
+ ret = -EINVAL;
+ goto error;
+ }
- handle = channel_handle_create(chan_data->shm_fd,
- chan_data->wait_fd,
- chan_data->memory_map_size);
- if (!handle) {
- ERR("create handle error");
- return NULL;
+ /* recv channel type */
+ len = ustcomm_recv_unix_sock(sock, &channel_data->u.channel.type,
+ sizeof(channel_data->u.channel.type));
+ if (len != sizeof(channel_data->u.channel.type)) {
+ if (len < 0)
+ ret = len;
+ else
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* recv channel data */
+ channel_data->u.channel.data = zmalloc(channel_data->size);
+ if (!channel_data->u.channel.data) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ len = ustcomm_recv_unix_sock(sock, channel_data->u.channel.data,
+ channel_data->size);
+ if (len != channel_data->size) {
+ if (len < 0)
+ ret = len;
+ else
+ ret = -EINVAL;
+ goto error_recv_data;
+ }
+
+ *_channel_data = channel_data;
+ return 0;
+
+error_recv_data:
+ free(channel_data->u.channel.data);
+error:
+ free(channel_data);
+error_alloc:
+ return ret;
+}
+
+int ustctl_recv_stream_from_consumer(int sock,
+ struct lttng_ust_object_data **_stream_data)
+{
+ struct lttng_ust_object_data *stream_data;
+ ssize_t len;
+ int ret;
+ int fds[2];
+
+ stream_data = zmalloc(sizeof(*stream_data));
+ if (!stream_data) {
+ ret = -ENOMEM;
+ goto error_alloc;
}
- /*
- * Set to -1, and then close the shm fd, and set the handle shm
- * fd to -1 too. We don't need the shm fds after they have been
- * mapped.
- * The wait_fd is set to -1 in chan_data because it is now owned
- * by the handle.
- */
- chan_data->shm_fd = -1;
- chan_data->wait_fd = -1;
-
- /* chan is object 0. This is hardcoded. */
- if (handle->table->objects[0].shm_fd >= 0) {
- ret = close(handle->table->objects[0].shm_fd);
- if (ret) {
- perror("Error closing shm_fd");
+
+ stream_data->type = LTTNG_UST_OBJECT_TYPE_STREAM;
+ stream_data->handle = -1;
+
+ /* recv mmap size */
+ len = ustcomm_recv_unix_sock(sock, &stream_data->size,
+ sizeof(stream_data->size));
+ if (len != sizeof(stream_data->size)) {
+ if (len < 0)
+ ret = len;
+ else
+ ret = -EINVAL;
+ goto error;
+ }
+ if (stream_data->size == -1) {
+ ret = -LTTNG_UST_ERR_NOENT;
+ goto error;
+ }
+
+ /* recv stream nr */
+ len = ustcomm_recv_unix_sock(sock, &stream_data->u.stream.stream_nr,
+ sizeof(stream_data->u.stream.stream_nr));
+ if (len != sizeof(stream_data->u.stream.stream_nr)) {
+ if (len < 0)
+ ret = len;
+ else
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* recv shm fd and wakeup fd */
+ len = ustcomm_recv_fds_unix_sock(sock, fds, 2);
+ if (len <= 0) {
+ if (len < 0) {
+ ret = len;
+ goto error;
+ } else {
+ ret = -EIO;
+ goto error;
}
- handle->table->objects[0].shm_fd = -1;
}
+ stream_data->u.stream.shm_fd = fds[0];
+ stream_data->u.stream.wakeup_fd = fds[1];
+ *_stream_data = stream_data;
+ return 0;
- /*
- * TODO: add consistency checks to be resilient if the
- * application try to feed us with incoherent channel structure
- * values.
- */
- chan = shmp(handle, handle->chan);
- /* chan is object 0. This is hardcoded. */
- chan_size = handle->table->objects[0].allocated_len;
- handle->shadow_chan = malloc(chan_size);
- if (!handle->shadow_chan) {
- channel_destroy(chan, handle, 1);
- return NULL;
+error:
+ free(stream_data);
+error_alloc:
+ return ret;
+}
+
+int ustctl_send_channel_to_ust(int sock, int session_handle,
+ struct lttng_ust_object_data *channel_data)
+{
+ struct ustcomm_ust_msg lum;
+ struct ustcomm_ust_reply lur;
+ int ret;
+
+ if (!channel_data)
+ return -EINVAL;
+
+ memset(&lum, 0, sizeof(lum));
+ lum.handle = session_handle;
+ lum.cmd = LTTNG_UST_CHANNEL;
+ lum.u.channel.len = channel_data->size;
+ lum.u.channel.type = channel_data->u.channel.type;
+ ret = ustcomm_send_app_msg(sock, &lum);
+ if (ret)
+ return ret;
+
+ ret = ustctl_send_channel(sock,
+ channel_data->u.channel.type,
+ channel_data->u.channel.data,
+ channel_data->size,
+ 1);
+ if (ret)
+ return ret;
+ ret = ustcomm_recv_app_reply(sock, &lur, lum.handle, lum.cmd);
+ if (!ret) {
+ if (lur.ret_val >= 0) {
+ channel_data->handle = lur.ret_val;
+ }
}
- memcpy(handle->shadow_chan, chan, chan_size);
- /*
- * The callback pointers in the producer are invalid in the
- * consumer. We need to look them up here.
- */
- config = &handle->shadow_chan->backend.config;
- switch (config->client_type) {
- case LTTNG_CLIENT_METADATA:
- memcpy(&config->cb, lttng_client_callbacks_metadata,
- sizeof(config->cb));
- break;
- case LTTNG_CLIENT_DISCARD:
- memcpy(&config->cb, lttng_client_callbacks_discard,
- sizeof(config->cb));
+ return ret;
+}
+
+int ustctl_send_stream_to_ust(int sock,
+ struct lttng_ust_object_data *channel_data,
+ struct lttng_ust_object_data *stream_data)
+{
+ struct ustcomm_ust_msg lum;
+ struct ustcomm_ust_reply lur;
+ int ret;
+
+ memset(&lum, 0, sizeof(lum));
+ lum.handle = channel_data->handle;
+ lum.cmd = LTTNG_UST_STREAM;
+ lum.u.stream.len = stream_data->size;
+ lum.u.stream.stream_nr = stream_data->u.stream.stream_nr;
+ ret = ustcomm_send_app_msg(sock, &lum);
+ if (ret)
+ return ret;
+
+ assert(stream_data);
+ assert(stream_data->type == LTTNG_UST_OBJECT_TYPE_STREAM);
+
+ ret = ustctl_send_stream(sock,
+ stream_data->u.stream.stream_nr,
+ stream_data->size,
+ stream_data->u.stream.shm_fd,
+ stream_data->u.stream.wakeup_fd, 1);
+ if (ret)
+ return ret;
+ return ustcomm_recv_app_reply(sock, &lur, lum.handle, lum.cmd);
+}
+
+
+/* Buffer operations */
+
+struct ustctl_consumer_channel *
+ ustctl_create_channel(struct ustctl_consumer_channel_attr *attr)
+{
+ struct ustctl_consumer_channel *chan;
+ const char *transport_name;
+ struct lttng_transport *transport;
+
+ switch (attr->type) {
+ case LTTNG_UST_CHAN_PER_CPU:
+ if (attr->output == LTTNG_UST_MMAP) {
+ transport_name = attr->overwrite ?
+ "relay-overwrite-mmap" : "relay-discard-mmap";
+ } else {
+ return NULL;
+ }
break;
- case LTTNG_CLIENT_OVERWRITE:
- memcpy(&config->cb, lttng_client_callbacks_overwrite,
- sizeof(config->cb));
+ case LTTNG_UST_CHAN_METADATA:
+ if (attr->output == LTTNG_UST_MMAP)
+ transport_name = "relay-metadata-mmap";
+ else
+ return NULL;
break;
default:
- ERR("Unknown client type %d", config->client_type);
- channel_destroy(chan, handle, 1);
- free(handle->shadow_chan);
+ transport_name = "<unknown>";
return NULL;
}
- /* Replace the object table pointer. */
- ret = munmap(handle->table->objects[0].memory_map,
- handle->table->objects[0].memory_map_size);
- if (ret) {
- perror("munmap");
- assert(0);
+
+ transport = lttng_transport_find(transport_name);
+ if (!transport) {
+ DBG("LTTng transport %s not found\n",
+ transport_name);
+ return NULL;
}
- handle->table->objects[0].memory_map = (char *) handle->shadow_chan;
- handle->table->objects[0].is_shadow = 1;
- return handle;
+
+ chan = zmalloc(sizeof(*chan));
+ if (!chan)
+ return NULL;
+
+ chan->chan = transport->ops.channel_create(transport_name, NULL,
+ attr->subbuf_size, attr->num_subbuf,
+ attr->switch_timer_interval,
+ attr->read_timer_interval,
+ attr->uuid);
+ if (!chan->chan) {
+ goto chan_error;
+ }
+ chan->chan->ops = &transport->ops;
+ memcpy(&chan->attr, attr, sizeof(chan->attr));
+ return chan;
+
+chan_error:
+ free(chan);
+ return NULL;
}
-/* Add stream to channel shm and map its shm into process memory */
-int ustctl_add_stream(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_object_data *stream_data)
+void ustctl_destroy_channel(struct ustctl_consumer_channel *chan)
{
- int ret;
+ chan->chan->ops->channel_destroy(chan->chan);
+ free(chan);
+}
+
+int ustctl_send_channel_to_sessiond(int sock,
+ struct ustctl_consumer_channel *channel)
+{
+ struct shm_object_table *table;
- if (!handle || !stream_data)
+ table = channel->chan->handle->table;
+ if (table->size <= 0)
return -EINVAL;
+ return ustctl_send_channel(sock,
+ channel->attr.type,
+ table->objects[0].memory_map,
+ table->objects[0].memory_map_size,
+ 0);
+}
- if (!stream_data->handle)
- return -ENOENT;
- /* map stream */
- ret = channel_handle_add_stream(handle,
- stream_data->shm_fd,
- stream_data->wait_fd,
- stream_data->memory_map_size);
- if (ret) {
- ERR("add stream error\n");
- return ret;
- }
- /*
- * Set to -1 because the lttng_ust_shm_handle destruction will take care
- * of closing shm_fd and wait_fd.
- */
- stream_data->shm_fd = -1;
- stream_data->wait_fd = -1;
- return 0;
+int ustctl_send_stream_to_sessiond(int sock,
+ struct ustctl_consumer_stream *stream)
+{
+ if (!stream)
+ return ustctl_send_stream(sock, -1U, -1U, -1, -1, 0);
+
+ return ustctl_send_stream(sock,
+ stream->cpu,
+ stream->memory_map_size,
+ stream->shm_fd, stream->wakeup_fd,
+ 0);
}
-void ustctl_unmap_channel(struct lttng_ust_shm_handle *handle)
+int ustctl_stream_close_wait_fd(struct ustctl_consumer_stream *stream)
{
struct channel *chan;
- assert(handle);
- chan = shmp(handle, handle->chan);
- channel_destroy(chan, handle, 1);
- free(handle->shadow_chan);
+ chan = stream->chan->chan->chan;
+ return ring_buffer_close_wait_fd(&chan->backend.config,
+ chan, stream->handle, stream->cpu);
}
-/*
- * ustctl closes the shm_fd fds after mapping it.
- */
-struct lttng_ust_lib_ring_buffer *ustctl_open_stream_read(struct lttng_ust_shm_handle *handle,
- int cpu)
+int ustctl_stream_close_wakeup_fd(struct ustctl_consumer_stream *stream)
{
struct channel *chan;
- int *shm_fd, *wait_fd;
- uint64_t *memory_map_size;
+
+ chan = stream->chan->chan->chan;
+ return ring_buffer_close_wakeup_fd(&chan->backend.config,
+ chan, stream->handle, stream->cpu);
+}
+
+struct ustctl_consumer_stream *
+ ustctl_create_stream(struct ustctl_consumer_channel *channel,
+ int cpu)
+{
+ struct ustctl_consumer_stream *stream;
+ struct lttng_ust_shm_handle *handle;
+ struct channel *chan;
+ int shm_fd, wait_fd, wakeup_fd;
+ uint64_t memory_map_size;
struct lttng_ust_lib_ring_buffer *buf;
int ret;
+ if (!channel)
+ return NULL;
+ handle = channel->chan->handle;
if (!handle)
return NULL;
- chan = handle->shadow_chan;
+ chan = channel->chan->chan;
buf = channel_get_ring_buffer(&chan->backend.config,
- chan, cpu, handle, &shm_fd, &wait_fd, &memory_map_size);
+ chan, cpu, handle, &shm_fd, &wait_fd,
+ &wakeup_fd, &memory_map_size);
if (!buf)
return NULL;
- ret = lib_ring_buffer_open_read(buf, handle, 1);
+ ret = lib_ring_buffer_open_read(buf, handle);
if (ret)
return NULL;
- /*
- * We can close shm_fd early, right after is has been mapped.
- */
- if (*shm_fd >= 0) {
- ret = close(*shm_fd);
- if (ret) {
- perror("Error closing shm_fd");
- }
- *shm_fd = -1;
- }
- return buf;
+
+ stream = zmalloc(sizeof(*stream));
+ if (!stream)
+ goto alloc_error;
+ stream->handle = handle;
+ stream->buf = buf;
+ stream->chan = channel;
+ stream->shm_fd = shm_fd;
+ stream->wait_fd = wait_fd;
+ stream->wakeup_fd = wakeup_fd;
+ stream->memory_map_size = memory_map_size;
+ stream->cpu = cpu;
+ return stream;
+
+alloc_error:
+ return NULL;
+}
+
+void ustctl_destroy_stream(struct ustctl_consumer_stream *stream)
+{
+ struct lttng_ust_lib_ring_buffer *buf;
+ struct ustctl_consumer_channel *consumer_chan;
+
+ assert(stream);
+ buf = stream->buf;
+ consumer_chan = stream->chan;
+ lib_ring_buffer_release_read(buf, consumer_chan->chan->handle);
+ free(stream);
}
-void ustctl_close_stream_read(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf)
+int ustctl_get_wait_fd(struct ustctl_consumer_stream *stream)
{
- assert(handle && buf);
- lib_ring_buffer_release_read(buf, handle, 1);
+ struct lttng_ust_lib_ring_buffer *buf;
+ struct ustctl_consumer_channel *consumer_chan;
+
+ if (!stream)
+ return -EINVAL;
+ buf = stream->buf;
+ consumer_chan = stream->chan;
+ return shm_get_wait_fd(consumer_chan->chan->handle, &buf->self._ref);
+}
+
+int ustctl_get_wakeup_fd(struct ustctl_consumer_stream *stream)
+{
+ struct lttng_ust_lib_ring_buffer *buf;
+ struct ustctl_consumer_channel *consumer_chan;
+
+ if (!stream)
+ return -EINVAL;
+ buf = stream->buf;
+ consumer_chan = stream->chan;
+ return shm_get_wakeup_fd(consumer_chan->chan->handle, &buf->self._ref);
}
/* For mmap mode, readable without "get" operation */
-void *ustctl_get_mmap_base(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf)
+void *ustctl_get_mmap_base(struct ustctl_consumer_stream *stream)
{
- if (!handle || !buf)
+ struct lttng_ust_lib_ring_buffer *buf;
+ struct ustctl_consumer_channel *consumer_chan;
+
+ if (!stream)
return NULL;
- return shmp(handle, buf->backend.memory_map);
+ buf = stream->buf;
+ consumer_chan = stream->chan;
+ return shmp(consumer_chan->chan->handle, buf->backend.memory_map);
}
/* returns the length to mmap. */
-int ustctl_get_mmap_len(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf,
+int ustctl_get_mmap_len(struct ustctl_consumer_stream *stream,
unsigned long *len)
{
+ struct ustctl_consumer_channel *consumer_chan;
unsigned long mmap_buf_len;
struct channel *chan;
- if (!handle || !buf || !len)
+ if (!stream)
return -EINVAL;
-
- chan = handle->shadow_chan;
+ consumer_chan = stream->chan;
+ chan = consumer_chan->chan->chan;
if (chan->backend.config.output != RING_BUFFER_MMAP)
return -EINVAL;
mmap_buf_len = chan->backend.buf_size;
}
/* returns the maximum size for sub-buffers. */
-int ustctl_get_max_subbuf_size(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf,
+int ustctl_get_max_subbuf_size(struct ustctl_consumer_stream *stream,
unsigned long *len)
{
+ struct ustctl_consumer_channel *consumer_chan;
struct channel *chan;
- if (!handle || !buf || !len)
+ if (!stream)
return -EINVAL;
-
- chan = handle->shadow_chan;
+ consumer_chan = stream->chan;
+ chan = consumer_chan->chan->chan;
*len = chan->backend.subbuf_size;
return 0;
}
*/
/* returns the offset of the subbuffer belonging to the mmap reader. */
-int ustctl_get_mmap_read_offset(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf, unsigned long *off)
+int ustctl_get_mmap_read_offset(struct ustctl_consumer_stream *stream,
+ unsigned long *off)
{
struct channel *chan;
unsigned long sb_bindex;
+ struct lttng_ust_lib_ring_buffer *buf;
+ struct ustctl_consumer_channel *consumer_chan;
- if (!handle || !buf || !off)
+ if (!stream)
return -EINVAL;
-
- chan = handle->shadow_chan;
+ buf = stream->buf;
+ consumer_chan = stream->chan;
+ chan = consumer_chan->chan->chan;
if (chan->backend.config.output != RING_BUFFER_MMAP)
return -EINVAL;
sb_bindex = subbuffer_id_get_index(&chan->backend.config,
buf->backend.buf_rsb.id);
- *off = shmp(handle, shmp_index(handle, buf->backend.array, sb_bindex)->shmp)->mmap_offset;
+ *off = shmp(consumer_chan->chan->handle,
+ shmp_index(consumer_chan->chan->handle, buf->backend.array, sb_bindex)->shmp)->mmap_offset;
return 0;
}
/* returns the size of the current sub-buffer, without padding (for mmap). */
-int ustctl_get_subbuf_size(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf, unsigned long *len)
+int ustctl_get_subbuf_size(struct ustctl_consumer_stream *stream,
+ unsigned long *len)
{
+ struct ustctl_consumer_channel *consumer_chan;
struct channel *chan;
+ struct lttng_ust_lib_ring_buffer *buf;
- if (!handle || !buf || !len)
+ if (!stream)
return -EINVAL;
- chan = handle->shadow_chan;
+ buf = stream->buf;
+ consumer_chan = stream->chan;
+ chan = consumer_chan->chan->chan;
*len = lib_ring_buffer_get_read_data_size(&chan->backend.config, buf,
- handle);
+ consumer_chan->chan->handle);
return 0;
}
/* returns the size of the current sub-buffer, without padding (for mmap). */
-int ustctl_get_padded_subbuf_size(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf, unsigned long *len)
+int ustctl_get_padded_subbuf_size(struct ustctl_consumer_stream *stream,
+ unsigned long *len)
{
+ struct ustctl_consumer_channel *consumer_chan;
struct channel *chan;
+ struct lttng_ust_lib_ring_buffer *buf;
- if (!handle || !buf || !len)
+ if (!stream)
return -EINVAL;
-
- chan = handle->shadow_chan;
+ buf = stream->buf;
+ consumer_chan = stream->chan;
+ chan = consumer_chan->chan->chan;
*len = lib_ring_buffer_get_read_data_size(&chan->backend.config, buf,
- handle);
+ consumer_chan->chan->handle);
*len = PAGE_ALIGN(*len);
return 0;
}
/* Get exclusive read access to the next sub-buffer that can be read. */
-int ustctl_get_next_subbuf(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf)
+int ustctl_get_next_subbuf(struct ustctl_consumer_stream *stream)
{
- if (!handle || !buf)
- return -EINVAL;
+ struct lttng_ust_lib_ring_buffer *buf;
+ struct ustctl_consumer_channel *consumer_chan;
- return lib_ring_buffer_get_next_subbuf(buf, handle);
+ if (!stream)
+ return -EINVAL;
+ buf = stream->buf;
+ consumer_chan = stream->chan;
+ return lib_ring_buffer_get_next_subbuf(buf,
+ consumer_chan->chan->handle);
}
/* Release exclusive sub-buffer access, move consumer forward. */
-int ustctl_put_next_subbuf(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf)
+int ustctl_put_next_subbuf(struct ustctl_consumer_stream *stream)
{
- if (!handle || !buf)
- return -EINVAL;
+ struct lttng_ust_lib_ring_buffer *buf;
+ struct ustctl_consumer_channel *consumer_chan;
- lib_ring_buffer_put_next_subbuf(buf, handle);
+ if (!stream)
+ return -EINVAL;
+ buf = stream->buf;
+ consumer_chan = stream->chan;
+ lib_ring_buffer_put_next_subbuf(buf, consumer_chan->chan->handle);
return 0;
}
/* snapshot */
/* Get a snapshot of the current ring buffer producer and consumer positions */
-int ustctl_snapshot(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf)
+int ustctl_snapshot(struct ustctl_consumer_stream *stream)
{
- if (!handle || !buf)
- return -EINVAL;
+ struct lttng_ust_lib_ring_buffer *buf;
+ struct ustctl_consumer_channel *consumer_chan;
+ if (!stream)
+ return -EINVAL;
+ buf = stream->buf;
+ consumer_chan = stream->chan;
return lib_ring_buffer_snapshot(buf, &buf->cons_snapshot,
- &buf->prod_snapshot, handle);
+ &buf->prod_snapshot, consumer_chan->chan->handle);
}
/* Get the consumer position (iteration start) */
-int ustctl_snapshot_get_consumed(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf, unsigned long *pos)
+int ustctl_snapshot_get_consumed(struct ustctl_consumer_stream *stream,
+ unsigned long *pos)
{
- if (!handle || !buf || !pos)
- return -EINVAL;
+ struct lttng_ust_lib_ring_buffer *buf;
+ if (!stream)
+ return -EINVAL;
+ buf = stream->buf;
*pos = buf->cons_snapshot;
return 0;
}
/* Get the producer position (iteration end) */
-int ustctl_snapshot_get_produced(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf, unsigned long *pos)
+int ustctl_snapshot_get_produced(struct ustctl_consumer_stream *stream,
+ unsigned long *pos)
{
- if (!handle || !buf || !pos)
- return -EINVAL;
+ struct lttng_ust_lib_ring_buffer *buf;
+ if (!stream)
+ return -EINVAL;
+ buf = stream->buf;
*pos = buf->prod_snapshot;
return 0;
}
/* Get exclusive read access to the specified sub-buffer position */
-int ustctl_get_subbuf(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf, unsigned long *pos)
+int ustctl_get_subbuf(struct ustctl_consumer_stream *stream,
+ unsigned long *pos)
{
- if (!handle || !buf || !pos)
- return -EINVAL;
+ struct lttng_ust_lib_ring_buffer *buf;
+ struct ustctl_consumer_channel *consumer_chan;
- return lib_ring_buffer_get_subbuf(buf, *pos, handle);
+ if (!stream)
+ return -EINVAL;
+ buf = stream->buf;
+ consumer_chan = stream->chan;
+ return lib_ring_buffer_get_subbuf(buf, *pos,
+ consumer_chan->chan->handle);
}
/* Release exclusive sub-buffer access */
-int ustctl_put_subbuf(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf)
+int ustctl_put_subbuf(struct ustctl_consumer_stream *stream)
{
- if (!handle || !buf)
- return -EINVAL;
+ struct lttng_ust_lib_ring_buffer *buf;
+ struct ustctl_consumer_channel *consumer_chan;
- lib_ring_buffer_put_subbuf(buf, handle);
+ if (!stream)
+ return -EINVAL;
+ buf = stream->buf;
+ consumer_chan = stream->chan;
+ lib_ring_buffer_put_subbuf(buf, consumer_chan->chan->handle);
return 0;
}
-void ustctl_flush_buffer(struct lttng_ust_shm_handle *handle,
- struct lttng_ust_lib_ring_buffer *buf,
+void ustctl_flush_buffer(struct ustctl_consumer_stream *stream,
int producer_active)
{
- assert(handle && buf);
+ struct lttng_ust_lib_ring_buffer *buf;
+ struct ustctl_consumer_channel *consumer_chan;
+
+ assert(stream);
+ buf = stream->buf;
+ consumer_chan = stream->chan;
lib_ring_buffer_switch_slow(buf,
producer_active ? SWITCH_ACTIVE : SWITCH_FLUSH,
- handle);
+ consumer_chan->chan->handle);
+}
+
+static __attribute__((constructor))
+void ustctl_init(void)
+{
+ init_usterr();
+ lttng_ring_buffer_metadata_client_init();
+ lttng_ring_buffer_client_overwrite_init();
+ lttng_ring_buffer_client_discard_init();
+}
+
+static __attribute__((destructor))
+void ustctl_exit(void)
+{
+ lttng_ring_buffer_client_discard_exit();
+ lttng_ring_buffer_client_overwrite_exit();
+ lttng_ring_buffer_metadata_client_exit();
}
compat.h \
wait.h \
jhash.h \
- error.h \
- lttng-ust-uuid.h
+ lttng-ust-uuid.h \
+ error.h
liblttng_ust_support_la_SOURCES = \
lttng-tracer.h \
$(top_builddir)/liblttng-ust-comm/liblttng-ust-comm.la \
liblttng-ust-runtime.la liblttng-ust-support.la
-if LTTNG_UST_BUILD_WITH_LIBUUID
-liblttng_ust_la_LIBADD += -luuid
-endif
-if LTTNG_UST_BUILD_WITH_LIBC_UUID
-liblttng_ust_la_LIBADD += -lc
-endif
-
liblttng_ust_la_CFLAGS = -DUST_COMPONENT="liblttng_ust" -fno-strict-aliasing
static CDS_LIST_HEAD(sessions);
static void _lttng_event_destroy(struct lttng_event *event);
-static void _lttng_channel_destroy(struct lttng_channel *chan);
static int _lttng_event_unregister(struct lttng_event *event);
static
int _lttng_event_metadata_statedump(struct lttng_session *session,
struct lttng_session *lttng_session_create(void)
{
struct lttng_session *session;
- int ret, i;
+ int i;
session = zmalloc(sizeof(struct lttng_session));
if (!session)
CDS_INIT_LIST_HEAD(&session->enablers_head);
for (i = 0; i < LTTNG_UST_EVENT_HT_SIZE; i++)
CDS_INIT_HLIST_HEAD(&session->events_ht.table[i]);
- ret = lttng_ust_uuid_generate(session->uuid);
- if (ret != 0) {
- session->uuid[0] = '\0';
- }
cds_list_add(&session->node, &sessions);
return session;
}
+/*
+ * Only used internally at session destruction.
+ */
+static
+void _lttng_channel_unmap(struct lttng_channel *lttng_chan)
+{
+ struct channel *chan;
+ struct lttng_ust_shm_handle *handle;
+
+ cds_list_del(<tng_chan->node);
+ lttng_destroy_context(lttng_chan->ctx);
+ chan = lttng_chan->chan;
+ handle = lttng_chan->handle;
+ /*
+ * note: lttng_chan is private data contained within handle. It
+ * will be freed along with the handle.
+ */
+ channel_destroy(chan, handle, 0);
+}
+
void lttng_session_destroy(struct lttng_session *session)
{
struct lttng_channel *chan, *tmpchan;
&session->events_head, node)
_lttng_event_destroy(event);
cds_list_for_each_entry_safe(chan, tmpchan, &session->chan_head, node)
- _lttng_channel_destroy(chan);
+ _lttng_channel_unmap(chan);
cds_list_del(&session->node);
free(session);
}
return 0;
}
-struct lttng_channel *lttng_channel_create(struct lttng_session *session,
- const char *transport_name,
- void *buf_addr,
- size_t subbuf_size, size_t num_subbuf,
- unsigned int switch_timer_interval,
- unsigned int read_timer_interval,
- int **shm_fd, int **wait_fd,
- uint64_t **memory_map_size,
- struct lttng_channel *chan_priv_init)
-{
- struct lttng_channel *chan = NULL;
- struct lttng_transport *transport;
-
- if (session->been_active)
- goto active; /* Refuse to add channel to active session */
- transport = lttng_transport_find(transport_name);
- if (!transport) {
- DBG("LTTng transport %s not found\n",
- transport_name);
- goto notransport;
- }
- chan_priv_init->id = session->free_chan_id++;
- chan_priv_init->session = session;
- /*
- * Note: the channel creation op already writes into the packet
- * headers. Therefore the "chan" information used as input
- * should be already accessible.
- */
- chan = transport->ops.channel_create(transport_name, buf_addr,
- subbuf_size, num_subbuf, switch_timer_interval,
- read_timer_interval, shm_fd, wait_fd,
- memory_map_size, chan_priv_init);
- if (!chan)
- goto create_error;
- chan->enabled = 1;
- chan->ops = &transport->ops;
- cds_list_add(&chan->node, &session->chan_head);
- return chan;
-
-create_error:
-notransport:
-active:
- return NULL;
-}
-
-/*
- * Only used internally at session destruction.
- */
-static
-void _lttng_channel_destroy(struct lttng_channel *chan)
-{
- cds_list_del(&chan->node);
- lttng_destroy_context(chan->ctx);
- chan->ops->channel_destroy(chan);
-}
-
/*
* Supports event creation while tracing session is active.
*/
static
int _lttng_session_metadata_statedump(struct lttng_session *session)
{
- unsigned char *uuid_c = session->uuid;
+ unsigned char *uuid_c;
char uuid_s[LTTNG_UST_UUID_STR_LEN],
clock_uuid_s[LTTNG_UST_UUID_STR_LEN];
struct lttng_channel *chan;
DBG("LTTng: attempt to start tracing, but metadata channel is not found. Operation abort.\n");
return -EPERM;
}
+ uuid_c = session->metadata->uuid;
snprintf(uuid_s, sizeof(uuid_s),
"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
return;
lttng_session_sync_enablers(session);
}
-
-/*
- * Take the TLS "fault" in libuuid if dlopen'd, which can take the
- * dynamic linker mutex, outside of the UST lock, since the UST lock is
- * taken in constructors, which are called with dynamic linker mutex
- * held.
- */
-void lttng_fixup_event_tls(void)
-{
- unsigned char uuid[LTTNG_UST_UUID_STR_LEN];
-
- (void) lttng_ust_uuid_generate(uuid);
-}
#include <lttng/ust-events.h>
#include "lttng/bitfield.h"
#include "clock.h"
-#include "lttng-ust-uuid.h"
#include "lttng-tracer.h"
#include "../libringbuffer/frontend_types.h"
size_t subbuf_size, size_t num_subbuf,
unsigned int switch_timer_interval,
unsigned int read_timer_interval,
- int **shm_fd, int **wait_fd,
- uint64_t **memory_map_size,
- struct lttng_channel *chan_priv_init)
+ unsigned char *uuid)
{
- void *priv;
- struct lttng_channel *lttng_chan = NULL;
+ struct lttng_channel chan_priv_init;
struct lttng_ust_shm_handle *handle;
+ struct lttng_channel *lttng_chan;
+ void *priv;
+ memset(&chan_priv_init, 0, sizeof(chan_priv_init));
+ memcpy(chan_priv_init.uuid, uuid, LTTNG_UST_UUID_LEN);
handle = channel_create(&client_config, name,
&priv, __alignof__(*lttng_chan), sizeof(*lttng_chan),
- chan_priv_init,
+ &chan_priv_init,
buf_addr, subbuf_size, num_subbuf,
- switch_timer_interval, read_timer_interval,
- shm_fd, wait_fd, memory_map_size);
+ switch_timer_interval, read_timer_interval);
if (!handle)
return NULL;
lttng_chan = priv;
lttng_chan->handle = handle;
- lttng_chan->chan = shmp(lttng_chan->handle, lttng_chan->handle->chan);
+ lttng_chan->chan = shmp(handle, handle->chan);
return lttng_chan;
}
static
-void lttng_channel_destroy(struct lttng_channel *lttng_chan)
-{
- channel_destroy(lttng_chan->chan, lttng_chan->handle, 0);
-}
-
-static
-struct lttng_ust_lib_ring_buffer *lttng_buffer_read_open(struct channel *chan,
- struct lttng_ust_shm_handle *handle,
- int **shm_fd, int **wait_fd,
- uint64_t **memory_map_size)
-{
- struct lttng_ust_lib_ring_buffer *buf;
- int cpu;
-
- for_each_channel_cpu(cpu, chan) {
- buf = channel_get_ring_buffer(&client_config, chan,
- cpu, handle, shm_fd, wait_fd,
- memory_map_size);
- if (!lib_ring_buffer_open_read(buf, handle, 0))
- return buf;
- }
- return NULL;
-}
-
-static
-void lttng_buffer_read_close(struct lttng_ust_lib_ring_buffer *buf,
- struct lttng_ust_shm_handle *handle)
+void lttng_channel_destroy(struct lttng_channel *chan)
{
- lib_ring_buffer_release_read(buf, handle, 0);
+ channel_destroy(chan->chan, chan->handle, 1);
}
static
int cpu;
for_each_channel_cpu(cpu, chan) {
- int *shm_fd, *wait_fd;
- uint64_t *memory_map_size;
+ int shm_fd, wait_fd, wakeup_fd;
+ uint64_t memory_map_size;
buf = channel_get_ring_buffer(&client_config, chan,
cpu, handle, &shm_fd, &wait_fd,
- &memory_map_size);
+ &wakeup_fd, &memory_map_size);
lib_ring_buffer_switch(&client_config, buf,
SWITCH_ACTIVE, handle);
}
.ops = {
.channel_create = _channel_create,
.channel_destroy = lttng_channel_destroy,
- .buffer_read_open = lttng_buffer_read_open,
- .buffer_read_close = lttng_buffer_read_close,
.event_reserve = lttng_event_reserve,
.event_commit = lttng_event_commit,
.event_write = lttng_event_write,
.is_disabled = lttng_is_disabled,
.flush_buffer = lttng_flush_buffer,
},
+ .client_config = &client_config,
};
void RING_BUFFER_MODE_TEMPLATE_INIT(void)
header->checksum_scheme = 0; /* 0 if unused */
header->major = CTF_SPEC_MAJOR;
header->minor = CTF_SPEC_MINOR;
-
}
/*
size_t subbuf_size, size_t num_subbuf,
unsigned int switch_timer_interval,
unsigned int read_timer_interval,
- int **shm_fd, int **wait_fd,
- uint64_t **memory_map_size,
- struct lttng_channel *chan_priv_init)
+ unsigned char *uuid)
{
- void *priv;
- struct lttng_channel *lttng_chan = NULL;
+ struct lttng_channel chan_priv_init;
struct lttng_ust_shm_handle *handle;
+ struct lttng_channel *lttng_chan;
+ void *priv;
+ memset(&chan_priv_init, 0, sizeof(chan_priv_init));
+ memcpy(chan_priv_init.uuid, uuid, LTTNG_UST_UUID_LEN);
handle = channel_create(&client_config, name,
&priv, __alignof__(*lttng_chan), sizeof(*lttng_chan),
- chan_priv_init,
+ &chan_priv_init,
buf_addr, subbuf_size, num_subbuf,
- switch_timer_interval, read_timer_interval,
- shm_fd, wait_fd, memory_map_size);
+ switch_timer_interval, read_timer_interval);
if (!handle)
return NULL;
lttng_chan = priv;
lttng_chan->handle = handle;
- lttng_chan->chan = shmp(lttng_chan->handle, lttng_chan->handle->chan);
+ lttng_chan->chan = shmp(handle, handle->chan);
return lttng_chan;
}
static
-void lttng_channel_destroy(struct lttng_channel *lttng_chan)
-{
- channel_destroy(lttng_chan->chan, lttng_chan->handle, 0);
-}
-
-static
-struct lttng_ust_lib_ring_buffer *lttng_buffer_read_open(struct channel *chan,
- struct lttng_ust_shm_handle *handle,
- int **shm_fd, int **wait_fd,
- uint64_t **memory_map_size)
-{
- struct lttng_ust_lib_ring_buffer *buf;
-
- buf = channel_get_ring_buffer(&client_config, chan,
- 0, handle, shm_fd, wait_fd, memory_map_size);
- if (!lib_ring_buffer_open_read(buf, handle, 0))
- return buf;
- return NULL;
-}
-
-static
-void lttng_buffer_read_close(struct lttng_ust_lib_ring_buffer *buf,
- struct lttng_ust_shm_handle *handle)
+void lttng_channel_destroy(struct lttng_channel *chan)
{
- lib_ring_buffer_release_read(buf, handle, 0);
+ channel_destroy(chan->chan, chan->handle, 1);
}
static
int lttng_flush_buffer(struct channel *chan, struct lttng_ust_shm_handle *handle)
{
struct lttng_ust_lib_ring_buffer *buf;
- int *shm_fd, *wait_fd;
- uint64_t *memory_map_size;
+ int shm_fd, wait_fd, wakeup_fd;
+ uint64_t memory_map_size;
buf = channel_get_ring_buffer(&client_config, chan,
- 0, handle, &shm_fd, &wait_fd,
+ 0, handle, &shm_fd, &wait_fd, &wakeup_fd,
&memory_map_size);
lib_ring_buffer_switch(&client_config, buf,
SWITCH_ACTIVE, handle);
.ops = {
.channel_create = _channel_create,
.channel_destroy = lttng_channel_destroy,
- .buffer_read_open = lttng_buffer_read_open,
- .buffer_read_close = lttng_buffer_read_close,
.event_reserve = lttng_event_reserve,
.event_commit = lttng_event_commit,
.event_write = lttng_event_write,
.is_disabled = lttng_is_disabled,
.flush_buffer = lttng_flush_buffer,
},
+ .client_config = &client_config,
};
void RING_BUFFER_MODE_TEMPLATE_INIT(void)
void lttng_fixup_vtid_tls(void);
void lttng_fixup_procname_tls(void);
+const char *lttng_ust_obj_get_name(int id);
+
#endif /* _LTTNG_TRACER_CORE_H */
#include <usterr-signal-safe.h>
#include <helper.h>
#include "lttng-tracer.h"
+#include "../libringbuffer/shm.h"
+#include "../libringbuffer/frontend_types.h"
#define OBJ_NAME_LEN 16
objd_table.freelist_head = -1;
}
+const char *lttng_ust_obj_get_name(int id)
+{
+ struct lttng_ust_obj *obj = _objd_get(id);
+
+ if (!obj)
+ return NULL;
+ return obj->u.s.name;
+}
+
void lttng_ust_objd_table_owner_cleanup(void *owner)
{
int i;
static const struct lttng_ust_objd_ops lttng_ops;
static const struct lttng_ust_objd_ops lttng_session_ops;
static const struct lttng_ust_objd_ops lttng_channel_ops;
-static const struct lttng_ust_objd_ops lttng_metadata_ops;
static const struct lttng_ust_objd_ops lttng_enabler_ops;
-static const struct lttng_ust_objd_ops lib_ring_buffer_objd_ops;
static const struct lttng_ust_objd_ops lttng_tracepoint_list_ops;
static const struct lttng_ust_objd_ops lttng_tracepoint_field_list_ops;
-enum channel_type {
- PER_CPU_CHANNEL,
- METADATA_CHANNEL,
-};
-
int lttng_abi_create_root_handle(void)
{
int root_handle;
return root_handle;
}
+static
+int lttng_is_channel_ready(struct lttng_channel *lttng_chan)
+{
+ struct channel *chan;
+ unsigned int nr_streams, exp_streams;
+
+ chan = lttng_chan->chan;
+ nr_streams = channel_handle_get_nr_streams(lttng_chan->handle);
+ exp_streams = chan->nr_streams;
+ return nr_streams == exp_streams;
+}
+
static
int lttng_abi_create_session(void *owner)
{
return; /* not allowed to return error */
}
-int lttng_abi_create_channel(int session_objd,
- struct lttng_ust_channel *chan_param,
- enum channel_type channel_type,
- union ust_args *uargs,
- void *owner)
+int lttng_abi_map_channel(int session_objd,
+ struct lttng_ust_channel *ust_chan,
+ union ust_args *uargs,
+ void *owner)
{
struct lttng_session *session = objd_private(session_objd);
- const struct lttng_ust_objd_ops *ops;
const char *transport_name;
- struct lttng_channel *chan;
+ const struct lttng_transport *transport;
+ const char *chan_name;
int chan_objd;
- int ret = 0;
- struct lttng_channel chan_priv_init;
+ struct lttng_ust_shm_handle *channel_handle;
+ struct lttng_channel *lttng_chan;
+ struct channel *chan;
+ struct lttng_ust_lib_ring_buffer_config *config;
+ void *chan_data;
+ uint64_t len;
+ int ret;
+ enum lttng_ust_chan_type type;
+
+ chan_data = uargs->channel.chan_data;
+ len = ust_chan->len;
+ type = ust_chan->type;
+
+ switch (type) {
+ case LTTNG_UST_CHAN_PER_CPU:
+ case LTTNG_UST_CHAN_METADATA:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (session->been_active) {
+ ret = -EBUSY;
+ goto active; /* Refuse to add channel to active session */
+ }
- switch (channel_type) {
- case PER_CPU_CHANNEL:
- if (chan_param->output == LTTNG_UST_MMAP) {
- transport_name = chan_param->overwrite ?
+ channel_handle = channel_handle_create(chan_data, len);
+ if (!channel_handle) {
+ ret = -EINVAL;
+ goto handle_error;
+ }
+
+ chan = shmp(channel_handle, channel_handle->chan);
+ assert(chan);
+ config = &chan->backend.config;
+ lttng_chan = channel_get_private(chan);
+ if (!lttng_chan) {
+ ret = -EINVAL;
+ goto alloc_error;
+ }
+
+ /* Lookup transport name */
+ switch (type) {
+ case LTTNG_UST_CHAN_PER_CPU:
+ if (config->output == RING_BUFFER_MMAP) {
+ transport_name = config->mode == RING_BUFFER_OVERWRITE ?
"relay-overwrite-mmap" : "relay-discard-mmap";
} else {
- return -EINVAL;
+ ret = -EINVAL;
+ goto notransport;
}
- ops = <tng_channel_ops;
+ chan_name = "channel";
break;
- case METADATA_CHANNEL:
- if (chan_param->output == LTTNG_UST_MMAP)
+ case LTTNG_UST_CHAN_METADATA:
+ if (config->output == RING_BUFFER_MMAP) {
transport_name = "relay-metadata-mmap";
- else
- return -EINVAL;
- ops = <tng_metadata_ops;
+ } else {
+ ret = -EINVAL;
+ goto notransport;
+ }
+ chan_name = "metadata";
break;
default:
transport_name = "<unknown>";
- return -EINVAL;
+ chan_name = "<unknown>";
+ ret = -EINVAL;
+ goto notransport;
}
- chan_objd = objd_alloc(NULL, ops, owner, "channel");
+ transport = lttng_transport_find(transport_name);
+ if (!transport) {
+ DBG("LTTng transport %s not found\n",
+ transport_name);
+ ret = -EINVAL;
+ goto notransport;
+ }
+
+ chan_objd = objd_alloc(NULL, <tng_channel_ops, owner, chan_name);
if (chan_objd < 0) {
ret = chan_objd;
goto objd_error;
}
- memset(&chan_priv_init, 0, sizeof(chan_priv_init));
- /* Copy of session UUID for consumer (availability through shm) */
- memcpy(chan_priv_init.uuid, session->uuid, sizeof(session->uuid));
-
+
+ /* Initialize our lttng chan */
+ lttng_chan->chan = chan;
+ lttng_chan->enabled = 1;
+ lttng_chan->ctx = NULL;
+ lttng_chan->session = session;
+ lttng_chan->free_event_id = 0;
+ lttng_chan->used_event_id = 0;
+ lttng_chan->ops = &transport->ops;
+ memcpy(<tng_chan->chan->backend.config,
+ transport->client_config,
+ sizeof(lttng_chan->chan->backend.config));
+ cds_list_add(<tng_chan->node, &session->chan_head);
+ lttng_chan->header_type = 0;
+ lttng_chan->handle = channel_handle;
+ lttng_chan->metadata_dumped = 0;
+ lttng_chan->id = session->free_chan_id++;
+ lttng_chan->type = type;
+
/*
* We tolerate no failure path after channel creation. It will stay
* invariant for the rest of the session.
*/
- chan = lttng_channel_create(session, transport_name, NULL,
- chan_param->subbuf_size,
- chan_param->num_subbuf,
- chan_param->switch_timer_interval,
- chan_param->read_timer_interval,
- &uargs->channel.shm_fd,
- &uargs->channel.wait_fd,
- &uargs->channel.memory_map_size,
- &chan_priv_init);
- if (!chan) {
- ret = -EINVAL;
- goto chan_error;
- }
- objd_set_private(chan_objd, chan);
- chan->objd = chan_objd;
- if (channel_type == METADATA_CHANNEL) {
- session->metadata = chan;
- lttng_metadata_create_events(chan_objd);
- }
+ objd_set_private(chan_objd, lttng_chan);
+ lttng_chan->objd = chan_objd;
/* The channel created holds a reference on the session */
objd_ref(session_objd);
-
return chan_objd;
-chan_error:
- {
- int err;
-
- err = lttng_ust_objd_unref(chan_objd);
- assert(!err);
- }
objd_error:
+notransport:
+ free(lttng_chan);
+alloc_error:
+ channel_destroy(chan, channel_handle, 0);
+handle_error:
+active:
return ret;
}
switch (cmd) {
case LTTNG_UST_CHANNEL:
- return lttng_abi_create_channel(objd,
+ return lttng_abi_map_channel(objd,
(struct lttng_ust_channel *) arg,
- PER_CPU_CHANNEL, uargs, owner);
+ uargs, owner);
case LTTNG_UST_SESSION_START:
case LTTNG_UST_ENABLE:
return lttng_session_enable(session);
case LTTNG_UST_SESSION_STOP:
case LTTNG_UST_DISABLE:
return lttng_session_disable(session);
- case LTTNG_UST_METADATA:
- return lttng_abi_create_channel(objd,
- (struct lttng_ust_channel *) arg,
- METADATA_CHANNEL, uargs, owner);
default:
return -EINVAL;
}
.cmd = lttng_tracepoint_field_list_cmd,
};
-struct stream_priv_data {
- struct lttng_ust_lib_ring_buffer *buf;
- struct lttng_channel *lttng_chan;
-};
-
static
-int lttng_abi_open_stream(int channel_objd, struct lttng_ust_stream *info,
+int lttng_abi_map_stream(int channel_objd, struct lttng_ust_stream *info,
union ust_args *uargs, void *owner)
{
struct lttng_channel *channel = objd_private(channel_objd);
- struct lttng_ust_lib_ring_buffer *buf;
- struct stream_priv_data *priv;
- int stream_objd, ret;
-
- buf = channel->ops->buffer_read_open(channel->chan, channel->handle,
- &uargs->stream.shm_fd,
- &uargs->stream.wait_fd,
- &uargs->stream.memory_map_size);
- if (!buf)
- return -ENOENT;
-
- priv = zmalloc(sizeof(*priv));
- if (!priv) {
- ret = -ENOMEM;
- goto alloc_error;
- }
- priv->buf = buf;
- priv->lttng_chan = channel;
- stream_objd = objd_alloc(priv, &lib_ring_buffer_objd_ops, owner, "open_stream");
- if (stream_objd < 0) {
- ret = stream_objd;
- goto objd_error;
- }
- /* Hold a reference on the channel object descriptor */
- objd_ref(channel_objd);
- return stream_objd;
+ int ret;
-objd_error:
- free(priv);
-alloc_error:
- channel->ops->buffer_read_close(buf, channel->handle);
+ ret = channel_handle_add_stream(channel->handle,
+ uargs->stream.shm_fd, uargs->stream.wakeup_fd,
+ info->stream_nr, info->len);
+ if (ret)
+ goto error_add_stream;
+
+ return 0;
+
+error_add_stream:
return ret;
}
return ret;
}
+static
+long lttng_metadata_cmd(int objd, unsigned int cmd, unsigned long arg,
+ union ust_args *uargs, void *owner)
+{
+ struct lttng_channel *channel = objd_private(objd);
+ struct lttng_session *session = channel->session;
+
+ switch (cmd) {
+ case LTTNG_UST_STREAM:
+ {
+ struct lttng_ust_stream *stream;
+ int ret;
+
+ stream = (struct lttng_ust_stream *) arg;
+ /* stream used as output */
+ ret = lttng_abi_map_stream(objd, stream, uargs, owner);
+ if (ret == 0) {
+ session->metadata = channel;
+ lttng_metadata_create_events(objd);
+ }
+ return ret;
+ }
+ case LTTNG_UST_FLUSH_BUFFER:
+ {
+ if (!session->metadata) {
+ return -ENOENT;
+ }
+ return channel->ops->flush_buffer(channel->chan, channel->handle);
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
/**
* lttng_channel_cmd - lttng control through object descriptors
*
{
struct lttng_channel *channel = objd_private(objd);
+ if (cmd != LTTNG_UST_STREAM) {
+ /*
+ * Check if channel received all streams.
+ */
+ if (!lttng_is_channel_ready(channel))
+ return -EPERM;
+ }
+
+ if (channel->type == LTTNG_UST_CHAN_METADATA) {
+ return lttng_metadata_cmd(objd, cmd, arg, uargs, owner);
+ }
+
switch (cmd) {
case LTTNG_UST_STREAM:
{
stream = (struct lttng_ust_stream *) arg;
/* stream used as output */
- return lttng_abi_open_stream(objd, stream, uargs, owner);
+ return lttng_abi_map_stream(objd, stream, uargs, owner);
}
case LTTNG_UST_EVENT:
{
}
}
-/**
- * lttng_metadata_cmd - lttng control through object descriptors
- *
- * @objd: the object descriptor
- * @cmd: the command
- * @arg: command arg
- * @uargs: UST arguments (internal)
- * @owner: objd owner
- *
- * This object descriptor implements lttng commands:
- * LTTNG_UST_STREAM
- * Returns an event stream file descriptor or failure.
- *
- * Channel and event file descriptors also hold a reference on the session.
- */
-static
-long lttng_metadata_cmd(int objd, unsigned int cmd, unsigned long arg,
- union ust_args *uargs, void *owner)
-{
- struct lttng_channel *channel = objd_private(objd);
-
- switch (cmd) {
- case LTTNG_UST_STREAM:
- {
- struct lttng_ust_stream *stream;
-
- stream = (struct lttng_ust_stream *) arg;
- /* stream used as output */
- return lttng_abi_open_stream(objd, stream, uargs, owner);
- }
- case LTTNG_UST_FLUSH_BUFFER:
- return channel->ops->flush_buffer(channel->chan, channel->handle);
- default:
- return -EINVAL;
- }
-}
-
static
int lttng_channel_release(int objd)
{
.cmd = lttng_channel_cmd,
};
-static const struct lttng_ust_objd_ops lttng_metadata_ops = {
- .release = lttng_channel_release,
- .cmd = lttng_metadata_cmd,
-};
-
-/**
- * lttng_rb_cmd - lttng ring buffer control through object descriptors
- *
- * @objd: the object descriptor
- * @cmd: the command
- * @arg: command arg
- * @uargs: UST arguments (internal)
- * @owner: objd owner
- *
- * This object descriptor implements lttng commands:
- * (None for now. Access is done directly though shm.)
- */
-static
-long lttng_rb_cmd(int objd, unsigned int cmd, unsigned long arg,
- union ust_args *uargs, void *owner)
-{
- switch (cmd) {
- default:
- return -EINVAL;
- }
-}
-
-static
-int lttng_rb_release(int objd)
-{
- struct stream_priv_data *priv = objd_private(objd);
- struct lttng_ust_lib_ring_buffer *buf;
- struct lttng_channel *channel;
-
- if (priv) {
- buf = priv->buf;
- channel = priv->lttng_chan;
- free(priv);
- /*
- * If we are at ABI exit, we don't want to close the
- * buffer opened for read: it is being shared between
- * the parent and child (right after fork), and we don't
- * want the child to close it for the parent. For a real
- * exit, we don't care about marking it as closed, as
- * the consumer daemon (if there is one) will do fine
- * even if we don't mark it as "closed" for reading on
- * our side.
- * We only mark it as closed if it is being explicitely
- * released by the session daemon with an explicit
- * release command.
- */
- if (!lttng_ust_abi_close_in_progress)
- channel->ops->buffer_read_close(buf, channel->handle);
-
- return lttng_ust_objd_unref(channel->objd);
- }
- return 0;
-}
-
-static const struct lttng_ust_objd_ops lib_ring_buffer_objd_ops = {
- .release = lttng_rb_release,
- .cmd = lttng_rb_cmd,
-};
-
/**
* lttng_enabler_cmd - lttng control through object descriptors
*
#include <lttng/ust-abi.h>
#include <lttng/ust.h>
#include <lttng/ust-error.h>
+#include <lttng/ust-ctl.h>
#include <ust-comm.h>
#include <usterr-signal-safe.h>
#include <helper.h>
static int wait_poll_fallback;
+static const char *cmd_name_mapping[] = {
+ [ LTTNG_UST_RELEASE ] = "Release",
+ [ LTTNG_UST_SESSION ] = "Create Session",
+ [ LTTNG_UST_TRACER_VERSION ] = "Get Tracer Version",
+
+ [ LTTNG_UST_TRACEPOINT_LIST ] = "Create Tracepoint List",
+ [ LTTNG_UST_WAIT_QUIESCENT ] = "Wait for Quiescent State",
+ [ LTTNG_UST_REGISTER_DONE ] = "Registration Done",
+ [ LTTNG_UST_TRACEPOINT_FIELD_LIST ] = "Create Tracepoint Field List",
+
+ /* Session FD commands */
+ [ LTTNG_UST_CHANNEL ] = "Create Channel",
+ [ LTTNG_UST_SESSION_START ] = "Start Session",
+ [ LTTNG_UST_SESSION_STOP ] = "Stop Session",
+
+ /* Channel FD commands */
+ [ LTTNG_UST_STREAM ] = "Create Stream",
+ [ LTTNG_UST_EVENT ] = "Create Event",
+
+ /* Event and Channel FD commands */
+ [ LTTNG_UST_CONTEXT ] = "Create Context",
+ [ LTTNG_UST_FLUSH_BUFFER ] = "Flush Buffer",
+
+ /* Event, Channel and Session commands */
+ [ LTTNG_UST_ENABLE ] = "Enable",
+ [ LTTNG_UST_DISABLE ] = "Disable",
+
+ /* Tracepoint list commands */
+ [ LTTNG_UST_TRACEPOINT_LIST_GET ] = "List Next Tracepoint",
+ [ LTTNG_UST_TRACEPOINT_FIELD_LIST_GET ] = "List Next Tracepoint Field",
+
+ /* Event FD commands */
+ [ LTTNG_UST_FILTER ] = "Create Filter",
+};
+
extern void lttng_ring_buffer_client_overwrite_init(void);
extern void lttng_ring_buffer_client_discard_init(void);
extern void lttng_ring_buffer_metadata_client_init(void);
asm volatile ("" : : "m" (lttng_ust_nest_count));
}
+static
+void print_cmd(int cmd, int handle)
+{
+ const char *cmd_name = "Unknown";
+
+ if (cmd_name_mapping[cmd]) {
+ cmd_name = cmd_name_mapping[cmd];
+ }
+ DBG("Message Received \"%s\", Handle \"%s\" (%d)", cmd_name,
+ lttng_ust_obj_get_name(handle), handle);
+}
+
static
int setup_local_apps(void)
{
int ret = 0;
const struct lttng_ust_objd_ops *ops;
struct ustcomm_ust_reply lur;
- int shm_fd, wait_fd;
union ust_args args;
ssize_t len;
memset(&lur, 0, sizeof(lur));
if (lttng_ust_comm_should_quit) {
- ret = -EPERM;
+ ret = -LTTNG_UST_ERR_EXITING;
goto end;
}
}
break;
}
+ case LTTNG_UST_CHANNEL:
+ {
+ void *chan_data;
+
+ len = ustcomm_recv_channel_from_sessiond(sock,
+ &chan_data, lum->u.channel.len);
+ switch (len) {
+ case 0: /* orderly shutdown */
+ ret = 0;
+ goto error;
+ default:
+ if (len == lum->u.channel.len) {
+ DBG("channel data received");
+ break;
+ } else if (len < 0) {
+ DBG("Receive failed from lttng-sessiond with errno %d", (int) -len);
+ if (len == -ECONNRESET) {
+ ERR("%s remote end closed connection", sock_info->name);
+ ret = len;
+ goto error;
+ }
+ ret = len;
+ goto end;
+ } else {
+ DBG("incorrect channel data message size: %zd", len);
+ ret = -EINVAL;
+ goto end;
+ }
+ }
+ args.channel.chan_data = chan_data;
+ if (ops->cmd)
+ ret = ops->cmd(lum->handle, lum->cmd,
+ (unsigned long) &lum->u,
+ &args, sock_info);
+ else
+ ret = -ENOSYS;
+ break;
+ }
+ case LTTNG_UST_STREAM:
+ {
+ /* Receive shm_fd, wakeup_fd */
+ ret = ustcomm_recv_stream_from_sessiond(sock,
+ &lum->u.stream.len,
+ &args.stream.shm_fd,
+ &args.stream.wakeup_fd);
+ if (ret) {
+ goto end;
+ }
+ if (ops->cmd)
+ ret = ops->cmd(lum->handle, lum->cmd,
+ (unsigned long) &lum->u,
+ &args, sock_info);
+ else
+ ret = -ENOSYS;
+ break;
+ }
default:
if (ops->cmd)
ret = ops->cmd(lum->handle, lum->cmd,
}
if (ret >= 0) {
switch (lum->cmd) {
- case LTTNG_UST_STREAM:
- /*
- * Special-case reply to send stream info.
- * Use lum.u output.
- */
- lur.u.stream.memory_map_size = *args.stream.memory_map_size;
- shm_fd = *args.stream.shm_fd;
- wait_fd = *args.stream.wait_fd;
- break;
- case LTTNG_UST_METADATA:
- case LTTNG_UST_CHANNEL:
- lur.u.channel.memory_map_size = *args.channel.memory_map_size;
- shm_fd = *args.channel.shm_fd;
- wait_fd = *args.channel.wait_fd;
- break;
case LTTNG_UST_TRACER_VERSION:
lur.u.version = lum->u.version;
break;
break;
}
}
+ DBG("Return value: %d", lur.ret_val);
ret = send_reply(sock, &lur);
if (ret < 0) {
DBG("error sending reply");
goto error;
}
- if ((lum->cmd == LTTNG_UST_STREAM
- || lum->cmd == LTTNG_UST_CHANNEL
- || lum->cmd == LTTNG_UST_METADATA)
- && lur.ret_code == LTTNG_UST_OK) {
- int sendret = 0;
-
- /* we also need to send the file descriptors. */
- ret = ustcomm_send_fds_unix_sock(sock,
- &shm_fd, &shm_fd,
- 1, sizeof(int));
- if (ret < 0) {
- ERR("send shm_fd");
- sendret = ret;
- }
- /*
- * The sessiond expects 2 file descriptors, even upon
- * error.
- */
- ret = ustcomm_send_fds_unix_sock(sock,
- &wait_fd, &wait_fd,
- 1, sizeof(int));
- if (ret < 0) {
- perror("send wait_fd");
- goto error;
- }
- if (sendret) {
- ret = sendret;
- goto error;
- }
- }
/*
* LTTNG_UST_TRACEPOINT_FIELD_LIST_GET needs to send the field
* after the reply.
}
}
}
- /*
- * We still have the memory map reference, and the fds have been
- * sent to the sessiond. We can therefore close those fds. Note
- * that we keep the write side of the wait_fd open, but close
- * the read side.
- */
- if (lur.ret_code == LTTNG_UST_OK) {
- switch (lum->cmd) {
- case LTTNG_UST_STREAM:
- if (shm_fd >= 0) {
- ret = close(shm_fd);
- if (ret) {
- PERROR("Error closing stream shm_fd");
- }
- *args.stream.shm_fd = -1;
- }
- if (wait_fd >= 0) {
- ret = close(wait_fd);
- if (ret) {
- PERROR("Error closing stream wait_fd");
- }
- *args.stream.wait_fd = -1;
- }
- break;
- case LTTNG_UST_METADATA:
- case LTTNG_UST_CHANNEL:
- if (shm_fd >= 0) {
- ret = close(shm_fd);
- if (ret) {
- PERROR("Error closing channel shm_fd");
- }
- *args.channel.shm_fd = -1;
- }
- if (wait_fd >= 0) {
- ret = close(wait_fd);
- if (ret) {
- PERROR("Error closing channel wait_fd");
- }
- *args.channel.wait_fd = -1;
- }
- break;
- }
- }
error:
ust_unlock();
ust_unlock();
goto end;
case sizeof(lum):
- DBG("message received");
+ print_cmd(lum.cmd, lum.handle);
ret = handle_message(sock_info, sock, &lum);
if (ret) {
ERR("Error handling message for %s socket", sock_info->name);
* to be the dynamic linker mutex) and ust_lock, taken within
* the ust lock.
*/
- lttng_fixup_event_tls();
lttng_fixup_ringbuffer_tls();
lttng_fixup_vtid_tls();
lttng_fixup_nest_count_tls();
* SOFTWARE.
*/
-#include <config.h>
#include <lttng/ust-events.h> /* For LTTNG_UST_UUID_LEN */
+
/*
* Includes final \0.
*/
-#define LTTNG_UST_UUID_STR_LEN 37
-
-#ifdef LTTNG_UST_HAVE_LIBUUID
-#include <uuid/uuid.h>
-
-static inline
-int lttng_ust_uuid_generate(unsigned char *uuid_out)
-{
- uuid_generate(uuid_out);
- return 0;
-}
-
-#elif defined(LTTNG_UST_HAVE_LIBC_UUID)
-#include <uuid.h>
-#include <stdint.h>
-
-static inline
-int lttng_ust_uuid_generate(unsigned char *uuid_out)
-{
- uint32_t status;
-
- uuid_create((uuid_t *) uuid_out, &status);
- if (status == uuid_s_ok)
- return 0;
- else
- return -1;
-}
-
-#else
-#error "LTTng-UST needs to have a UUID generator configured."
-#endif
+#define LTTNG_UST_UUID_STR_LEN 37
#endif /* _LTTNG_UST_UUID_H */
void *buf_addr,
size_t subbuf_size, size_t num_subbuf,
unsigned int switch_timer_interval,
- unsigned int read_timer_interval,
- int **shm_fd, int **wait_fd,
- uint64_t **memory_map_size);
-
-/* channel_handle_create - for consumer. */
-extern
-struct lttng_ust_shm_handle *channel_handle_create(int shm_fd, int wait_fd,
- uint64_t memory_map_size);
-
-/* channel_handle_add_stream - for consumer. */
-extern
-int channel_handle_add_stream(struct lttng_ust_shm_handle *handle,
- int shm_fd, int wait_fd, uint64_t memory_map_size);
+ unsigned int read_timer_interval);
/*
* channel_destroy finalizes all channel's buffers, waits for readers to
*/
extern
void channel_destroy(struct channel *chan, struct lttng_ust_shm_handle *handle,
- int shadow);
+ int consumer);
/* Buffer read operations */
const struct lttng_ust_lib_ring_buffer_config *config,
struct channel *chan, int cpu,
struct lttng_ust_shm_handle *handle,
- int **shm_fd, int **wait_fd,
- uint64_t **memory_map_size);
+ int *shm_fd, int *wait_fd,
+ int *wakeup_fd,
+ uint64_t *memory_map_size);
+extern
+int ring_buffer_close_wait_fd(const struct lttng_ust_lib_ring_buffer_config *config,
+ struct channel *chan,
+ struct lttng_ust_shm_handle *handle,
+ int cpu);
+extern
+int ring_buffer_close_wakeup_fd(const struct lttng_ust_lib_ring_buffer_config *config,
+ struct channel *chan,
+ struct lttng_ust_shm_handle *handle,
+ int cpu);
+
extern int lib_ring_buffer_open_read(struct lttng_ust_lib_ring_buffer *buf,
- struct lttng_ust_shm_handle *handle,
- int shadow);
+ struct lttng_ust_shm_handle *handle);
extern void lib_ring_buffer_release_read(struct lttng_ust_lib_ring_buffer *buf,
- struct lttng_ust_shm_handle *handle,
- int shadow);
+ struct lttng_ust_shm_handle *handle);
/*
* Read sequence: snapshot, many get_subbuf/put_subbuf, move_consumer.
* RING_BUFFER_WAKEUP_BY_WRITER wakeup is not lock-free.
*/
if (config->wakeup == RING_BUFFER_WAKEUP_BY_WRITER
- && (uatomic_read(&buf->active_readers)
- || uatomic_read(&buf->active_shadow_readers))
+ && uatomic_read(&buf->active_readers)
&& lib_ring_buffer_poll_deliver(config, buf, chan, handle)) {
int wakeup_fd = shm_get_wakeup_fd(handle, &buf->self._ref);
enum switch_mode { SWITCH_ACTIVE, SWITCH_FLUSH };
/* channel: collection of per-cpu ring buffers. */
+#define RB_CHANNEL_PADDING 32
struct channel {
int record_disabled;
unsigned long commit_count_mask; /*
//wait_queue_head_t read_wait; /* reader wait queue */
int finalized; /* Has channel been finalized */
size_t priv_data_offset;
- /* Note: padding field is missing */
+ unsigned int nr_streams; /* Number of streams */
+ char padding[RB_CHANNEL_PADDING];
/*
* Associated backend contains a variable-length array. Needs to
* be last member.
* Active readers count
* standard atomic access (shared)
*/
- long active_shadow_readers;
/* Dropped records */
union v_atomic records_lost_full; /* Buffer full */
union v_atomic records_lost_wrap; /* Nested wrap-around */
for_each_possible_cpu(i) {
struct shm_object *shmobj;
- shmobj = shm_object_table_append(handle->table, shmsize);
+ shmobj = shm_object_table_alloc(handle->table, shmsize,
+ SHM_OBJECT_SHM);
if (!shmobj)
goto end;
align_shm(shmobj, __alignof__(struct lttng_ust_lib_ring_buffer));
struct shm_object *shmobj;
struct lttng_ust_lib_ring_buffer *buf;
- shmobj = shm_object_table_append(handle->table, shmsize);
+ shmobj = shm_object_table_alloc(handle->table, shmsize,
+ SHM_OBJECT_SHM);
if (!shmobj)
goto end;
align_shm(shmobj, __alignof__(struct lttng_ust_lib_ring_buffer));
/*
* Only flush buffers periodically if readers are active.
*/
- if (uatomic_read(&buf->active_readers) || uatomic_read(&buf->active_shadow_readers))
+ if (uatomic_read(&buf->active_readers))
lib_ring_buffer_switch_slow(buf, SWITCH_ACTIVE, handle);
//TODO timers
CHAN_WARN_ON(chan, !buf->backend.allocated);
- if (uatomic_read(&buf->active_readers) || uatomic_read(&buf->active_shadow_readers))
+ if (uatomic_read(&buf->active_readers))
&& lib_ring_buffer_poll_deliver(config, buf, chan)) {
//TODO
//wake_up_interruptible(&buf->read_wait);
//channel_backend_unregister_notifiers(&chan->backend);
}
-static void channel_free(struct channel *chan, struct lttng_ust_shm_handle *handle,
- int shadow)
+static void channel_free(struct channel *chan, struct lttng_ust_shm_handle *handle)
{
- if (!shadow)
- channel_backend_free(&chan->backend, handle);
+ channel_backend_free(&chan->backend, handle);
/* chan is freed by shm teardown */
shm_object_table_destroy(handle->table);
free(handle);
void *priv_data_init,
void *buf_addr, size_t subbuf_size,
size_t num_subbuf, unsigned int switch_timer_interval,
- unsigned int read_timer_interval,
- int **shm_fd, int **wait_fd, uint64_t **memory_map_size)
+ unsigned int read_timer_interval)
{
int ret, cpu;
size_t shmsize, chansize;
struct channel *chan;
struct lttng_ust_shm_handle *handle;
struct shm_object *shmobj;
- struct shm_ref *ref;
+ unsigned int nr_streams;
+
+ if (config->alloc == RING_BUFFER_ALLOC_PER_CPU)
+ nr_streams = num_possible_cpus();
+ else
+ nr_streams = 1;
if (lib_ring_buffer_check_config(config, switch_timer_interval,
read_timer_interval))
/* Calculate the shm allocation layout */
shmsize = sizeof(struct channel);
shmsize += offset_align(shmsize, __alignof__(struct lttng_ust_lib_ring_buffer_shmp));
- if (config->alloc == RING_BUFFER_ALLOC_PER_CPU)
- shmsize += sizeof(struct lttng_ust_lib_ring_buffer_shmp) * num_possible_cpus();
- else
- shmsize += sizeof(struct lttng_ust_lib_ring_buffer_shmp);
+ shmsize += sizeof(struct lttng_ust_lib_ring_buffer_shmp) * nr_streams;
chansize = shmsize;
- shmsize += offset_align(shmsize, priv_data_align);
+ if (priv_data_align)
+ shmsize += offset_align(shmsize, priv_data_align);
shmsize += priv_data_size;
- shmobj = shm_object_table_append(handle->table, shmsize);
+ /* Allocate normal memory for channel (not shared) */
+ shmobj = shm_object_table_alloc(handle->table, shmsize, SHM_OBJECT_MEM);
if (!shmobj)
goto error_append;
/* struct channel is at object 0, offset 0 (hardcoded) */
chan = shmp(handle, handle->chan);
if (!chan)
goto error_append;
+ chan->nr_streams = nr_streams;
/* space for private data */
if (priv_data_size) {
memcpy(*priv_data, priv_data_init, priv_data_size);
} else {
chan->priv_data_offset = -1;
- *priv_data = NULL;
+ if (priv_data)
+ *priv_data = NULL;
}
ret = channel_backend_init(&chan->backend, name, config,
lib_ring_buffer_start_switch_timer(buf, handle);
lib_ring_buffer_start_read_timer(buf, handle);
}
- ref = &handle->chan._ref;
- shm_get_object_data(handle, ref, shm_fd, wait_fd, memory_map_size);
return handle;
error_backend_init:
return NULL;
}
-struct lttng_ust_shm_handle *channel_handle_create(int shm_fd, int wait_fd,
+struct lttng_ust_shm_handle *channel_handle_create(void *data,
uint64_t memory_map_size)
{
struct lttng_ust_shm_handle *handle;
if (!handle->table)
goto error_table_alloc;
/* Add channel object */
- object = shm_object_table_append_shadow(handle->table,
- shm_fd, wait_fd, memory_map_size);
+ object = shm_object_table_append_mem(handle->table, data,
+ memory_map_size);
if (!object)
goto error_table_object;
/* struct channel is at object 0, offset 0 (hardcoded) */
}
int channel_handle_add_stream(struct lttng_ust_shm_handle *handle,
- int shm_fd, int wait_fd, uint64_t memory_map_size)
+ int shm_fd, int wakeup_fd, uint32_t stream_nr,
+ uint64_t memory_map_size)
{
struct shm_object *object;
/* Add stream object */
- object = shm_object_table_append_shadow(handle->table,
- shm_fd, wait_fd, memory_map_size);
+ object = shm_object_table_append_shm(handle->table,
+ shm_fd, wakeup_fd, stream_nr,
+ memory_map_size);
if (!object)
- return -1;
+ return -EINVAL;
return 0;
}
+unsigned int channel_handle_get_nr_streams(struct lttng_ust_shm_handle *handle)
+{
+ assert(handle->table);
+ return handle->table->allocated_len - 1;
+}
+
static
-void channel_release(struct channel *chan, struct lttng_ust_shm_handle *handle,
- int shadow)
+void channel_release(struct channel *chan, struct lttng_ust_shm_handle *handle)
{
- channel_free(chan, handle, shadow);
+ channel_free(chan, handle);
}
/**
* They should release their handle at that point.
*/
void channel_destroy(struct channel *chan, struct lttng_ust_shm_handle *handle,
- int shadow)
+ int consumer)
{
- if (shadow) {
- channel_release(chan, handle, shadow);
- return;
+ if (consumer) {
+ /*
+ * Note: the consumer takes care of finalizing and
+ * switching the buffers.
+ */
+ channel_unregister_notifiers(chan, handle);
}
- channel_unregister_notifiers(chan, handle);
-
- /*
- * Note: the consumer takes care of finalizing and switching the
- * buffers.
- */
-
/*
* sessiond/consumer are keeping a reference on the shm file
* descriptor directly. No need to refcount.
*/
- channel_release(chan, handle, shadow);
+ channel_release(chan, handle);
return;
}
const struct lttng_ust_lib_ring_buffer_config *config,
struct channel *chan, int cpu,
struct lttng_ust_shm_handle *handle,
- int **shm_fd, int **wait_fd,
- uint64_t **memory_map_size)
+ int *shm_fd, int *wait_fd,
+ int *wakeup_fd,
+ uint64_t *memory_map_size)
{
struct shm_ref *ref;
if (config->alloc == RING_BUFFER_ALLOC_GLOBAL) {
- ref = &chan->backend.buf[0].shmp._ref;
- shm_get_object_data(handle, ref, shm_fd, wait_fd,
- memory_map_size);
- return shmp(handle, chan->backend.buf[0].shmp);
+ cpu = 0;
} else {
if (cpu >= num_possible_cpus())
return NULL;
- ref = &chan->backend.buf[cpu].shmp._ref;
- shm_get_object_data(handle, ref, shm_fd, wait_fd,
- memory_map_size);
- return shmp(handle, chan->backend.buf[cpu].shmp);
}
+ ref = &chan->backend.buf[cpu].shmp._ref;
+ *shm_fd = shm_get_shm_fd(handle, ref);
+ *wait_fd = shm_get_wait_fd(handle, ref);
+ *wakeup_fd = shm_get_wakeup_fd(handle, ref);
+ if (shm_get_shm_size(handle, ref, memory_map_size))
+ return NULL;
+ return shmp(handle, chan->backend.buf[cpu].shmp);
}
-int lib_ring_buffer_open_read(struct lttng_ust_lib_ring_buffer *buf,
- struct lttng_ust_shm_handle *handle,
- int shadow)
+int ring_buffer_close_wait_fd(const struct lttng_ust_lib_ring_buffer_config *config,
+ struct channel *chan,
+ struct lttng_ust_shm_handle *handle,
+ int cpu)
{
- if (shadow) {
- if (uatomic_cmpxchg(&buf->active_shadow_readers, 0, 1) != 0)
- return -EBUSY;
- cmm_smp_mb();
- return 0;
+ struct shm_ref *ref;
+
+ if (config->alloc == RING_BUFFER_ALLOC_GLOBAL) {
+ cpu = 0;
+ } else {
+ if (cpu >= num_possible_cpus())
+ return -EINVAL;
}
+ ref = &chan->backend.buf[cpu].shmp._ref;
+ return shm_close_wait_fd(handle, ref);
+}
+
+int ring_buffer_close_wakeup_fd(const struct lttng_ust_lib_ring_buffer_config *config,
+ struct channel *chan,
+ struct lttng_ust_shm_handle *handle,
+ int cpu)
+{
+ struct shm_ref *ref;
+
+ if (config->alloc == RING_BUFFER_ALLOC_GLOBAL) {
+ cpu = 0;
+ } else {
+ if (cpu >= num_possible_cpus())
+ return -EINVAL;
+ }
+ ref = &chan->backend.buf[cpu].shmp._ref;
+ return shm_close_wakeup_fd(handle, ref);
+}
+
+int lib_ring_buffer_open_read(struct lttng_ust_lib_ring_buffer *buf,
+ struct lttng_ust_shm_handle *handle)
+{
if (uatomic_cmpxchg(&buf->active_readers, 0, 1) != 0)
return -EBUSY;
cmm_smp_mb();
}
void lib_ring_buffer_release_read(struct lttng_ust_lib_ring_buffer *buf,
- struct lttng_ust_shm_handle *handle,
- int shadow)
+ struct lttng_ust_shm_handle *handle)
{
struct channel *chan = shmp(handle, buf->backend.chan);
- if (shadow) {
- CHAN_WARN_ON(chan, uatomic_read(&buf->active_shadow_readers) != 1);
- cmm_smp_mb();
- uatomic_dec(&buf->active_shadow_readers);
- return;
- }
CHAN_WARN_ON(chan, uatomic_read(&buf->active_readers) != 1);
cmm_smp_mb();
uatomic_dec(&buf->active_readers);
struct channel *chan = shmp(handle, bufb->chan);
unsigned long consumed;
- CHAN_WARN_ON(chan, uatomic_read(&buf->active_readers) != 1
- && uatomic_read(&buf->active_shadow_readers) != 1);
+ CHAN_WARN_ON(chan, uatomic_read(&buf->active_readers) != 1);
/*
* Only push the consumed value forward.
const struct lttng_ust_lib_ring_buffer_config *config = &chan->backend.config;
unsigned long read_sb_bindex, consumed_idx, consumed;
- CHAN_WARN_ON(chan, uatomic_read(&buf->active_readers) != 1
- && uatomic_read(&buf->active_shadow_readers) != 1);
+ CHAN_WARN_ON(chan, uatomic_read(&buf->active_readers) != 1);
if (!buf->get_subbuf) {
/*
return table;
}
-struct shm_object *shm_object_table_append(struct shm_object_table *table,
+static
+struct shm_object *_shm_object_table_alloc_shm(struct shm_object_table *table,
size_t memory_map_size)
{
int shmfd, waitfd[2], ret, i, sigblocked = 0;
PERROR("mmap");
goto error_mmap;
}
+ obj->type = SHM_OBJECT_SHM;
obj->memory_map = memory_map;
obj->memory_map_size = memory_map_size;
obj->allocated_len = 0;
}
error_pipe:
return NULL;
-
}
-struct shm_object *shm_object_table_append_shadow(struct shm_object_table *table,
- int shm_fd, int wait_fd, size_t memory_map_size)
+static
+struct shm_object *_shm_object_table_alloc_mem(struct shm_object_table *table,
+ size_t memory_map_size)
+{
+ struct shm_object *obj;
+ void *memory_map;
+
+ if (table->allocated_len >= table->size)
+ return NULL;
+ obj = &table->objects[table->allocated_len];
+
+ memory_map = zmalloc(memory_map_size);
+ if (!memory_map)
+ goto alloc_error;
+
+ obj->wait_fd[0] = -1;
+ obj->wait_fd[1] = -1;
+ obj->shm_fd = -1;
+
+ obj->type = SHM_OBJECT_MEM;
+ obj->memory_map = memory_map;
+ obj->memory_map_size = memory_map_size;
+ obj->allocated_len = 0;
+ obj->index = table->allocated_len++;
+
+ return obj;
+
+alloc_error:
+ return NULL;
+}
+
+struct shm_object *shm_object_table_alloc(struct shm_object_table *table,
+ size_t memory_map_size,
+ enum shm_object_type type)
+{
+ switch (type) {
+ case SHM_OBJECT_SHM:
+ return _shm_object_table_alloc_shm(table, memory_map_size);
+ case SHM_OBJECT_MEM:
+ return _shm_object_table_alloc_mem(table, memory_map_size);
+ default:
+ assert(0);
+ }
+ return NULL;
+}
+
+struct shm_object *shm_object_table_append_shm(struct shm_object_table *table,
+ int shm_fd, int wakeup_fd, uint32_t stream_nr,
+ size_t memory_map_size)
{
struct shm_object *obj;
char *memory_map;
+ int ret;
if (table->allocated_len >= table->size)
return NULL;
+ /* streams _must_ be received in sequential order, else fail. */
+ if (stream_nr + 1 != table->allocated_len)
+ return NULL;
+
obj = &table->objects[table->allocated_len];
- /* wait_fd: set read end of the pipe. */
- obj->wait_fd[0] = wait_fd;
- obj->wait_fd[1] = -1; /* write end is unset. */
+ /* wait_fd: set write end of the pipe. */
+ obj->wait_fd[0] = -1; /* read end is unset */
+ obj->wait_fd[1] = wakeup_fd;
obj->shm_fd = shm_fd;
+ ret = fcntl(obj->wait_fd[1], F_SETFD, FD_CLOEXEC);
+ if (ret < 0) {
+ PERROR("fcntl");
+ goto error_fcntl;
+ }
+ /* The write end of the pipe needs to be non-blocking */
+ ret = fcntl(obj->wait_fd[1], F_SETFL, O_NONBLOCK);
+ if (ret < 0) {
+ PERROR("fcntl");
+ goto error_fcntl;
+ }
+
/* memory_map: mmap */
memory_map = mmap(NULL, memory_map_size, PROT_READ | PROT_WRITE,
MAP_SHARED, shm_fd, 0);
PERROR("mmap");
goto error_mmap;
}
+ obj->type = SHM_OBJECT_SHM;
obj->memory_map = memory_map;
obj->memory_map_size = memory_map_size;
obj->allocated_len = memory_map_size;
return obj;
+error_fcntl:
error_mmap:
return NULL;
}
+/*
+ * Passing ownership of mem to object.
+ */
+struct shm_object *shm_object_table_append_mem(struct shm_object_table *table,
+ void *mem, size_t memory_map_size)
+{
+ struct shm_object *obj;
+
+ if (table->allocated_len >= table->size)
+ return NULL;
+ obj = &table->objects[table->allocated_len];
+
+ obj->wait_fd[0] = -1;
+ obj->wait_fd[1] = -1;
+ obj->shm_fd = -1;
+
+ obj->type = SHM_OBJECT_MEM;
+ obj->memory_map = mem;
+ obj->memory_map_size = memory_map_size;
+ obj->allocated_len = memory_map_size;
+ obj->index = table->allocated_len++;
+
+ return obj;
+}
+
static
void shmp_object_destroy(struct shm_object *obj)
{
- int ret, i;
+ switch (obj->type) {
+ case SHM_OBJECT_SHM:
+ {
+ int ret, i;
- if (!obj->is_shadow) {
ret = munmap(obj->memory_map, obj->memory_map_size);
if (ret) {
PERROR("umnmap");
assert(0);
}
- }
- if (obj->shm_fd >= 0) {
ret = close(obj->shm_fd);
if (ret) {
PERROR("close");
assert(0);
}
- }
- for (i = 0; i < 2; i++) {
- if (obj->wait_fd[i] < 0)
- continue;
- ret = close(obj->wait_fd[i]);
- if (ret) {
- PERROR("close");
- assert(0);
+ for (i = 0; i < 2; i++) {
+ if (obj->wait_fd[i] < 0)
+ continue;
+ ret = close(obj->wait_fd[i]);
+ if (ret) {
+ PERROR("close");
+ assert(0);
+ }
}
+ break;
+ }
+ case SHM_OBJECT_MEM:
+ free(obj->memory_map);
+ break;
+ default:
+ assert(0);
}
}
#include <urcu/compiler.h>
#include "shm_types.h"
+/* channel_handle_create - for UST. */
+extern
+struct lttng_ust_shm_handle *channel_handle_create(void *data,
+ uint64_t memory_map_size);
+/* channel_handle_add_stream - for UST. */
+extern
+int channel_handle_add_stream(struct lttng_ust_shm_handle *handle,
+ int shm_fd, int wakeup_fd, uint32_t stream_nr,
+ uint64_t memory_map_size);
+unsigned int channel_handle_get_nr_streams(struct lttng_ust_shm_handle *handle);
+extern
+void channel_destroy(struct channel *chan, struct lttng_ust_shm_handle *handle,
+ int consumer);
+
/*
* Pointer dereferencing. We don't trust the shm_ref, so we validate
* both the index and offset with known boundaries.
#define set_shmp(ref, src) _set_shmp(&(ref)._ref, src)
struct shm_object_table *shm_object_table_create(size_t max_nb_obj);
-struct shm_object *shm_object_table_append_shadow(struct shm_object_table *table,
- int shm_fd, int wait_fd, size_t memory_map_size);
+struct shm_object *shm_object_table_alloc(struct shm_object_table *table,
+ size_t memory_map_size,
+ enum shm_object_type type);
+struct shm_object *shm_object_table_append_shm(struct shm_object_table *table,
+ int shm_fd, int wakeup_fd, uint32_t stream_nr,
+ size_t memory_map_size);
+/* mem ownership is passed to shm_object_table_append_mem(). */
+struct shm_object *shm_object_table_append_mem(struct shm_object_table *table,
+ void *mem, size_t memory_map_size);
void shm_object_table_destroy(struct shm_object_table *table);
-struct shm_object *shm_object_table_append(struct shm_object_table *table,
- size_t memory_map_size);
/*
* zalloc_shm - allocate memory within a shm object.
struct shm_ref zalloc_shm(struct shm_object *obj, size_t len);
void align_shm(struct shm_object *obj, size_t align);
+static inline
+int shm_get_wait_fd(struct lttng_ust_shm_handle *handle, struct shm_ref *ref)
+{
+ struct shm_object_table *table = handle->table;
+ struct shm_object *obj;
+ size_t index;
+
+ index = (size_t) ref->index;
+ if (caa_unlikely(index >= table->allocated_len))
+ return -EPERM;
+ obj = &table->objects[index];
+ return obj->wait_fd[0];
+}
+
static inline
int shm_get_wakeup_fd(struct lttng_ust_shm_handle *handle, struct shm_ref *ref)
{
return -EPERM;
obj = &table->objects[index];
return obj->wait_fd[1];
+}
+
+static inline
+int shm_close_wait_fd(struct lttng_ust_shm_handle *handle,
+ struct shm_ref *ref)
+{
+ struct shm_object_table *table = handle->table;
+ struct shm_object *obj;
+ size_t index;
+ int ret;
+ index = (size_t) ref->index;
+ if (caa_unlikely(index >= table->allocated_len))
+ return -EPERM;
+ obj = &table->objects[index];
+ if (obj->wait_fd[0] < 0)
+ return -ENOENT;
+ ret = close(obj->wait_fd[0]);
+ if (ret) {
+ ret = -errno;
+ return ret;
+ }
+ obj->wait_fd[0] = -1;
+ return 0;
}
static inline
-int shm_get_wait_fd(struct lttng_ust_shm_handle *handle, struct shm_ref *ref)
+int shm_close_wakeup_fd(struct lttng_ust_shm_handle *handle,
+ struct shm_ref *ref)
{
struct shm_object_table *table = handle->table;
struct shm_object *obj;
size_t index;
+ int ret;
index = (size_t) ref->index;
if (caa_unlikely(index >= table->allocated_len))
return -EPERM;
obj = &table->objects[index];
- return obj->wait_fd[0];
+ if (obj->wait_fd[1] < 0)
+ return -ENOENT;
+ ret = close(obj->wait_fd[1]);
+ if (ret) {
+ ret = -errno;
+ return ret;
+ }
+ obj->wait_fd[1] = -1;
+ return 0;
}
static inline
-int shm_get_object_data(struct lttng_ust_shm_handle *handle, struct shm_ref *ref,
- int **shm_fd, int **wait_fd, uint64_t **memory_map_size)
+int shm_get_shm_fd(struct lttng_ust_shm_handle *handle, struct shm_ref *ref)
+{
+ struct shm_object_table *table = handle->table;
+ struct shm_object *obj;
+ size_t index;
+
+ index = (size_t) ref->index;
+ if (caa_unlikely(index >= table->allocated_len))
+ return -EPERM;
+ obj = &table->objects[index];
+ return obj->shm_fd;
+}
+
+
+static inline
+int shm_get_shm_size(struct lttng_ust_shm_handle *handle, struct shm_ref *ref,
+ uint64_t *size)
{
struct shm_object_table *table = handle->table;
struct shm_object *obj;
if (caa_unlikely(index >= table->allocated_len))
return -EPERM;
obj = &table->objects[index];
- *shm_fd = &obj->shm_fd;
- *wait_fd = &obj->wait_fd[0];
- *memory_map_size = &obj->allocated_len;
+ *size = obj->memory_map_size;
return 0;
}
struct channel;
+enum shm_object_type {
+ SHM_OBJECT_SHM,
+ SHM_OBJECT_MEM,
+};
+
struct shm_object {
+ enum shm_object_type type;
size_t index; /* within the object table */
int shm_fd; /* shm fd */
int wait_fd[2]; /* fd for wait/wakeup */
char *memory_map;
- int is_shadow;
size_t memory_map_size;
uint64_t allocated_len;
};
struct lttng_ust_shm_handle {
struct shm_object_table *table;
DECLARE_SHMP(struct channel, chan);
- /*
- * In the consumer, chan points to a shadow copy, validated upon
- * reception. The chan object is overridden in the consumer to
- * point to this shadow copy.
- */
- struct channel *shadow_chan;
};
#endif /* _LIBRINGBUFFER_SHM_TYPES_H */
-SUBDIRS = . hello hello-static-lib fork ust-basic-tracing ust-multi-test \
- demo daemon
+SUBDIRS = . hello hello-static-lib fork demo daemon
+#ust-basic-tracing ust-multi-test
#SUBDIRS = . hello2 basic basic_long simple_include snprintf test-nevents test-libustinstr-malloc dlopen same_line_marker trace_event register_test tracepoint libustctl_function_tests exit-fast
if CXX_WORKS