From 616d3093e1c34557aca7e9f6149338f43cf91886 Mon Sep 17 00:00:00 2001 From: Christian Babeux Date: Wed, 28 Nov 2012 21:11:27 -0500 Subject: [PATCH] Cygwin: Introduce new LTTNG_UST_STREAM_PIPE command to open wakeup pipe 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 --- include/lttng/ust-abi.h | 2 +- include/lttng/ust-ctl.h | 1 + include/lttng/ust-events.h | 1 + liblttng-ust-ctl/ustctl.c | 30 +++++++++++++++++++ liblttng-ust/ltt-ring-buffer-client.h | 29 ++++++++++++++++++ .../ltt-ring-buffer-metadata-client.h | 29 ++++++++++++++++++ liblttng-ust/lttng-ust-abi.c | 4 +++ libringbuffer/shm.h | 30 +++++++++++++++++++ 8 files changed, 125 insertions(+), 1 deletion(-) diff --git a/include/lttng/ust-abi.h b/include/lttng/ust-abi.h index 86edba90..cc9fa76a 100644 --- a/include/lttng/ust-abi.h +++ b/include/lttng/ust-abi.h @@ -179,7 +179,7 @@ struct lttng_ust_calibrate { #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) diff --git a/include/lttng/ust-ctl.h b/include/lttng/ust-ctl.h index 10602ee7..8917d0e0 100644 --- a/include/lttng/ust-ctl.h +++ b/include/lttng/ust-ctl.h @@ -26,6 +26,7 @@ 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_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); diff --git a/include/lttng/ust-events.h b/include/lttng/ust-events.h index b892fbf8..1044bb0a 100644 --- a/include/lttng/ust-events.h +++ b/include/lttng/ust-events.h @@ -332,6 +332,7 @@ struct ltt_channel_ops { 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); }; struct ltt_channel { diff --git a/liblttng-ust-ctl/ustctl.c b/liblttng-ust-ctl/ustctl.c index 5069fbb1..c9e930d0 100644 --- a/liblttng-ust-ctl/ustctl.c +++ b/liblttng-ust-ctl/ustctl.c @@ -237,6 +237,36 @@ error: return -EINVAL; } +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) diff --git a/liblttng-ust/ltt-ring-buffer-client.h b/liblttng-ust/ltt-ring-buffer-client.h index b896169e..0779348a 100644 --- a/liblttng-ust/ltt-ring-buffer-client.h +++ b/liblttng-ust/ltt-ring-buffer-client.h @@ -437,6 +437,34 @@ struct ltt_channel *_channel_create(const char *name, return ltt_chan; } +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) { @@ -571,6 +599,7 @@ static struct ltt_transport ltt_relay_transport = { .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, diff --git a/liblttng-ust/ltt-ring-buffer-metadata-client.h b/liblttng-ust/ltt-ring-buffer-metadata-client.h index 0e9b7fa3..a8ba282d 100644 --- a/liblttng-ust/ltt-ring-buffer-metadata-client.h +++ b/liblttng-ust/ltt-ring-buffer-metadata-client.h @@ -207,6 +207,34 @@ struct ltt_channel *_channel_create(const char *name, return ltt_chan; } +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) { @@ -321,6 +349,7 @@ static struct ltt_transport ltt_relay_transport = { .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, diff --git a/liblttng-ust/lttng-ust-abi.c b/liblttng-ust/lttng-ust-abi.c index a3edd3ea..c0e089d0 100644 --- a/liblttng-ust/lttng-ust-abi.c +++ b/liblttng-ust/lttng-ust-abi.c @@ -783,6 +783,8 @@ long lttng_channel_cmd(int objd, unsigned int cmd, unsigned long arg, 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; } @@ -819,6 +821,8 @@ long lttng_metadata_cmd(int objd, unsigned int cmd, unsigned long arg, } 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; } diff --git a/libringbuffer/shm.h b/libringbuffer/shm.h index a745d345..3a61a39d 100644 --- a/libringbuffer/shm.h +++ b/libringbuffer/shm.h @@ -25,6 +25,7 @@ #include #include #include "shm_types.h" +#include /* * Pointer dereferencing. We don't trust the shm_ref, so we validate @@ -99,8 +100,37 @@ int shm_get_wakeup_fd(struct lttng_ust_shm_handle *handle, struct shm_ref *ref) if (caa_unlikely(index >= table->allocated_len)) return -EPERM; obj = &table->objects[index]; + return obj->wait_fd[1]; +} + +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; } static inline -- 2.34.1