From bf5ff35ed0a3a7f60e92d654a5b97e73b94da852 Mon Sep 17 00:00:00 2001 From: Christian Babeux Date: Wed, 28 Nov 2012 16:28:22 -0500 Subject: [PATCH] Cygwin: Pass file paths instead of file descriptors over UNIX sockets Cygwin doesn't support file descriptors passing over UNIX sockets [1]. LTTng-ust and LTTng-tools make extensive use of this feature to pass the shm and the wakeup pipe file descriptor from the userspace tracer to the session daemon. The sessiond then pass those file descriptors to the consumer. To workaround this limitation, we pass the file paths of the shm and the named wakeup pipe. These paths are relayed by the sessiond to the consumer. The consumer then needs to open these paths. The files are created in /tmp/lttng-fds and have the following format: SHM : ust-shm-- Wakeup pipe : ust-wait-- The libringbuffer has been modified to automatically create these files on shm creation. Take note that the shm path is actually a symlink to the shm in /dev/shm. Also, this change introduce an additional dependency to libuuid in libringbuffer. [1] - http://cygwin.com/ml/cygwin/2009-10/msg00403.html --- include/lttng/ust-abi.h | 6 + include/lttng/ust-events.h | 12 +- include/ust-comm.h | 4 + liblttng-ust-comm/lttng-ust-comm.c | 82 +++++++++ liblttng-ust-ctl/ustctl.c | 112 +++++++---- liblttng-ust/ltt-events.c | 8 +- liblttng-ust/ltt-ring-buffer-client.h | 24 ++- .../ltt-ring-buffer-metadata-client.h | 23 ++- liblttng-ust/lttng-ust-abi.c | 8 +- liblttng-ust/lttng-ust-comm.c | 27 +-- libringbuffer/Makefile.am | 3 +- libringbuffer/frontend.h | 6 +- libringbuffer/ring_buffer_frontend.c | 16 +- libringbuffer/shm.c | 174 ++++++++++++++---- libringbuffer/shm.h | 10 +- libringbuffer/shm_types.h | 8 +- tests/ust-basic-tracing/ust-basic-tracing.c | 6 +- tests/ust-multi-test/ust-multi-test.c | 6 +- 18 files changed, 408 insertions(+), 127 deletions(-) diff --git a/include/lttng/ust-abi.h b/include/lttng/ust-abi.h index b3af9bf4..86edba90 100644 --- a/include/lttng/ust-abi.h +++ b/include/lttng/ust-abi.h @@ -128,7 +128,9 @@ struct lttng_ust_tracepoint_iter { struct lttng_ust_object_data { int handle; int shm_fd; + char *shm_path; int wait_fd; + char *wait_pipe_path; uint64_t memory_map_size; char padding[LTTNG_UST_OBJECT_DATA_PADDING]; }; @@ -198,12 +200,16 @@ struct lttng_ust_obj; union ust_args { struct { int *shm_fd; + char *shm_path; int *wait_fd; + char *wait_pipe_path; uint64_t *memory_map_size; } channel; struct { int *shm_fd; + char *shm_path; int *wait_fd; + char *wait_pipe_path; uint64_t *memory_map_size; } stream; }; diff --git a/include/lttng/ust-events.h b/include/lttng/ust-events.h index 8a40aadf..b892fbf8 100644 --- a/include/lttng/ust-events.h +++ b/include/lttng/ust-events.h @@ -303,13 +303,15 @@ struct ltt_channel_ops { size_t subbuf_size, size_t num_subbuf, unsigned int switch_timer_interval, unsigned int read_timer_interval, - int **shm_fd, int **wait_fd, + int **shm_fd, char **shm_path, + int **wait_fd, char **wait_pipe_path, uint64_t **memory_map_size, struct ltt_channel *chan_priv_init); void (*channel_destroy)(struct ltt_channel *ltt_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, + int **shm_fd, char **shm_path, + int **wait_fd, char **wait_pipe_path, uint64_t **memory_map_size); void (*buffer_read_close)(struct lttng_ust_lib_ring_buffer *buf, struct lttng_ust_shm_handle *handle); @@ -390,7 +392,8 @@ struct ltt_channel *ltt_channel_create(struct ltt_session *session, size_t subbuf_size, size_t num_subbuf, unsigned int switch_timer_interval, unsigned int read_timer_interval, - int **shm_fd, int **wait_fd, + int **shm_fd, char **shm_path, + int **wait_fd, char **wait_pipe_path, uint64_t **memory_map_size, struct ltt_channel *chan_priv_init); struct ltt_channel *ltt_global_channel_create(struct ltt_session *session, @@ -398,7 +401,8 @@ struct ltt_channel *ltt_global_channel_create(struct ltt_session *session, size_t subbuf_size, size_t num_subbuf, unsigned int switch_timer_interval, unsigned int read_timer_interval, - int **shm_fd, int **wait_fd, + int **shm_fd, char **shm_path, + int **wait_fd, char **wait_pipe_path, uint64_t **memory_map_size); int ltt_event_create(struct ltt_channel *chan, diff --git a/include/ust-comm.h b/include/ust-comm.h index 7d0b6296..0b80a0ce 100644 --- a/include/ust-comm.h +++ b/include/ust-comm.h @@ -174,4 +174,8 @@ extern int ustcomm_send_app_cmd(int sock, struct ustcomm_ust_reply *lur); int ustcomm_recv_fd(int sock); +/* Send/recv string over unix socket */ +extern ssize_t ustcomm_send_string(int sock, char *str, size_t len); +extern char *ustcomm_recv_string(int sock); + #endif /* _LTTNG_UST_COMM_H */ diff --git a/liblttng-ust-comm/lttng-ust-comm.c b/liblttng-ust-comm/lttng-ust-comm.c index 078b56a0..31380165 100644 --- a/liblttng-ust-comm/lttng-ust-comm.c +++ b/liblttng-ust-comm/lttng-ust-comm.c @@ -509,3 +509,85 @@ int ustcomm_recv_fd(int sock) end: return ret; } + +ssize_t ustcomm_send_string(int sock, char *str, size_t len) +{ + ssize_t slen, ret = -1; + + if (!str) { + goto end; + } + + /* Send string len first */ + slen = ustcomm_send_unix_sock(sock, &len, sizeof(len)); + + if (slen != sizeof(len)) { + fprintf(stderr, + "Unexpected sent size. Expected %zu got %zu\n", + sizeof(len), slen); + ret = -1; + goto end; + } + + /* Send the actual string */ + slen = ustcomm_send_unix_sock(sock, str, len); + if (slen != len) { + fprintf(stderr, + "Unexpected sent size. Expected %zu got %zu\n", + len, slen); + ret = -1; + goto end; + } + + ret = slen; + +end: + return ret; +} + +/* + * Allocate and return the received string. + * Return NULL on error. + * Caller is responsible of freeing the allocated string. + */ +char *ustcomm_recv_string(int sock) +{ + ssize_t rlen; + size_t len; + char *ret; + + /* Get the string len first */ + rlen = ustcomm_recv_unix_sock(sock, &len, sizeof(len)); + + if (rlen != sizeof(len)) { + fprintf(stderr, + "Unexpected received size. Expected %zu got %zu\n", + sizeof(len), rlen); + ret = NULL; + goto end; + } + + /* Account for the NULL byte */ + ret = malloc(len + 1); + if (!ret) { + ret = NULL; + goto end; + } + + /* Get the actual string */ + rlen = ustcomm_recv_unix_sock(sock, ret, len); + if (rlen != len) { + fprintf(stderr, + "Unexpected received size. Expected %zu got %zu\n", + len, rlen); + free(ret); + ret = NULL; + goto end; + } + + /* Set terminating NULL byte */ + ret[len] = '\0'; + +end: + return ret; +} diff --git a/liblttng-ust-ctl/ustctl.c b/liblttng-ust-ctl/ustctl.c index cf7cf87a..39997a2b 100644 --- a/liblttng-ust-ctl/ustctl.c +++ b/liblttng-ust-ctl/ustctl.c @@ -36,7 +36,9 @@ void init_object(struct lttng_ust_object_data *data) { data->handle = -1; data->shm_fd = -1; + data->shm_path = NULL; data->wait_fd = -1; + data->wait_pipe_path = NULL; data->memory_map_size = 0; } @@ -74,12 +76,22 @@ int ustctl_release_object(int sock, struct lttng_ust_object_data *data) return ret; } } + + if (data->shm_path) { + free(data->shm_path); + } + if (data->wait_fd >= 0) { ret = close(data->wait_fd); if (ret < 0) { return ret; } } + + if (data->wait_pipe_path) { + free(data->wait_pipe_path); + } + return ustctl_release_handle(sock, data->handle); } @@ -139,6 +151,7 @@ int ustctl_open_metadata(int sock, int session_handle, struct ustcomm_ust_reply lur; struct lttng_ust_object_data *metadata_data; int ret, err = 0; + char *shm_path, *wait_pipe_path; if (!chops || !_metadata_data) return -EINVAL; @@ -169,22 +182,33 @@ int ustctl_open_metadata(int sock, int session_handle, 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) + /* get shm path */ + shm_path = ustcomm_recv_string(sock); + if (!shm_path) { err = 1; - else - metadata_data->shm_fd = ret; + } else { + DBG("Received shm path: %s\n", shm_path); + metadata_data->shm_fd = -1; + metadata_data->shm_path = shm_path; + } + /* * 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) + + /* get wait pipe path */ + wait_pipe_path = ustcomm_recv_string(sock); + if (!wait_pipe_path) { + free(shm_path); err = 1; - else - metadata_data->wait_fd = ret; + } else { + DBG("Received wait pipe path: %s\n", wait_pipe_path); + metadata_data->wait_fd = -1; + metadata_data->wait_pipe_path = wait_pipe_path; + } + + if (err) goto error; *_metadata_data = metadata_data; @@ -204,6 +228,7 @@ int ustctl_create_channel(int sock, int session_handle, struct ustcomm_ust_reply lur; struct lttng_ust_object_data *channel_data; int ret, err = 0; + char *shm_path, *wait_pipe_path; if (!chops || !_channel_data) return -EINVAL; @@ -234,22 +259,31 @@ int ustctl_create_channel(int sock, int session_handle, 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) + /* get shm path */ + shm_path = ustcomm_recv_string(sock); + if (!shm_path) { err = 1; - else - channel_data->shm_fd = ret; + } else { + DBG("Received shm path: %s\n", shm_path); + channel_data->shm_fd = -1; + channel_data->shm_path = shm_path; + } + /* * 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) + /* get wait pipe path */ + wait_pipe_path = ustcomm_recv_string(sock); + if (!wait_pipe_path) { + free(shm_path); err = 1; - else - channel_data->wait_fd = ret; + } else { + DBG("Received wait pipe path: %s\n", wait_pipe_path); + channel_data->wait_fd = -1; + channel_data->wait_pipe_path = wait_pipe_path; + } + if (err) goto error; *_channel_data = channel_data; @@ -272,7 +306,8 @@ int ustctl_create_stream(int sock, struct lttng_ust_object_data *channel_data, struct ustcomm_ust_msg lum; struct ustcomm_ust_reply lur; struct lttng_ust_object_data *stream_data; - int ret, fd, err = 0; + int ret, err = 0; + char *shm_path, *wait_pipe_path; if (!channel_data || !_stream_data) return -EINVAL; @@ -297,22 +332,31 @@ int ustctl_create_stream(int sock, struct lttng_ust_object_data *channel_data, 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) + /* get shm path */ + shm_path = ustcomm_recv_string(sock); + if (!shm_path) { err = 1; - else - stream_data->shm_fd = fd; + } else { + DBG("Received shm path: %s\n", shm_path); + stream_data->shm_fd = -1; + stream_data->shm_path = shm_path; + } + /* * 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) + /* get wait pipe path */ + wait_pipe_path = ustcomm_recv_string(sock); + if (!wait_pipe_path) { + free(shm_path); err = 1; - else - stream_data->wait_fd = fd; + } else { + DBG("Received wait pipe path: %s\n", wait_pipe_path); + stream_data->wait_fd = -1; + stream_data->wait_pipe_path = wait_pipe_path; + } + if (err) goto error; *_stream_data = stream_data; @@ -684,6 +728,7 @@ struct lttng_ust_lib_ring_buffer *ustctl_open_stream_read(struct lttng_ust_shm_h { struct channel *chan; int *shm_fd, *wait_fd; + char *shm_path, *wait_pipe_path; uint64_t *memory_map_size; struct lttng_ust_lib_ring_buffer *buf; int ret; @@ -693,7 +738,10 @@ struct lttng_ust_lib_ring_buffer *ustctl_open_stream_read(struct lttng_ust_shm_h chan = handle->shadow_chan; buf = channel_get_ring_buffer(&chan->backend.config, - chan, cpu, handle, &shm_fd, &wait_fd, &memory_map_size); + chan, cpu, handle, + &shm_fd, &shm_path, + &wait_fd, &wait_pipe_path, + &memory_map_size); if (!buf) return NULL; ret = lib_ring_buffer_open_read(buf, handle, 1); diff --git a/liblttng-ust/ltt-events.c b/liblttng-ust/ltt-events.c index 2b9037ef..21e8f8ac 100644 --- a/liblttng-ust/ltt-events.c +++ b/liblttng-ust/ltt-events.c @@ -446,7 +446,8 @@ struct ltt_channel *ltt_channel_create(struct ltt_session *session, size_t subbuf_size, size_t num_subbuf, unsigned int switch_timer_interval, unsigned int read_timer_interval, - int **shm_fd, int **wait_fd, + int **shm_fd, char **shm_path, + int **wait_fd, char **wait_pipe_path, uint64_t **memory_map_size, struct ltt_channel *chan_priv_init) { @@ -470,8 +471,9 @@ struct ltt_channel *ltt_channel_create(struct ltt_session *session, */ 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); + read_timer_interval, shm_fd, shm_path, + wait_fd, wait_pipe_path, memory_map_size, + chan_priv_init); if (!chan) goto create_error; chan->enabled = 1; diff --git a/liblttng-ust/ltt-ring-buffer-client.h b/liblttng-ust/ltt-ring-buffer-client.h index f18b4ed3..b896169e 100644 --- a/liblttng-ust/ltt-ring-buffer-client.h +++ b/liblttng-ust/ltt-ring-buffer-client.h @@ -413,7 +413,8 @@ struct ltt_channel *_channel_create(const char *name, size_t subbuf_size, size_t num_subbuf, unsigned int switch_timer_interval, unsigned int read_timer_interval, - int **shm_fd, int **wait_fd, + int **shm_fd, char **shm_path, + int **wait_fd, char **wait_pipe_path, uint64_t **memory_map_size, struct ltt_channel *chan_priv_init) { @@ -426,7 +427,8 @@ struct ltt_channel *_channel_create(const char *name, chan_priv_init, buf_addr, subbuf_size, num_subbuf, switch_timer_interval, read_timer_interval, - shm_fd, wait_fd, memory_map_size); + shm_fd, shm_path, wait_fd, wait_pipe_path, + memory_map_size); if (!handle) return NULL; ltt_chan = priv; @@ -443,17 +445,19 @@ void ltt_channel_destroy(struct ltt_channel *ltt_chan) static struct lttng_ust_lib_ring_buffer *ltt_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_shm_handle *handle, + int **shm_fd, char **shm_path, + int **wait_fd, char **wait_pipe_path, + 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); + cpu, handle, shm_fd, shm_path, + wait_fd, wait_pipe_path, + memory_map_size); if (!lib_ring_buffer_open_read(buf, handle, 0)) return buf; } @@ -550,11 +554,13 @@ int ltt_flush_buffer(struct channel *chan, struct lttng_ust_shm_handle *handle) for_each_channel_cpu(cpu, chan) { int *shm_fd, *wait_fd; + char *shm_path, *wait_pipe_path; uint64_t *memory_map_size; buf = channel_get_ring_buffer(&client_config, chan, - cpu, handle, &shm_fd, &wait_fd, - &memory_map_size); + cpu, handle, &shm_fd, &shm_path, + &wait_fd, &wait_pipe_path, + &memory_map_size); lib_ring_buffer_switch(&client_config, buf, SWITCH_ACTIVE, handle); } diff --git a/liblttng-ust/ltt-ring-buffer-metadata-client.h b/liblttng-ust/ltt-ring-buffer-metadata-client.h index acc56fdd..0e9b7fa3 100644 --- a/liblttng-ust/ltt-ring-buffer-metadata-client.h +++ b/liblttng-ust/ltt-ring-buffer-metadata-client.h @@ -183,7 +183,8 @@ struct ltt_channel *_channel_create(const char *name, size_t subbuf_size, size_t num_subbuf, unsigned int switch_timer_interval, unsigned int read_timer_interval, - int **shm_fd, int **wait_fd, + int **shm_fd, char **shm_path, + int **wait_fd, char **wait_pipe_path, uint64_t **memory_map_size, struct ltt_channel *chan_priv_init) { @@ -196,7 +197,8 @@ struct ltt_channel *_channel_create(const char *name, chan_priv_init, buf_addr, subbuf_size, num_subbuf, switch_timer_interval, read_timer_interval, - shm_fd, wait_fd, memory_map_size); + shm_fd, shm_path, wait_fd, wait_pipe_path, + memory_map_size); if (!handle) return NULL; ltt_chan = priv; @@ -213,14 +215,17 @@ void ltt_channel_destroy(struct ltt_channel *ltt_chan) static struct lttng_ust_lib_ring_buffer *ltt_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_shm_handle *handle, + int **shm_fd, char **shm_path, + int **wait_fd, char **wait_pipe_path, + 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); + 0, handle, shm_fd, shm_path, + wait_fd, wait_pipe_path, + memory_map_size); if (!lib_ring_buffer_open_read(buf, handle, 0)) return buf; return NULL; @@ -300,11 +305,13 @@ int ltt_flush_buffer(struct channel *chan, struct lttng_ust_shm_handle *handle) { struct lttng_ust_lib_ring_buffer *buf; int *shm_fd, *wait_fd; + char *shm_path, *wait_pipe_path; uint64_t *memory_map_size; buf = channel_get_ring_buffer(&client_config, chan, - 0, handle, &shm_fd, &wait_fd, - &memory_map_size); + 0, handle, &shm_fd, &shm_path, + &wait_fd, &wait_pipe_path, + &memory_map_size); lib_ring_buffer_switch(&client_config, buf, SWITCH_ACTIVE, handle); return 0; diff --git a/liblttng-ust/lttng-ust-abi.c b/liblttng-ust/lttng-ust-abi.c index 435763d7..a3edd3ea 100644 --- a/liblttng-ust/lttng-ust-abi.c +++ b/liblttng-ust/lttng-ust-abi.c @@ -418,7 +418,9 @@ int lttng_abi_create_channel(int session_objd, chan_param->switch_timer_interval, chan_param->read_timer_interval, &uargs->channel.shm_fd, + &uargs->channel.shm_path, &uargs->channel.wait_fd, + &uargs->channel.wait_pipe_path, &uargs->channel.memory_map_size, &chan_priv_init); if (!chan) { @@ -617,9 +619,9 @@ int lttng_abi_open_stream(int channel_objd, struct lttng_ust_stream *info, 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); + &uargs->stream.shm_fd, &uargs->stream.shm_path, + &uargs->stream.wait_fd, &uargs->stream.wait_pipe_path, + &uargs->stream.memory_map_size); if (!buf) return -ENOENT; diff --git a/liblttng-ust/lttng-ust-comm.c b/liblttng-ust/lttng-ust-comm.c index af7928c3..3bddf767 100644 --- a/liblttng-ust/lttng-ust-comm.c +++ b/liblttng-ust/lttng-ust-comm.c @@ -252,6 +252,7 @@ int handle_message(struct sock_info *sock_info, const struct lttng_ust_objd_ops *ops; struct ustcomm_ust_reply lur; int shm_fd, wait_fd; + char *shm_path, *wait_pipe_path; union ust_args args; ust_lock(); @@ -310,14 +311,18 @@ end: * 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; + shm_fd = *args.stream.shm_fd; + shm_path = args.stream.shm_path; + wait_fd = *args.stream.wait_fd; + wait_pipe_path = args.stream.wait_pipe_path; 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; + shm_fd = *args.channel.shm_fd; + shm_path = args.channel.shm_path; + wait_fd = *args.channel.wait_fd; + wait_pipe_path = args.channel.wait_pipe_path; break; case LTTNG_UST_TRACER_VERSION: lur.u.version = lum->u.version; @@ -339,23 +344,19 @@ end: && lur.ret_code == USTCOMM_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)); + /* send the shm path */ + ret = ustcomm_send_string(sock, shm_path, strlen(shm_path)); if (ret < 0) { - perror("send shm_fd"); + perror("send shm_path"); 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)); + ret = ustcomm_send_string(sock, wait_pipe_path, strlen(wait_pipe_path)); if (ret < 0) { - perror("send wait_fd"); + perror("send wait_pipe_path"); goto error; } if (sendret) { diff --git a/libringbuffer/Makefile.am b/libringbuffer/Makefile.am index 271c8bee..0148a030 100644 --- a/libringbuffer/Makefile.am +++ b/libringbuffer/Makefile.am @@ -15,6 +15,7 @@ libringbuffer_la_SOURCES = \ libringbuffer_la_LIBADD = \ -lpthread \ - -lrt + -lrt \ + -luuid libringbuffer_la_CFLAGS = -DUST_COMPONENT="libringbuffer" -fno-strict-aliasing diff --git a/libringbuffer/frontend.h b/libringbuffer/frontend.h index b1ccddec..784307d0 100644 --- a/libringbuffer/frontend.h +++ b/libringbuffer/frontend.h @@ -65,7 +65,8 @@ struct lttng_ust_shm_handle *channel_create(const struct lttng_ust_lib_ring_buff size_t subbuf_size, size_t num_subbuf, unsigned int switch_timer_interval, unsigned int read_timer_interval, - int **shm_fd, int **wait_fd, + int **shm_fd, char **shm_path, + int **wait_fd, char **wait_pipe_path, uint64_t **memory_map_size); /* channel_handle_create - for consumer. */ @@ -102,7 +103,8 @@ extern struct lttng_ust_lib_ring_buffer *channel_get_ring_buffer( 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, + int **shm_fd, char **shm_path, + int **wait_fd, char **wait_pipe_path, uint64_t **memory_map_size); extern int lib_ring_buffer_open_read(struct lttng_ust_lib_ring_buffer *buf, struct lttng_ust_shm_handle *handle, diff --git a/libringbuffer/ring_buffer_frontend.c b/libringbuffer/ring_buffer_frontend.c index 5913f78d..c9de2923 100644 --- a/libringbuffer/ring_buffer_frontend.c +++ b/libringbuffer/ring_buffer_frontend.c @@ -439,7 +439,8 @@ struct lttng_ust_shm_handle *channel_create(const struct lttng_ust_lib_ring_buff 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 **shm_fd, char **shm_path, + int **wait_fd, char **wait_pipe_path, uint64_t **memory_map_size) { int ret, cpu; size_t shmsize, chansize; @@ -530,7 +531,7 @@ struct lttng_ust_shm_handle *channel_create(const struct lttng_ust_lib_ring_buff 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); + shm_get_object_data(handle, ref, shm_fd, shm_path, wait_fd, wait_pipe_path, memory_map_size); return handle; error_backend_init: @@ -629,22 +630,23 @@ struct lttng_ust_lib_ring_buffer *channel_get_ring_buffer( 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, + int **shm_fd, char **shm_path, + int **wait_fd, char **wait_pipe_path, 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); + shm_get_object_data(handle, ref, shm_fd, shm_path, + wait_fd, wait_pipe_path, memory_map_size); return shmp(handle, chan->backend.buf[0].shmp); } 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); + shm_get_object_data(handle, ref, shm_fd, shm_path, + wait_fd, wait_pipe_path, memory_map_size); return shmp(handle, chan->backend.buf[cpu].shmp); } } diff --git a/libringbuffer/shm.c b/libringbuffer/shm.c index 79977017..06724e58 100644 --- a/libringbuffer/shm.c +++ b/libringbuffer/shm.c @@ -20,6 +20,7 @@ #include "shm.h" #include +#include #include #include #include /* For mode constants */ @@ -32,6 +33,8 @@ #include #include #include +/* FIXME: Include UUID the proper way, e.g. config.h... */ +#include /* * Ensure we have the required amount of space available by writing 0 @@ -81,39 +84,95 @@ struct shm_object_table *shm_object_table_create(size_t max_nb_obj) return table; } +/* + * Generate a unique name with the desired prefix. + * Pattern is as follow: prefix-pid-uuid. + * Caller is responsible of freeing the resulting string. + */ +static +char *gen_unique_name(const char *prefix) +{ + int written; + pid_t pid; + uuid_t uuid; + char uuid_str[37]; + char tmp_name[NAME_MAX]; + char *name; + + if (!prefix) + return NULL; + + pid = getpid(); + + uuid_generate(uuid); + uuid_unparse(uuid, uuid_str); + + written = snprintf(tmp_name, NAME_MAX, + "%s-%d-%s", prefix, pid, uuid_str); + + if (written < 0 || written >= NAME_MAX) + return NULL; + + name = zmalloc(written + 1); + + if (!name) + return NULL; + + return strncpy(name, tmp_name, written); +} + struct shm_object *shm_object_table_append(struct shm_object_table *table, size_t memory_map_size) { - int shmfd, waitfd[2], ret, i, sigblocked = 0; + int shmfd, ret, sigblocked = 0; struct shm_object *obj; char *memory_map; + + const char *base_shm = "/dev/shm/"; + const char *base_path = "/tmp/lttng-fds/"; + const char *waitfd_prefix = "ust-wait"; + const char *shm_prefix = "ust-shm"; + + char *wait_pipe_path, *wait_pipe_file; + char *shm_path, *shm_symlink_path, *shm_file; + char tmp_name[NAME_MAX] = "ust-shm-tmp-XXXXXX"; + sigset_t all_sigs, orig_sigs; if (table->allocated_len >= table->size) return NULL; obj = &table->objects[table->allocated_len]; - /* wait_fd: create pipe */ - ret = pipe(waitfd); - if (ret < 0) { - PERROR("pipe"); - goto error_pipe; + wait_pipe_file = gen_unique_name(waitfd_prefix); + + if (!wait_pipe_file) { + goto error_gen_unique_wait; } - for (i = 0; i < 2; i++) { - ret = fcntl(waitfd[i], F_SETFD, FD_CLOEXEC); - if (ret < 0) { - PERROR("fcntl"); - goto error_fcntl; - } + + wait_pipe_path = zmalloc(strlen(base_path) + + strlen(wait_pipe_file) + 1); + + if (!wait_pipe_path) { + free(wait_pipe_file); + goto error_wait_alloc; } - /* The write end of the pipe needs to be non-blocking */ - ret = fcntl(waitfd[1], F_SETFL, O_NONBLOCK); + + strncat(wait_pipe_path, base_path, strlen(base_path)); + strncat(wait_pipe_path, wait_pipe_file, strlen(wait_pipe_file)); + + free(wait_pipe_file); + + /* wait_fd: create named pipe */ + ret = mkfifo(wait_pipe_path, 0777); if (ret < 0) { - PERROR("fcntl"); - goto error_fcntl; + PERROR("mkfifo"); + goto error_mkfifo; } - memcpy(obj->wait_fd, waitfd, sizeof(waitfd)); + + obj->wait_fd[0] = -1; + obj->wait_fd[1] = -1; + obj->wait_pipe_path = wait_pipe_path; /* shm_fd: create shm */ @@ -131,10 +190,6 @@ struct shm_object *shm_object_table_append(struct shm_object_table *table, sigblocked = 1; /* - * Allocate shm, and immediately unlink its shm oject, keeping - * only the file descriptor as a reference to the object. If it - * already exists (caused by short race window during which the - * global object exists in a concurrent shm_open), simply retry. * We specifically do _not_ use the / at the beginning of the * pathname so that some OS implementations can keep it local to * the process (POSIX leaves this implementation-defined). @@ -156,17 +211,54 @@ struct shm_object *shm_object_table_append(struct shm_object_table *table, PERROR("shm_open"); goto error_shm_open; } - ret = shm_unlink(tmp_name); - if (ret < 0 && errno != ENOENT) { - PERROR("shm_unlink"); - goto error_shm_release; - } + sigblocked = 0; ret = pthread_sigmask(SIG_SETMASK, &orig_sigs, NULL); if (ret == -1) { PERROR("pthread_sigmask"); goto error_sigmask_release; } + + /* Create unique symlink to shm */ + shm_path = zmalloc(strlen(base_shm) + strlen(tmp_name) + 1); + + if (!shm_path) { + goto error_shm_alloc; + } + + strncat(shm_path, base_shm, strlen(base_shm)); + strncat(shm_path, tmp_name, strlen(tmp_name)); + + shm_file = gen_unique_name(shm_prefix); + + if (!shm_file) { + free(shm_path); + goto error_gen_unique_shm; + } + + shm_symlink_path = zmalloc(strlen(base_path) + strlen(shm_file) + 1); + + if (!shm_symlink_path) { + free(shm_path); + free(shm_file); + goto error_symlink_alloc; + } + + strncat(shm_symlink_path, base_path, strlen(base_path)); + strncat(shm_symlink_path, shm_file, strlen(shm_file)); + + free(shm_file); + + ret = symlink(shm_path, shm_symlink_path); + if (ret < 0) { + PERROR("symlink"); + free(shm_path); + free(shm_symlink_path); + goto error_symlink_shm; + } + + free(shm_path); + ret = zero_file(shmfd, memory_map_size); if (ret) { PERROR("zero_file"); @@ -178,6 +270,7 @@ struct shm_object *shm_object_table_append(struct shm_object_table *table, goto error_ftruncate; } obj->shm_fd = shmfd; + obj->shm_path = shm_symlink_path; /* memory_map: mmap */ memory_map = mmap(NULL, memory_map_size, PROT_READ | PROT_WRITE, @@ -195,8 +288,12 @@ struct shm_object *shm_object_table_append(struct shm_object_table *table, error_mmap: error_ftruncate: -error_shm_release: error_zero_file: + free(shm_symlink_path); +error_symlink_shm: +error_symlink_alloc: +error_gen_unique_shm: +error_shm_alloc: error_sigmask_release: ret = close(shmfd); if (ret) { @@ -211,17 +308,11 @@ error_shm_open: } } error_pthread_sigmask: -error_fcntl: - for (i = 0; i < 2; i++) { - ret = close(waitfd[i]); - if (ret) { - PERROR("close"); - assert(0); - } - } -error_pipe: +error_mkfifo: + free(wait_pipe_path); +error_wait_alloc: +error_gen_unique_wait: return NULL; - } struct shm_object *shm_object_table_append_shadow(struct shm_object_table *table, @@ -276,6 +367,11 @@ void shmp_object_destroy(struct shm_object *obj) assert(0); } } + + if (obj->shm_path) { + free(obj->shm_path); + } + for (i = 0; i < 2; i++) { if (obj->wait_fd[i] < 0) continue; @@ -285,6 +381,10 @@ void shmp_object_destroy(struct shm_object *obj) assert(0); } } + + if (obj->wait_pipe_path) { + free(obj->wait_pipe_path); + } } void shm_object_table_destroy(struct shm_object_table *table) diff --git a/libringbuffer/shm.h b/libringbuffer/shm.h index 8987f72a..a745d345 100644 --- a/libringbuffer/shm.h +++ b/libringbuffer/shm.h @@ -119,7 +119,9 @@ int shm_get_wait_fd(struct lttng_ust_shm_handle *handle, struct shm_ref *ref) 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_fd, char **shm_path, + int **wait_fd, char **wait_pipe_path, + uint64_t **memory_map_size) { struct shm_object_table *table = handle->table; struct shm_object *obj; @@ -129,8 +131,10 @@ int shm_get_object_data(struct lttng_ust_shm_handle *handle, struct shm_ref *ref if (caa_unlikely(index >= table->allocated_len)) return -EPERM; obj = &table->objects[index]; - *shm_fd = &obj->shm_fd; - *wait_fd = &obj->wait_fd[0]; + *shm_fd = &obj->shm_fd; + *shm_path = obj->shm_path; + *wait_fd = &obj->wait_fd[0]; + *wait_pipe_path = obj->wait_pipe_path; *memory_map_size = &obj->allocated_len; return 0; } diff --git a/libringbuffer/shm_types.h b/libringbuffer/shm_types.h index 8b01d803..a311f1cd 100644 --- a/libringbuffer/shm_types.h +++ b/libringbuffer/shm_types.h @@ -27,9 +27,11 @@ struct channel; struct shm_object { - size_t index; /* within the object table */ - int shm_fd; /* shm fd */ - int wait_fd[2]; /* fd for wait/wakeup */ + size_t index; /* within the object table */ + int shm_fd; /* shm fd */ + char *shm_path; /* shm path */ + int wait_fd[2]; /* fd for wait/wakeup */ + char *wait_pipe_path; /* named pipe path for wait/wakeup */ char *memory_map; int is_shadow; size_t memory_map_size; diff --git a/tests/ust-basic-tracing/ust-basic-tracing.c b/tests/ust-basic-tracing/ust-basic-tracing.c index e704af1f..186d56ef 100644 --- a/tests/ust-basic-tracing/ust-basic-tracing.c +++ b/tests/ust-basic-tracing/ust-basic-tracing.c @@ -207,13 +207,17 @@ int consume_stream(struct lttng_ust_shm_handle *handle, int cpu, char *outfile) struct lttng_ust_lib_ring_buffer *buf; int outfd, ret; int *shm_fd, *wait_fd; + char *shm_path, *wait_pipe_path; uint64_t *memory_map_size; chan = shmp(handle, handle->chan); /* open stream */ buf = channel_get_ring_buffer(&chan->backend.config, - chan, cpu, handle, &shm_fd, &wait_fd, &memory_map_size); + chan, cpu, handle, + &shm_fd, &shm_path, + &wait_fd, &wait_pipe_path, + &memory_map_size); if (!buf) return -ENOENT; ret = lib_ring_buffer_open_read(buf, handle, 1); diff --git a/tests/ust-multi-test/ust-multi-test.c b/tests/ust-multi-test/ust-multi-test.c index bea01b16..db629626 100644 --- a/tests/ust-multi-test/ust-multi-test.c +++ b/tests/ust-multi-test/ust-multi-test.c @@ -214,13 +214,17 @@ int consume_stream(struct lttng_ust_shm_handle *handle, int cpu, char *outfile) struct lttng_ust_lib_ring_buffer *buf; int outfd, ret; int *shm_fd, *wait_fd; + char *shm_path, *wait_pipe_path; uint64_t *memory_map_size; chan = shmp(handle, handle->chan); /* open stream */ buf = channel_get_ring_buffer(&chan->backend.config, - chan, cpu, handle, &shm_fd, &wait_fd, &memory_map_size); + chan, cpu, handle, + &shm_fd, &shm_path, + &wait_fd, &wait_pipe_path, + &memory_map_size); if (!buf) return -ENOENT; ret = lib_ring_buffer_open_read(buf, handle, 1); -- 2.34.1