union {
struct lttng_ust_tracer_version version;
struct lttng_ust_channel channel;
+ struct lttng_ust_stream stream;
struct lttng_ust_event event;
struct lttng_ust_context context;
} u;
uint32_t ret_code; /* enum enum lttcomm_return_code */
uint32_t ret_val; /* return value */
union {
+ struct {
+ uint64_t memory_map_size;
+ } stream;
} u;
};
unsigned int read_timer_interval);
void (*channel_destroy)(struct ltt_channel *ltt_chan);
struct lib_ring_buffer *(*buffer_read_open)(struct channel *chan,
- struct shm_handle *handle);
+ struct shm_handle *handle,
+ int *shm_fd, int *wait_fd,
+ uint64_t *memory_map_size);
void (*buffer_read_close)(struct lib_ring_buffer *buf,
struct shm_handle *handle);
int (*event_reserve)(struct lib_ring_buffer_ctx *ctx,
enum lttng_ust_output output; /* output mode */
};
+/*
+ * This structure is only used internally within UST. It is not per-se
+ * part of the communication between sessiond and UST.
+ */
+struct lttng_ust_stream {
+ int shm_fd;
+ int wait_fd;
+ uint64_t memory_map_size;
+};
+
struct lttng_ust_event {
char name[LTTNG_UST_SYM_NAME_LEN]; /* event name */
enum lttng_ust_instrumentation instrumentation;
extern struct lib_ring_buffer *channel_get_ring_buffer(
const struct lib_ring_buffer_config *config,
struct channel *chan, int cpu,
- struct shm_handle *handle);
+ struct shm_handle *handle,
+ int *shm_fd, int *wait_fd,
+ uint64_t *memory_map_size);
extern int lib_ring_buffer_open_read(struct lib_ring_buffer *buf,
struct shm_handle *handle);
extern void lib_ring_buffer_release_read(struct lib_ring_buffer *buf,
struct channel_backend *chanb = &shmp(handle, bufb->chan)->backend;
const struct lib_ring_buffer_config *config = chanb->config;
unsigned long sb_bindex, id;
- void *ret;
offset &= chanb->buf_size - 1;
sbidx = offset >> chanb->subbuf_size_order;
struct lib_ring_buffer *channel_get_ring_buffer(
const struct lib_ring_buffer_config *config,
struct channel *chan, int cpu,
- struct shm_handle *handle)
+ struct shm_handle *handle,
+ int *shm_fd, int *wait_fd,
+ uint64_t *memory_map_size)
{
- if (config->alloc == RING_BUFFER_ALLOC_GLOBAL)
+ 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);
- else
+ } else {
+ 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);
+ }
}
int lib_ring_buffer_open_read(struct lib_ring_buffer *buf,
return obj->wait_fd[0];
}
+static inline
+int shm_get_object_data(struct shm_handle *handle, struct shm_ref *ref,
+ int *shm_fd, int *wait_fd, uint64_t *memory_map_size)
+{
+ struct shm_object_table *table = handle->table;
+ struct shm_object *obj;
+ size_t index;
+
+ index = (size_t) ref->index;
+ if (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->memory_map_size;
+ return 0;
+}
+
#endif /* _LIBRINGBUFFER_SHM_H */
static
struct lib_ring_buffer *ltt_buffer_read_open(struct channel *chan,
- struct shm_handle *handle)
+ struct shm_handle *handle,
+ int *shm_fd, int *wait_fd,
+ uint64_t *memory_map_size)
{
struct lib_ring_buffer *buf;
int cpu;
for_each_channel_cpu(cpu, chan) {
- buf = channel_get_ring_buffer(&client_config, chan, cpu, handle);
+ 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))
return buf;
}
static
struct lib_ring_buffer *ltt_buffer_read_open(struct channel *chan,
- struct shm_handle *handle)
+ struct shm_handle *handle,
+ int *shm_fd, int *wait_fd,
+ uint64_t *memory_map_size)
{
struct lib_ring_buffer *buf;
- buf = channel_get_ring_buffer(&client_config, chan, 0, handle);
+ 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))
return buf;
return NULL;
static const struct objd_ops lttng_channel_ops;
static const struct objd_ops lttng_metadata_ops;
static const struct objd_ops lttng_event_ops;
+static const struct objd_ops lib_ring_buffer_objd_ops;
enum channel_type {
PER_CPU_CHANNEL,
.cmd = lttng_session_cmd,
};
-#if 0
+struct stream_priv_data {
+ struct lib_ring_buffer *buf;
+ struct ltt_channel *ltt_chan;
+};
+
static
-int lttng_abi_open_stream(int channel_objd)
+int lttng_abi_open_stream(int channel_objd, struct lttng_ust_stream *info)
{
struct ltt_channel *channel = objd_private(channel_objd);
struct lib_ring_buffer *buf;
+ struct stream_priv_data *priv;
int stream_objd, ret;
- buf = channel->ops->buffer_read_open(channel->chan);
+ buf = channel->ops->buffer_read_open(channel->chan, channel->handle,
+ &info->shm_fd, &info->wait_fd, &info->memory_map_size);
if (!buf)
return -ENOENT;
- stream_objd = objd_alloc(buf, &lib_ring_buffer_objd_ops);
+ priv = zmalloc(sizeof(*priv));
+ if (!priv) {
+ ret = -ENOMEM;
+ goto alloc_error;
+ }
+ priv->buf = buf;
+ priv->ltt_chan = channel;
+ stream_objd = objd_alloc(priv, &lib_ring_buffer_objd_ops);
if (stream_objd < 0) {
ret = stream_objd;
goto objd_error;
}
- /*
- * The stream holds a reference to the channel within the generic ring
- * buffer library, so no need to hold a refcount on the channel and
- * session files here.
- */
+ /* Hold a reference on the channel object descriptor */
+ objd_ref(channel_objd);
return stream_objd;
objd_error:
- channel->ops->buffer_read_close(buf);
+ free(priv);
+alloc_error:
+ channel->ops->buffer_read_close(buf, channel->handle);
return ret;
}
-#endif //0
static
int lttng_abi_create_event(int channel_objd,
switch (cmd) {
case LTTNG_UST_STREAM:
- return -ENOSYS; //TODO
- //return lttng_abi_open_stream(objd);
+ {
+ struct lttng_ust_stream *stream;
+
+ stream = (struct lttng_ust_stream *) arg;
+ /* stream used as output */
+ return lttng_abi_open_stream(objd, stream);
+ }
case LTTNG_UST_EVENT:
return lttng_abi_create_event(objd, (struct lttng_ust_event *) arg);
case LTTNG_UST_CONTEXT:
{
switch (cmd) {
case LTTNG_UST_STREAM:
- return -ENOSYS; //TODO
- //return lttng_abi_open_stream(objd);
+ {
+ struct lttng_ust_stream *stream;
+
+ stream = (struct lttng_ust_stream *) arg;
+ /* stream used as output */
+ return lttng_abi_open_stream(objd, stream);
+ }
default:
return -EINVAL;
}
.cmd = lttng_metadata_cmd,
};
+/**
+ * lttng_rb_cmd - lttng ring buffer control through object descriptors
+ *
+ * @objd: the object descriptor
+ * @cmd: the command
+ * @arg: command arg
+ *
+ * This object descriptor implements lttng commands:
+ * (None for now. Access is done directly though shm.)
+ * TODO: Add buffer flush.
+ */
+static
+long lttng_rb_cmd(int objd, unsigned int cmd, unsigned long arg)
+{
+ struct stream_priv_data *priv = objd_private(objd);
+
+ switch (cmd) {
+ default:
+ return -EINVAL;
+ }
+}
+
+static
+int lttng_rb_release(int objd)
+{
+ struct stream_priv_data *priv = objd_private(objd);
+ struct lib_ring_buffer *buf;
+ struct ltt_channel *channel;
+
+ if (priv) {
+ buf = priv->buf;
+ channel = priv->ltt_chan;
+ free(priv);
+
+ return objd_unref(channel->objd);
+ }
+ return 0;
+}
+
+static const struct objd_ops lib_ring_buffer_objd_ops = {
+ .release = lttng_rb_release,
+ .cmd = lttng_rb_cmd,
+};
+
/**
* lttng_event_cmd - lttng control through object descriptors
*
} else {
lur.ret_code = LTTCOMM_SESSION_FAIL;
}
+ if (lum->cmd == LTTNG_UST_STREAM) {
+ /*
+ * Special-case reply to send stream info.
+ * Use lum.u output.
+ */
+ lur.u.stream.memory_map_size = lum->u.stream.memory_map_size;
+ }
ret = send_reply(sock, &lur);
+ if (lum->cmd == LTTNG_UST_STREAM && ret >= 0) {
+ /* we also need to send the file descriptors. */
+ ret = lttcomm_send_fds_unix_sock(sock,
+ &lum->u.stream.shm_fd, &lum->u.stream.shm_fd,
+ 1, sizeof(int));
+ if (ret < 0) {
+ perror("send shm_fd");
+ goto error;
+ }
+ ret = lttcomm_send_fds_unix_sock(sock,
+ &lum->u.stream.wait_fd, &lum->u.stream.wait_fd,
+ 1, sizeof(int));
+ if (ret < 0) {
+ perror("send wait_fd");
+ goto error;
+ }
+ }
+error:
ust_unlock();
return ret;
}