summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
42100b8)
Normally, the userspace tracer open the wakeup pipe, and the resulting
fd is passed to the consumer via the session daemon. Since we can't pass
fds via UNIX socket, the pipe need to be opened separately in the tracer
and in the consumer. The only way to open the write side of a named pipe
*before* the read side without blocking is to open it in read/write mode.
This is supported on Linux, but POSIX leave this behavior undefined [1].
The Cygwin named pipe implementation doesn't seem to allow multiple
readers/writers on a named pipe. Opening a pipe in RW mode in the tracer
and then opening the read side in the consumer won't work because the
consumer will get a "Device or ressource busy" error. Thus arise the need
to open the named pipe read side *before* the write side.
In order to accomplish this task, a new command must be introduced to signal
to the tracer that a specific named pipe should be opened in write mode.
Proper care must be taken to issue this command *after* the named pipe paths
have been sent to the consumer or else the sessiond or tracer will block
indefinitely.
[1] - man 7 fifo
#define LTTNG_UST_STREAM _UST_CMD(0x60)
#define LTTNG_UST_EVENT \
_UST_CMDW(0x61, struct lttng_ust_event)
#define LTTNG_UST_STREAM _UST_CMD(0x60)
#define LTTNG_UST_EVENT \
_UST_CMDW(0x61, struct lttng_ust_event)
+#define LTTNG_UST_STREAM_PIPE _UST_CMD(0x62)
/* Event and Channel FD commands */
#define LTTNG_UST_CONTEXT \
_UST_CMDW(0x70, struct lttng_ust_context)
/* Event and Channel FD commands */
#define LTTNG_UST_CONTEXT \
_UST_CMDW(0x70, struct lttng_ust_context)
int ustctl_open_metadata(int sock, int session_handle,
struct lttng_ust_channel_attr *chops,
struct lttng_ust_object_data **metadata_data);
int ustctl_open_metadata(int sock, int session_handle,
struct lttng_ust_channel_attr *chops,
struct lttng_ust_object_data **metadata_data);
+int ustctl_open_wait_pipe(int sock, struct lttng_ust_object_data *channel_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_channel(int sock, int session_handle,
struct lttng_ust_channel_attr *chops,
struct lttng_ust_object_data **channel_data);
int (*is_finalized)(struct channel *chan);
int (*is_disabled)(struct channel *chan);
int (*flush_buffer)(struct channel *chan, struct lttng_ust_shm_handle *handle);
int (*is_finalized)(struct channel *chan);
int (*is_disabled)(struct channel *chan);
int (*flush_buffer)(struct channel *chan, struct lttng_ust_shm_handle *handle);
+ int (*channel_open_pipe)(struct channel *chan, struct lttng_ust_shm_handle *handle);
+int ustctl_open_wait_pipe(int sock,
+ struct lttng_ust_object_data *channel_data)
+{
+ struct ustcomm_ust_msg lum;
+ struct ustcomm_ust_reply lur;
+ int ret;
+
+ if (!channel_data)
+ return -EINVAL;
+
+ /* Create metadata channel */
+ memset(&lum, 0, sizeof(lum));
+ lum.handle = channel_data->handle;
+ lum.cmd = LTTNG_UST_STREAM_PIPE;
+ ret = ustcomm_send_app_cmd(sock, &lum, &lur);
+
+ if (ret) {
+ goto error;
+ }
+ if (lur.ret_code != USTCOMM_OK) {
+ ret = lur.ret_code;
+ goto error;
+ }
+
+ return 0;
+
+error:
+ return ret;
+}
+
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_channel(int sock, int session_handle,
struct lttng_ust_channel_attr *chops,
struct lttng_ust_object_data **_channel_data)
+static
+int ltt_channel_open_pipe(struct channel *chan,
+ struct lttng_ust_shm_handle *handle)
+{
+ struct shm_ref *ref;
+ int cpu = 0;
+
+ if (client_config.alloc == RING_BUFFER_ALLOC_GLOBAL) {
+ ref = &chan->backend.buf[0].shmp._ref;
+ return shm_open_wakeup_pipe(handle, ref);
+ } else {
+ if (cpu >= num_possible_cpus()) {
+ goto error;
+ }
+
+ for_each_possible_cpu(cpu) {
+ ref = &chan->backend.buf[cpu].shmp._ref;
+ if (shm_open_wakeup_pipe(handle, ref) < 0) {
+ goto error;
+ }
+ }
+ }
+
+ return 0;
+error:
+ return -1;
+}
+
static
void ltt_channel_destroy(struct ltt_channel *ltt_chan)
{
static
void ltt_channel_destroy(struct ltt_channel *ltt_chan)
{
.name = "relay-" RING_BUFFER_MODE_TEMPLATE_STRING "-mmap",
.ops = {
.channel_create = _channel_create,
.name = "relay-" RING_BUFFER_MODE_TEMPLATE_STRING "-mmap",
.ops = {
.channel_create = _channel_create,
+ .channel_open_pipe = ltt_channel_open_pipe,
.channel_destroy = ltt_channel_destroy,
.buffer_read_open = ltt_buffer_read_open,
.buffer_read_close = ltt_buffer_read_close,
.channel_destroy = ltt_channel_destroy,
.buffer_read_open = ltt_buffer_read_open,
.buffer_read_close = ltt_buffer_read_close,
+static
+int ltt_channel_open_pipe(struct channel *chan,
+ struct lttng_ust_shm_handle *handle)
+{
+ struct shm_ref *ref;
+ int cpu = 0;
+
+ if (client_config.alloc == RING_BUFFER_ALLOC_GLOBAL) {
+ ref = &chan->backend.buf[0].shmp._ref;
+ return shm_open_wakeup_pipe(handle, ref);
+ } else {
+ if (cpu >= num_possible_cpus()) {
+ goto error;
+ }
+
+ for_each_possible_cpu(cpu) {
+ ref = &chan->backend.buf[cpu].shmp._ref;
+ if (shm_open_wakeup_pipe(handle, ref) < 0) {
+ goto error;
+ }
+ }
+ }
+
+ return 0;
+error:
+ return -1;
+}
+
static
void ltt_channel_destroy(struct ltt_channel *ltt_chan)
{
static
void ltt_channel_destroy(struct ltt_channel *ltt_chan)
{
.name = "relay-" RING_BUFFER_MODE_TEMPLATE_STRING "-mmap",
.ops = {
.channel_create = _channel_create,
.name = "relay-" RING_BUFFER_MODE_TEMPLATE_STRING "-mmap",
.ops = {
.channel_create = _channel_create,
+ .channel_open_pipe = ltt_channel_open_pipe,
.channel_destroy = ltt_channel_destroy,
.buffer_read_open = ltt_buffer_read_open,
.buffer_read_close = ltt_buffer_read_close,
.channel_destroy = ltt_channel_destroy,
.buffer_read_open = ltt_buffer_read_open,
.buffer_read_close = ltt_buffer_read_close,
return ltt_channel_disable(channel);
case LTTNG_UST_FLUSH_BUFFER:
return channel->ops->flush_buffer(channel->chan, channel->handle);
return ltt_channel_disable(channel);
case LTTNG_UST_FLUSH_BUFFER:
return channel->ops->flush_buffer(channel->chan, channel->handle);
+ case LTTNG_UST_STREAM_PIPE:
+ return channel->ops->channel_open_pipe(channel->chan, channel->handle);
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}
case LTTNG_UST_FLUSH_BUFFER:
return channel->ops->flush_buffer(channel->chan, channel->handle);
}
case LTTNG_UST_FLUSH_BUFFER:
return channel->ops->flush_buffer(channel->chan, channel->handle);
+ case LTTNG_UST_STREAM_PIPE:
+ return channel->ops->channel_open_pipe(channel->chan, channel->handle);
default:
return -EINVAL;
}
default:
return -EINVAL;
}
#include <usterr-signal-safe.h>
#include <urcu/compiler.h>
#include "shm_types.h"
#include <usterr-signal-safe.h>
#include <urcu/compiler.h>
#include "shm_types.h"
/*
* Pointer dereferencing. We don't trust the shm_ref, so we validate
/*
* Pointer dereferencing. We don't trust the shm_ref, so we validate
if (caa_unlikely(index >= table->allocated_len))
return -EPERM;
obj = &table->objects[index];
if (caa_unlikely(index >= table->allocated_len))
return -EPERM;
obj = &table->objects[index];
+}
+
+static inline
+int shm_open_wakeup_pipe(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 fd, ret = -1;
+
+ index = (size_t) ref->index;
+ if (caa_unlikely(index >= table->allocated_len))
+ return -EPERM;
+
+ obj = &table->objects[index];
+ if (obj->wait_fd[1] < 0 && obj->wait_pipe_path != NULL) {
+ fd = open(obj->wait_pipe_path, O_WRONLY);
+ if (fd < 0) {
+ ret = -1;
+ } else {
+ /* FIXME: What if fcntl fail? */
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+ obj->wait_fd[1] = fd;
+ ret = 0;
+ }
+ }
+
+ return ret;