From a3f61e7f689a5fc60b833a773f462989dc6cc78f Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Tue, 8 Nov 2011 09:41:35 -0500 Subject: [PATCH] Move struct ltt_channel to shm for consumer flush Signed-off-by: Mathieu Desnoyers --- include/lttng/ust-events.h | 13 ++++- liblttng-ust/ltt-events.c | 18 +++---- liblttng-ust/ltt-ring-buffer-client.h | 22 +++++--- .../ltt-ring-buffer-metadata-client.h | 22 +++++--- liblttng-ust/lttng-ust-abi.c | 3 +- libringbuffer/backend_internal.h | 2 +- libringbuffer/backend_types.h | 2 +- libringbuffer/frontend.h | 17 ++++-- libringbuffer/frontend_types.h | 3 +- libringbuffer/ring_buffer_backend.c | 4 +- libringbuffer/ring_buffer_frontend.c | 53 +++++++++++++------ 11 files changed, 100 insertions(+), 59 deletions(-) diff --git a/include/lttng/ust-events.h b/include/lttng/ust-events.h index f6d76528..5068a3b3 100644 --- a/include/lttng/ust-events.h +++ b/include/lttng/ust-events.h @@ -216,7 +216,6 @@ struct lttng_ust_shm_handle; struct ltt_channel_ops { struct ltt_channel *(*channel_create)(const char *name, - struct ltt_channel *ltt_chan, void *buf_addr, size_t subbuf_size, size_t num_subbuf, unsigned int switch_timer_interval, @@ -250,7 +249,12 @@ struct ltt_channel_ops { }; struct ltt_channel { - unsigned int id; + /* + * The pointers located in this private data are NOT safe to be + * dereferenced by the consumer. The only operations the + * consumer process is designed to be allowed to do is to read + * and perform subbuffer flush. + */ struct channel *chan; /* Channel buffers */ int enabled; struct lttng_ctx *ctx; @@ -264,6 +268,11 @@ struct ltt_channel { int header_type; /* 0: unset, 1: compact, 2: large */ struct lttng_ust_shm_handle *handle; /* shared-memory handle */ int metadata_dumped:1; + + /* Channel ID, available for consumer too */ + unsigned int id; + /* Copy of session UUID for consumer (availability through shm) */ + uuid_t uuid; /* Trace session unique ID */ }; struct ltt_session { diff --git a/liblttng-ust/ltt-events.c b/liblttng-ust/ltt-events.c index fc7dfc7c..d31412c6 100644 --- a/liblttng-ust/ltt-events.c +++ b/liblttng-ust/ltt-events.c @@ -295,7 +295,7 @@ struct ltt_channel *ltt_channel_create(struct ltt_session *session, int *shm_fd, int *wait_fd, uint64_t *memory_map_size) { - struct ltt_channel *chan; + struct ltt_channel *chan = NULL; struct ltt_transport *transport; if (session->been_active) @@ -306,30 +306,25 @@ struct ltt_channel *ltt_channel_create(struct ltt_session *session, transport_name); goto notransport; } - chan = zmalloc(sizeof(struct ltt_channel)); - if (!chan) - goto nomem; - chan->session = session; - chan->id = session->free_chan_id++; /* * Note: the channel creation op already writes into the packet * headers. Therefore the "chan" information used as input * should be already accessible. */ - transport->ops.channel_create("[lttng]", chan, buf_addr, + chan = transport->ops.channel_create("[lttng]", buf_addr, subbuf_size, num_subbuf, switch_timer_interval, read_timer_interval, shm_fd, wait_fd, memory_map_size); - if (!chan->chan) + if (!chan) goto create_error; + chan->session = session; + chan->id = session->free_chan_id++; chan->enabled = 1; chan->ops = &transport->ops; cds_list_add(&chan->list, &session->chan); return chan; create_error: - free(chan); -nomem: notransport: active: return NULL; @@ -341,10 +336,9 @@ active: static void _ltt_channel_destroy(struct ltt_channel *chan) { - chan->ops->channel_destroy(chan); cds_list_del(&chan->list); lttng_destroy_context(chan->ctx); - free(chan); + chan->ops->channel_destroy(chan); } /* diff --git a/liblttng-ust/ltt-ring-buffer-client.h b/liblttng-ust/ltt-ring-buffer-client.h index 9bbcab90..abbaf705 100644 --- a/liblttng-ust/ltt-ring-buffer-client.h +++ b/liblttng-ust/ltt-ring-buffer-client.h @@ -305,10 +305,9 @@ static void client_buffer_begin(struct lttng_ust_lib_ring_buffer *buf, u64 tsc, subbuf_idx * chan->backend.subbuf_size, handle); struct ltt_channel *ltt_chan = channel_get_private(chan); - struct ltt_session *session = ltt_chan->session; header->magic = CTF_MAGIC_NUMBER; - memcpy(header->uuid, session->uuid, sizeof(session->uuid)); + memcpy(header->uuid, ltt_chan->uuid, sizeof(ltt_chan->uuid)); header->stream_id = ltt_chan->id; header->ctx.timestamp_begin = tsc; header->ctx.timestamp_end = 0; @@ -382,19 +381,26 @@ const struct lttng_ust_lib_ring_buffer_client_cb *LTTNG_CLIENT_CALLBACKS = &clie static struct ltt_channel *_channel_create(const char *name, - struct ltt_channel *ltt_chan, void *buf_addr, + 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) { - ltt_chan->handle = channel_create(&client_config, name, ltt_chan, buf_addr, - subbuf_size, num_subbuf, switch_timer_interval, - read_timer_interval, shm_fd, wait_fd, - memory_map_size); - if (!ltt_chan->handle) + void *priv; + struct ltt_channel *ltt_chan = NULL; + struct lttng_ust_shm_handle *handle; + + handle = channel_create(&client_config, name, + &priv, __alignof__(*ltt_chan), sizeof(*ltt_chan), + buf_addr, subbuf_size, num_subbuf, + switch_timer_interval, read_timer_interval, + shm_fd, wait_fd, memory_map_size); + if (!handle) return NULL; + ltt_chan = priv; + ltt_chan->handle = handle; ltt_chan->chan = shmp(ltt_chan->handle, ltt_chan->handle->chan); return ltt_chan; } diff --git a/liblttng-ust/ltt-ring-buffer-metadata-client.h b/liblttng-ust/ltt-ring-buffer-metadata-client.h index 4f2620e0..46aab3cc 100644 --- a/liblttng-ust/ltt-ring-buffer-metadata-client.h +++ b/liblttng-ust/ltt-ring-buffer-metadata-client.h @@ -88,10 +88,9 @@ static void client_buffer_begin(struct lttng_ust_lib_ring_buffer *buf, u64 tsc, subbuf_idx * chan->backend.subbuf_size, handle); struct ltt_channel *ltt_chan = channel_get_private(chan); - struct ltt_session *session = ltt_chan->session; header->magic = TSDL_MAGIC_NUMBER; - memcpy(header->uuid, session->uuid, sizeof(session->uuid)); + memcpy(header->uuid, ltt_chan->uuid, sizeof(ltt_chan->uuid)); header->checksum = 0; /* 0 if unused */ header->content_size = 0xFFFFFFFF; /* in bits, for debugging */ header->packet_size = 0xFFFFFFFF; /* in bits, for debugging */ @@ -165,19 +164,26 @@ const struct lttng_ust_lib_ring_buffer_client_cb *LTTNG_CLIENT_CALLBACKS = &clie static struct ltt_channel *_channel_create(const char *name, - struct ltt_channel *ltt_chan, void *buf_addr, + 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) { - ltt_chan->handle = channel_create(&client_config, name, ltt_chan, buf_addr, - subbuf_size, num_subbuf, switch_timer_interval, - read_timer_interval, shm_fd, wait_fd, - memory_map_size); - if (!ltt_chan->handle) + void *priv; + struct ltt_channel *ltt_chan = NULL; + struct lttng_ust_shm_handle *handle; + + handle = channel_create(&client_config, name, + &priv, __alignof__(*ltt_chan), sizeof(*ltt_chan), + buf_addr, subbuf_size, num_subbuf, + switch_timer_interval, read_timer_interval, + shm_fd, wait_fd, memory_map_size); + if (!handle) return NULL; + ltt_chan = priv; + ltt_chan->handle = handle; ltt_chan->chan = shmp(ltt_chan->handle, ltt_chan->handle->chan); return ltt_chan; } diff --git a/liblttng-ust/lttng-ust-abi.c b/liblttng-ust/lttng-ust-abi.c index 6d17c200..639165eb 100644 --- a/liblttng-ust/lttng-ust-abi.c +++ b/liblttng-ust/lttng-ust-abi.c @@ -419,9 +419,10 @@ int lttng_abi_create_channel(int session_objd, session->metadata = chan; lttng_metadata_create_events(chan_objd); } - /* The channel created holds a reference on the session */ objd_ref(session_objd); + /* Copy of session UUID for consumer (availability through shm) */ + memcpy(chan->uuid, session->uuid, sizeof(session->uuid)); return chan_objd; diff --git a/libringbuffer/backend_internal.h b/libringbuffer/backend_internal.h index e3192be7..f61d1d61 100644 --- a/libringbuffer/backend_internal.h +++ b/libringbuffer/backend_internal.h @@ -32,7 +32,7 @@ void lib_ring_buffer_backend_free(struct lttng_ust_lib_ring_buffer_backend *bufb int channel_backend_init(struct channel_backend *chanb, const char *name, const struct lttng_ust_lib_ring_buffer_config *config, - void *priv, size_t subbuf_size, + size_t subbuf_size, size_t num_subbuf, struct lttng_ust_shm_handle *handle); void channel_backend_free(struct channel_backend *chanb, struct lttng_ust_shm_handle *handle); diff --git a/libringbuffer/backend_types.h b/libringbuffer/backend_types.h index a77c4c95..1c3d3bc5 100644 --- a/libringbuffer/backend_types.h +++ b/libringbuffer/backend_types.h @@ -70,7 +70,7 @@ struct channel_backend { int extra_reader_sb:1; /* Bool: has extra reader subbuffer */ unsigned long num_subbuf; /* Number of sub-buffers for writer */ u64 start_tsc; /* Channel creation TSC value */ - void *priv; /* Client-specific information */ + DECLARE_SHMP(void *, priv_data);/* Client-specific information */ struct lttng_ust_lib_ring_buffer_config config; /* Ring buffer configuration */ char name[NAME_MAX]; /* Channel name */ struct lttng_ust_lib_ring_buffer_shmp buf[]; diff --git a/libringbuffer/frontend.h b/libringbuffer/frontend.h index e1d9d575..993a3917 100644 --- a/libringbuffer/frontend.h +++ b/libringbuffer/frontend.h @@ -34,11 +34,19 @@ * buf_addr is a pointer the the beginning of the preallocated buffer contiguous * address mapping. It is used only by RING_BUFFER_STATIC configuration. It can * be set to NULL for other backends. + * + * priv_data (output) is set to a pointer into a "priv_data_len"-sized + * memory area for client-specific data. This memory is managed by lib + * ring buffer. priv_data_align is the alignment required for the + * private data area. */ extern struct lttng_ust_shm_handle *channel_create(const struct lttng_ust_lib_ring_buffer_config *config, - const char *name, void *priv, + const char *name, + void **priv_data, + size_t priv_data_align, + size_t priv_data_size, void *buf_addr, size_t subbuf_size, size_t num_subbuf, unsigned int switch_timer_interval, @@ -57,12 +65,11 @@ int channel_handle_add_stream(struct lttng_ust_shm_handle *handle, int shm_fd, int wait_fd, uint64_t memory_map_size); /* - * channel_destroy returns the private data pointer. It finalizes all channel's - * buffers, waits for readers to release all references, and destroys the - * channel. + * channel_destroy finalizes all channel's buffers, waits for readers to + * release all references, and destroys the channel. */ extern -void *channel_destroy(struct channel *chan, struct lttng_ust_shm_handle *handle, +void channel_destroy(struct channel *chan, struct lttng_ust_shm_handle *handle, int shadow); diff --git a/libringbuffer/frontend_types.h b/libringbuffer/frontend_types.h index 7d9166e0..93131616 100644 --- a/libringbuffer/frontend_types.h +++ b/libringbuffer/frontend_types.h @@ -48,6 +48,7 @@ struct channel { unsigned long read_timer_interval; /* Reader wakeup (jiffies) */ //wait_queue_head_t read_wait; /* reader wait queue */ int finalized; /* Has channel been finalized */ + size_t priv_data_offset; /* * Associated backend contains a variable-length array. Needs to * be last member. @@ -114,7 +115,7 @@ struct lttng_ust_lib_ring_buffer { static inline void *channel_get_private(struct channel *chan) { - return chan->backend.priv; + return ((char *) chan) + chan->priv_data_offset; } /* diff --git a/libringbuffer/ring_buffer_backend.c b/libringbuffer/ring_buffer_backend.c index f2169aa7..c32ba982 100644 --- a/libringbuffer/ring_buffer_backend.c +++ b/libringbuffer/ring_buffer_backend.c @@ -190,7 +190,6 @@ void channel_backend_reset(struct channel_backend *chanb) * @chanb: channel backend * @name: channel name * @config: client ring buffer configuration - * @priv: client private data * @parent: dentry of parent directory, %NULL for root directory * @subbuf_size: size of sub-buffers (> PAGE_SIZE, power of 2) * @num_subbuf: number of sub-buffers (power of 2) @@ -207,7 +206,7 @@ void channel_backend_reset(struct channel_backend *chanb) int channel_backend_init(struct channel_backend *chanb, const char *name, const struct lttng_ust_lib_ring_buffer_config *config, - void *priv, size_t subbuf_size, size_t num_subbuf, + size_t subbuf_size, size_t num_subbuf, struct lttng_ust_shm_handle *handle) { struct channel *chan = caa_container_of(chanb, struct channel, backend); @@ -235,7 +234,6 @@ int channel_backend_init(struct channel_backend *chanb, if (ret) return ret; - chanb->priv = priv; chanb->buf_size = num_subbuf * subbuf_size; chanb->subbuf_size = subbuf_size; chanb->buf_size_order = get_count_order(chanb->buf_size); diff --git a/libringbuffer/ring_buffer_frontend.c b/libringbuffer/ring_buffer_frontend.c index 436e4b8c..fdb4bdfc 100644 --- a/libringbuffer/ring_buffer_frontend.c +++ b/libringbuffer/ring_buffer_frontend.c @@ -174,7 +174,7 @@ int lib_ring_buffer_create(struct lttng_ust_lib_ring_buffer *buf, { const struct lttng_ust_lib_ring_buffer_config *config = &chanb->config; struct channel *chan = caa_container_of(chanb, struct channel, backend); - void *priv = chanb->priv; + void *priv = channel_get_private(chan); unsigned int num_subbuf; size_t subbuf_header_size; u64 tsc; @@ -409,7 +409,8 @@ static void channel_free(struct channel *chan, struct lttng_ust_shm_handle *hand * channel_create - Create channel. * @config: ring buffer instance configuration * @name: name of the channel - * @priv: ring buffer client private data + * @priv_data: ring buffer client private data area pointer (output) + * @priv_data_size: length, in bytes, of the private data area. * @buf_addr: pointer the the beginning of the preallocated buffer contiguous * address mapping. It is used only by RING_BUFFER_STATIC * configuration. It can be set to NULL for other backends. @@ -424,14 +425,17 @@ static void channel_free(struct channel *chan, struct lttng_ust_shm_handle *hand * Returns NULL on failure. */ struct lttng_ust_shm_handle *channel_create(const struct lttng_ust_lib_ring_buffer_config *config, - const char *name, void *priv, void *buf_addr, - size_t subbuf_size, + const char *name, + void **priv_data, + size_t priv_data_align, + size_t priv_data_size, + 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 ret, cpu; - size_t shmsize; + size_t shmsize, chansize; struct channel *chan; struct lttng_ust_shm_handle *handle; struct shm_object *shmobj; @@ -457,19 +461,37 @@ struct lttng_ust_shm_handle *channel_create(const struct lttng_ust_lib_ring_buff shmsize += sizeof(struct lttng_ust_lib_ring_buffer_shmp) * num_possible_cpus(); else shmsize += sizeof(struct lttng_ust_lib_ring_buffer_shmp); + chansize = shmsize; + shmsize += offset_align(shmsize, priv_data_align); + shmsize += priv_data_size; shmobj = shm_object_table_append(handle->table, shmsize); if (!shmobj) goto error_append; /* struct channel is at object 0, offset 0 (hardcoded) */ - set_shmp(handle->chan, zalloc_shm(shmobj, shmsize)); + set_shmp(handle->chan, zalloc_shm(shmobj, chansize)); assert(handle->chan._ref.index == 0); assert(handle->chan._ref.offset == 0); chan = shmp(handle, handle->chan); if (!chan) goto error_append; - ret = channel_backend_init(&chan->backend, name, config, priv, + /* space for private data */ + if (priv_data_size) { + DECLARE_SHMP(void, priv_data_alloc); + + align_shm(shmobj, priv_data_align); + chan->priv_data_offset = shmobj->allocated_len; + set_shmp(priv_data_alloc, zalloc_shm(shmobj, priv_data_size)); + if (!shmp(handle, priv_data_alloc)) + goto error_append; + *priv_data = channel_get_private(chan); + } else { + chan->priv_data_offset = -1; + *priv_data = NULL; + } + + ret = channel_backend_init(&chan->backend, name, config, subbuf_size, num_subbuf, handle); if (ret) goto error_backend_init; @@ -570,19 +592,17 @@ void channel_release(struct channel *chan, struct lttng_ust_shm_handle *handle, * Call "destroy" callback, finalize channels, decrement the channel * reference count. Note that when readers have completed data * consumption of finalized channels, get_subbuf() will return -ENODATA. - * They should release their handle at that point. Returns the private - * data pointer. + * They should release their handle at that point. */ -void *channel_destroy(struct channel *chan, struct lttng_ust_shm_handle *handle, +void channel_destroy(struct channel *chan, struct lttng_ust_shm_handle *handle, int shadow) { const struct lttng_ust_lib_ring_buffer_config *config = &chan->backend.config; - void *priv; int cpu; if (shadow) { channel_release(chan, handle, shadow); - return NULL; + return; } channel_unregister_notifiers(chan, handle); @@ -593,7 +613,7 @@ void *channel_destroy(struct channel *chan, struct lttng_ust_shm_handle *handle, if (config->cb.buffer_finalize) config->cb.buffer_finalize(buf, - chan->backend.priv, + channel_get_private(chan), cpu, handle); if (buf->backend.allocated) lib_ring_buffer_switch_slow(buf, SWITCH_FLUSH, @@ -609,7 +629,7 @@ void *channel_destroy(struct channel *chan, struct lttng_ust_shm_handle *handle, struct lttng_ust_lib_ring_buffer *buf = shmp(handle, chan->backend.buf[0].shmp); if (config->cb.buffer_finalize) - config->cb.buffer_finalize(buf, chan->backend.priv, -1, handle); + config->cb.buffer_finalize(buf, channel_get_private(chan), -1, handle); if (buf->backend.allocated) lib_ring_buffer_switch_slow(buf, SWITCH_FLUSH, handle); @@ -627,9 +647,8 @@ void *channel_destroy(struct channel *chan, struct lttng_ust_shm_handle *handle, * sessiond/consumer are keeping a reference on the shm file * descriptor directly. No need to refcount. */ - priv = chan->backend.priv; channel_release(chan, handle, shadow); - return priv; + return; } struct lttng_ust_lib_ring_buffer *channel_get_ring_buffer( @@ -1006,7 +1025,7 @@ void lib_ring_buffer_print_errors(struct channel *chan, struct lttng_ust_shm_handle *handle) { const struct lttng_ust_lib_ring_buffer_config *config = &chan->backend.config; - void *priv = chan->backend.priv; + void *priv = channel_get_private(chan); ERRMSG("ring buffer %s, cpu %d: %lu records written, " "%lu records overrun\n", -- 2.34.1