From: Mathieu Desnoyers Date: Tue, 29 Jan 2013 22:40:18 +0000 (-0500) Subject: Move LTTng-UST buffer ownership from application to consumer X-Git-Tag: v2.2.0-rc1~82 X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=74d81a6cca2cd4a7718bba9368f382f9f2fbba84;p=lttng-ust.git Move LTTng-UST buffer ownership from application to consumer Before this change, applications were performing allocation and teardown of their buffers. Applications therefore had ownership of the buffers. The shm and wait fd were passed from applications, though sessiond, to consumerd through unix sockets. This change moves ownership of buffers from applications to consumer. This will allow sharing buffers across many processes in a near future. It will also facilitate implementation of periodical timers on the consumer side, now that it has ownership of channels and buffers (also called streams). This imply that file descriptors on shm and wakeup end of the pipe are now passed from the consumerd to sessiond, then to applications, through unix sockets. Then, applications "map" channel and streams into their own memory space. Channel control structure is actually a copy for each application, while streams are a shared memory map (shm) between consumerd and all applications that write into it, and have a wake up file descriptor on the application side. Dependency on libuuid is now removed from lttng-ust, and moved to lttng-tools, since the UUID is needed at channel and buffer allocation. This commit needs to be used along with commit named "Move LTTng-UST buffer ownership from application to consumer" in lttng-tools. Reviewed-by: David Goulet Signed-off-by: Mathieu Desnoyers --- diff --git a/README b/README index a6487335..55c72df7 100644 --- a/README +++ b/README @@ -24,10 +24,6 @@ PREREQUISITES: * GitWeb: http://lttng.org/cgi-bin/gitweb.cgi?p=userspace-rcu.git;a=summary * Git: git://lttng.org/userspace-rcu.git - - libuuid (for Linux) - * Debian/Ubuntu package: libuuid1, uuid-dev - * Fedora package: libuuid-devel - For developers using the git tree: This source tree is based on the autotools suite from GNU to simplify diff --git a/configure.ac b/configure.ac index ba529f38..fdc5c846 100644 --- a/configure.ac +++ b/configure.ac @@ -109,27 +109,6 @@ AM_CONDITIONAL([LTTNG_UST_BUILD_WITH_LIBC_DL], [test "x$have_libc_dl" = "xyes"]) AC_CHECK_LIB([pthread], [pthread_create]) -# Check for libuuid -AC_CHECK_LIB([uuid], [uuid_generate], -[ - AC_DEFINE_UNQUOTED([LTTNG_UST_HAVE_LIBUUID], 1, [Has libuuid support.]) - have_libuuid=yes -], -[ - # libuuid not found, check for uuid_create in libc. - AC_CHECK_LIB([c], [uuid_create], - [ - AC_DEFINE_UNQUOTED([LTTNG_UST_HAVE_LIBC_UUID], 1, [Has libc uuid support.]) - have_libc_uuid=yes - ], - [ - AC_MSG_ERROR([Cannot find libuuid uuid_generate nor libc uuid_create. Use [LDFLAGS]=-Ldir to specify their location.]) - ]) -] -) -AM_CONDITIONAL([LTTNG_UST_BUILD_WITH_LIBUUID], [test "x$have_libuuid" = "xyes"]) -AM_CONDITIONAL([LTTNG_UST_BUILD_WITH_LIBC_UUID], [test "x$have_libc_uuid" = "xyes"]) - # Checks for header files. #AC_CHECK_HEADERS([fcntl.h stdint.h stdlib.h string.h sys/socket.h sys/time.h unistd.h]) diff --git a/include/lttng/ust-abi.h b/include/lttng/ust-abi.h index a5740357..8c065fca 100644 --- a/include/lttng/ust-abi.h +++ b/include/lttng/ust-abi.h @@ -57,35 +57,45 @@ enum lttng_ust_output { LTTNG_UST_MMAP = 0, }; +enum lttng_ust_chan_type { + LTTNG_UST_CHAN_PER_CPU = 0, + LTTNG_UST_CHAN_METADATA = 1, +}; + struct lttng_ust_tracer_version { uint32_t major; uint32_t minor; uint32_t patchlevel; } LTTNG_PACKED; -#define LTTNG_UST_CHANNEL_PADDING LTTNG_UST_SYM_NAME_LEN + 32 +#define LTTNG_UST_CHANNEL_PADDING (LTTNG_UST_SYM_NAME_LEN + 32) +/* + * Given that the consumerd is limited to 64k file descriptors, we + * cannot expect much more than 1MB channel structure size. This size is + * depends on the number of streams within a channel, which depends on + * the number of possible CPUs on the system. + */ +#define LTTNG_UST_CHANNEL_DATA_MAX_LEN 1048576U struct lttng_ust_channel { - uint64_t subbuf_size; /* in bytes */ - uint64_t num_subbuf; - int overwrite; /* 1: overwrite, 0: discard */ - unsigned int switch_timer_interval; /* usecs */ - unsigned int read_timer_interval; /* usecs */ - enum lttng_ust_output output; /* output mode */ + uint64_t len; + enum lttng_ust_chan_type type; char padding[LTTNG_UST_CHANNEL_PADDING]; + char data[]; /* variable sized data */ } LTTNG_PACKED; -#define LTTNG_UST_STREAM_PADDING1 16 -#define LTTNG_UST_STREAM_PADDING2 LTTNG_UST_SYM_NAME_LEN + 32 +#define LTTNG_UST_STREAM_PADDING1 (LTTNG_UST_SYM_NAME_LEN + 32) struct lttng_ust_stream { + uint64_t len; /* shm len */ + uint32_t stream_nr; /* stream number */ char padding[LTTNG_UST_STREAM_PADDING1]; - - union { - char padding[LTTNG_UST_STREAM_PADDING2]; - } u; + /* + * shm_fd and wakeup_fd are send over unix socket as file + * descriptors after this structure. + */ } LTTNG_PACKED; #define LTTNG_UST_EVENT_PADDING1 16 -#define LTTNG_UST_EVENT_PADDING2 LTTNG_UST_SYM_NAME_LEN + 32 +#define LTTNG_UST_EVENT_PADDING2 (LTTNG_UST_SYM_NAME_LEN + 32) struct lttng_ust_event { enum lttng_ust_instrumentation instrumentation; char name[LTTNG_UST_SYM_NAME_LEN]; /* event name */ @@ -108,7 +118,7 @@ enum lttng_ust_field_type { LTTNG_UST_FIELD_STRING = 4, }; -#define LTTNG_UST_FIELD_ITER_PADDING LTTNG_UST_SYM_NAME_LEN + 28 +#define LTTNG_UST_FIELD_ITER_PADDING (LTTNG_UST_SYM_NAME_LEN + 28) struct lttng_ust_field_iter { char event_name[LTTNG_UST_SYM_NAME_LEN]; char field_name[LTTNG_UST_SYM_NAME_LEN]; @@ -126,7 +136,7 @@ enum lttng_ust_context_type { }; #define LTTNG_UST_CONTEXT_PADDING1 16 -#define LTTNG_UST_CONTEXT_PADDING2 LTTNG_UST_SYM_NAME_LEN + 32 +#define LTTNG_UST_CONTEXT_PADDING2 (LTTNG_UST_SYM_NAME_LEN + 32) struct lttng_ust_context { enum lttng_ust_context_type ctx; char padding[LTTNG_UST_CONTEXT_PADDING1]; @@ -139,7 +149,7 @@ struct lttng_ust_context { /* * Tracer channel attributes. */ -#define LTTNG_UST_CHANNEL_ATTR_PADDING LTTNG_UST_SYM_NAME_LEN + 32 +#define LTTNG_UST_CHANNEL_ATTR_PADDING (LTTNG_UST_SYM_NAME_LEN + 32) struct lttng_ust_channel_attr { uint64_t subbuf_size; /* bytes */ uint64_t num_subbuf; /* power of 2 */ @@ -157,13 +167,32 @@ struct lttng_ust_tracepoint_iter { char padding[LTTNG_UST_TRACEPOINT_ITER_PADDING]; } LTTNG_PACKED; -#define LTTNG_UST_OBJECT_DATA_PADDING LTTNG_UST_SYM_NAME_LEN + 32 +enum lttng_ust_object_type { + LTTNG_UST_OBJECT_TYPE_UNKNOWN = -1, + LTTNG_UST_OBJECT_TYPE_CHANNEL = 0, + LTTNG_UST_OBJECT_TYPE_STREAM = 1, +}; + +#define LTTNG_UST_OBJECT_DATA_PADDING1 32 +#define LTTNG_UST_OBJECT_DATA_PADDING2 (LTTNG_UST_SYM_NAME_LEN + 32) + struct lttng_ust_object_data { - uint64_t memory_map_size; + enum lttng_ust_object_type type; int handle; - int shm_fd; - int wait_fd; - char padding[LTTNG_UST_OBJECT_DATA_PADDING]; + uint64_t size; + char padding1[LTTNG_UST_OBJECT_DATA_PADDING1]; + union { + struct { + void *data; + enum lttng_ust_chan_type type; + } channel; + struct { + int shm_fd; + int wakeup_fd; + uint32_t stream_nr; + } stream; + char padding2[LTTNG_UST_OBJECT_DATA_PADDING2]; + } u; } LTTNG_PACKED; enum lttng_ust_calibrate_type { @@ -171,7 +200,7 @@ enum lttng_ust_calibrate_type { }; #define LTTNG_UST_CALIBRATE_PADDING1 16 -#define LTTNG_UST_CALIBRATE_PADDING2 LTTNG_UST_SYM_NAME_LEN + 32 +#define LTTNG_UST_CALIBRATE_PADDING2 (LTTNG_UST_SYM_NAME_LEN + 32) struct lttng_ust_calibrate { enum lttng_ust_calibrate_type type; /* type (input) */ char padding[LTTNG_UST_CALIBRATE_PADDING1]; @@ -210,8 +239,6 @@ struct lttng_ust_filter_bytecode { #define LTTNG_UST_TRACEPOINT_FIELD_LIST _UST_CMD(0x45) /* Session FD commands */ -#define LTTNG_UST_METADATA \ - _UST_CMDW(0x50, struct lttng_ust_channel) #define LTTNG_UST_CHANNEL \ _UST_CMDW(0x51, struct lttng_ust_channel) #define LTTNG_UST_SESSION_START _UST_CMD(0x52) @@ -245,14 +272,11 @@ struct lttng_ust_obj; union ust_args { struct { - int *shm_fd; - int *wait_fd; - uint64_t *memory_map_size; + void *chan_data; } channel; struct { - int *shm_fd; - int *wait_fd; - uint64_t *memory_map_size; + int shm_fd; + int wakeup_fd; } stream; struct { struct lttng_ust_field_iter entry; diff --git a/include/lttng/ust-ctl.h b/include/lttng/ust-ctl.h index a067480b..06b9f92b 100644 --- a/include/lttng/ust-ctl.h +++ b/include/lttng/ust-ctl.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2011 - Julien Desfossez - * Mathieu Desnoyers + * Copyright (C) 2011-2013 - Mathieu Desnoyers * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,6 +21,32 @@ #include +#ifndef LTTNG_PACKED +#define LTTNG_PACKED __attribute__((packed)) +#endif + +#ifndef LTTNG_UST_UUID_LEN +#define LTTNG_UST_UUID_LEN 16 +#endif + +struct lttng_ust_shm_handle; +struct lttng_ust_lib_ring_buffer; + +struct ustctl_consumer_channel_attr { + enum lttng_ust_chan_type type; + uint64_t subbuf_size; /* bytes */ + uint64_t num_subbuf; /* power of 2 */ + int overwrite; /* 1: overwrite, 0: discard */ + unsigned int switch_timer_interval; /* usec */ + unsigned int read_timer_interval; /* usec */ + enum lttng_ust_output output; /* splice, mmap */ + unsigned char uuid[LTTNG_UST_UUID_LEN]; /* Trace session unique ID */ +} LTTNG_PACKED; + +/* + * API used by sessiond. + */ + /* * Error values: all the following functions return: * >= 0: Success (LTTNG_UST_OK) @@ -28,12 +54,6 @@ */ int ustctl_register_done(int sock); 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_create_channel(int sock, int session_handle, - struct lttng_ust_channel_attr *chops, - struct lttng_ust_object_data **channel_data); int ustctl_create_event(int sock, struct lttng_ust_event *ev, struct lttng_ust_object_data *channel_data, struct lttng_ust_object_data **event_data); @@ -48,20 +68,12 @@ int ustctl_disable(int sock, struct lttng_ust_object_data *object); int ustctl_start_session(int sock, int handle); int ustctl_stop_session(int sock, int handle); -/* - * Return -LTTNG_UST_ERR_NOENT if no more stream is available for creation. - * Return 0 on success. - * Return negative error value on system error. - * Return positive error value on UST error. - */ -int ustctl_create_stream(int sock, struct lttng_ust_object_data *channel_data, - struct lttng_ust_object_data **stream_data); - /* * ustctl_tracepoint_list returns a tracepoint list handle, or negative * error value. */ int ustctl_tracepoint_list(int sock); + /* * ustctl_tracepoint_list_get is used to iterate on the tp list * handle. End is iteration is reached when -LTTNG_UST_ERR_NOENT is @@ -91,75 +103,89 @@ int ustctl_sock_flush_buffer(int sock, struct lttng_ust_object_data *object); int ustctl_calibrate(int sock, struct lttng_ust_calibrate *calibrate); +/* Release object created by members of this API. */ +int ustctl_release_object(int sock, struct lttng_ust_object_data *data); +/* Release handle returned by create session. */ +int ustctl_release_handle(int sock, int handle); + +int ustctl_recv_channel_from_consumer(int sock, + struct lttng_ust_object_data **channel_data); +int ustctl_recv_stream_from_consumer(int sock, + struct lttng_ust_object_data **stream_data); +int ustctl_send_channel_to_ust(int sock, int session_handle, + struct lttng_ust_object_data *channel_data); +int ustctl_send_stream_to_ust(int sock, + struct lttng_ust_object_data *channel_data, + struct lttng_ust_object_data *stream_data); + /* - * Map channel lttng_ust_shm_handle and add streams. Typically performed by the - * consumer to map the objects into its memory space. + * API used by consumer. */ -struct lttng_ust_shm_handle *ustctl_map_channel(struct lttng_ust_object_data *chan_data); -int ustctl_add_stream(struct lttng_ust_shm_handle *lttng_ust_shm_handle, - struct lttng_ust_object_data *stream_data); + +struct ustctl_consumer_channel; +struct ustctl_consumer_stream; +struct ustctl_consumer_channel_attr; + +struct ustctl_consumer_channel * + ustctl_create_channel(struct ustctl_consumer_channel_attr *attr); /* - * Note: the lttng_ust_object_data from which the lttng_ust_shm_handle is derived can only - * be released after unmapping the handle. + * Each stream created needs to be destroyed before calling + * ustctl_destroy_channel(). */ -void ustctl_unmap_channel(struct lttng_ust_shm_handle *lttng_ust_shm_handle); +void ustctl_destroy_channel(struct ustctl_consumer_channel *chan); -/* Buffer operations */ +int ustctl_send_channel_to_sessiond(int sock, + struct ustctl_consumer_channel *channel); +/* + * Send a NULL stream to finish iteration over all streams of a given + * channel. + */ +int ustctl_send_stream_to_sessiond(int sock, + struct ustctl_consumer_stream *stream); +int ustctl_stream_close_wait_fd(struct ustctl_consumer_stream *stream); +int ustctl_stream_close_wakeup_fd(struct ustctl_consumer_stream *stream); -struct lttng_ust_shm_handle; -struct lttng_ust_lib_ring_buffer; +/* Create/destroy stream buffers for read */ +struct ustctl_consumer_stream * + ustctl_create_stream(struct ustctl_consumer_channel *channel, + int cpu); +void ustctl_destroy_stream(struct ustctl_consumer_stream *stream); -/* Open/close stream buffers for read */ -struct lttng_ust_lib_ring_buffer *ustctl_open_stream_read(struct lttng_ust_shm_handle *handle, - int cpu); -void ustctl_close_stream_read(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf); +int ustctl_get_wait_fd(struct ustctl_consumer_stream *stream); +int ustctl_get_wakeup_fd(struct ustctl_consumer_stream *stream); /* For mmap mode, readable without "get" operation */ -int ustctl_get_mmap_len(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf, +int ustctl_get_mmap_len(struct ustctl_consumer_stream *stream, unsigned long *len); -int ustctl_get_max_subbuf_size(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf, +int ustctl_get_max_subbuf_size(struct ustctl_consumer_stream *stream, unsigned long *len); /* * For mmap mode, operate on the current packet (between get/put or * get_next/put_next). */ -void *ustctl_get_mmap_base(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf); -int ustctl_get_mmap_read_offset(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf, unsigned long *off); -int ustctl_get_subbuf_size(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf, unsigned long *len); -int ustctl_get_padded_subbuf_size(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf, unsigned long *len); -int ustctl_get_next_subbuf(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf); -int ustctl_put_next_subbuf(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf); +void *ustctl_get_mmap_base(struct ustctl_consumer_stream *stream); +int ustctl_get_mmap_read_offset(struct ustctl_consumer_stream *stream, + unsigned long *off); +int ustctl_get_subbuf_size(struct ustctl_consumer_stream *stream, + unsigned long *len); +int ustctl_get_padded_subbuf_size(struct ustctl_consumer_stream *stream, + unsigned long *len); +int ustctl_get_next_subbuf(struct ustctl_consumer_stream *stream); +int ustctl_put_next_subbuf(struct ustctl_consumer_stream *stream); /* snapshot */ -int ustctl_snapshot(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf); -int ustctl_snapshot_get_consumed(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf, unsigned long *pos); -int ustctl_snapshot_get_produced(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf, unsigned long *pos); -int ustctl_get_subbuf(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf, unsigned long *pos); -int ustctl_put_subbuf(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf); - -void ustctl_flush_buffer(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf, - int producer_active); +int ustctl_snapshot(struct ustctl_consumer_stream *stream); +int ustctl_snapshot_get_consumed(struct ustctl_consumer_stream *stream, + unsigned long *pos); +int ustctl_snapshot_get_produced(struct ustctl_consumer_stream *stream, + unsigned long *pos); +int ustctl_get_subbuf(struct ustctl_consumer_stream *stream, + unsigned long *pos); +int ustctl_put_subbuf(struct ustctl_consumer_stream *stream); -/* Release object created by members of this API. */ -int ustctl_release_object(int sock, struct lttng_ust_object_data *data); -/* Release handle returned by create session. */ -int ustctl_release_handle(int sock, int handle); +void ustctl_flush_buffer(struct ustctl_consumer_stream *stream, + int producer_active); #endif /* _LTTNG_UST_CTL_H */ diff --git a/include/lttng/ust-error.h b/include/lttng/ust-error.h index 0c46c904..bf6b7f33 100644 --- a/include/lttng/ust-error.h +++ b/include/lttng/ust-error.h @@ -41,6 +41,7 @@ enum lttng_ust_error_code { LTTNG_UST_ERR_INVAL = 1027, /* Invalid argument */ LTTNG_UST_ERR_PERM = 1028, /* Permission denied */ LTTNG_UST_ERR_NOSYS = 1029, /* Not implemented */ + LTTNG_UST_ERR_EXITING = 1030, /* Process is exiting */ /* MUST be last element */ LTTNG_UST_ERR_NR, /* Last element */ diff --git a/include/lttng/ust-events.h b/include/lttng/ust-events.h index b5d75850..e755e0c6 100644 --- a/include/lttng/ust-events.h +++ b/include/lttng/ust-events.h @@ -375,25 +375,17 @@ struct lttng_ust_shm_handle; */ struct lttng_channel_ops { struct lttng_channel *(*channel_create)(const char *name, - 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, - struct lttng_channel *chan_priv_init); - void (*channel_destroy)(struct lttng_channel *lttng_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, - uint64_t **memory_map_size); - void (*buffer_read_close)(struct lttng_ust_lib_ring_buffer *buf, - struct lttng_ust_shm_handle *handle); + void *buf_addr, + size_t subbuf_size, size_t num_subbuf, + unsigned int switch_timer_interval, + unsigned int read_timer_interval, + unsigned char *uuid); + void (*channel_destroy)(struct lttng_channel *chan); int (*event_reserve)(struct lttng_ust_lib_ring_buffer_ctx *ctx, uint32_t event_id); void (*event_commit)(struct lttng_ust_lib_ring_buffer_ctx *ctx); - void (*event_write)(struct lttng_ust_lib_ring_buffer_ctx *ctx, const void *src, - size_t len); + void (*event_write)(struct lttng_ust_lib_ring_buffer_ctx *ctx, + const void *src, size_t len); /* * packet_avail_size returns the available size in the current * packet. Note that the size returned is only a hint, since it @@ -429,14 +421,14 @@ struct lttng_channel { unsigned int free_event_id; /* Next event ID to allocate */ unsigned int used_event_id; /* Max allocated event IDs */ struct cds_list_head node; /* Channel list in session */ - struct lttng_channel_ops *ops; + const struct lttng_channel_ops *ops; int header_type; /* 0: unset, 1: compact, 2: large */ struct lttng_ust_shm_handle *handle; /* shared-memory handle */ unsigned int metadata_dumped:1; - /* Channel ID, available for consumer too */ + /* Channel ID */ unsigned int id; - /* Copy of session UUID for consumer (availability through shm) */ + enum lttng_ust_chan_type type; unsigned char uuid[LTTNG_UST_UUID_LEN]; /* Trace session unique ID */ }; @@ -462,7 +454,6 @@ struct lttng_session { struct cds_list_head _deprecated1; struct cds_list_head node; /* Session list */ unsigned int free_chan_id; /* Next chan ID to allocate */ - unsigned char uuid[LTTNG_UST_UUID_LEN]; /* Trace session unique ID */ unsigned int metadata_dumped:1; /* New UST 2.1 */ @@ -475,6 +466,7 @@ struct lttng_transport { char *name; struct cds_list_head node; struct lttng_channel_ops ops; + const struct lttng_ust_lib_ring_buffer_config *client_config; }; struct lttng_session *lttng_session_create(void); @@ -491,13 +483,6 @@ struct lttng_channel *lttng_channel_create(struct lttng_session *session, int **shm_fd, int **wait_fd, uint64_t **memory_map_size, struct lttng_channel *chan_priv_init); -struct lttng_channel *lttng_global_channel_create(struct lttng_session *session, - int overwrite, 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 lttng_channel_enable(struct lttng_channel *channel); int lttng_channel_disable(struct lttng_channel *channel); diff --git a/include/ust-comm.h b/include/ust-comm.h index 0034f2aa..0eca73a9 100644 --- a/include/ust-comm.h +++ b/include/ust-comm.h @@ -107,11 +107,12 @@ extern int ustcomm_connect_unix_sock(const char *pathname); extern int ustcomm_accept_unix_sock(int sock); extern int ustcomm_listen_unix_sock(int sock); extern int ustcomm_close_unix_sock(int sock); -/* Send fd(s) over a unix socket. */ -extern ssize_t ustcomm_send_fds_unix_sock(int sock, void *buf, int *fds, - size_t nb_fd, size_t len); + extern ssize_t ustcomm_recv_unix_sock(int sock, void *buf, size_t len); extern ssize_t ustcomm_send_unix_sock(int sock, void *buf, size_t len); +extern ssize_t ustcomm_send_fds_unix_sock(int sock, int *fds, size_t nb_fd); +extern ssize_t ustcomm_recv_fds_unix_sock(int sock, int *fds, size_t nb_fd); + extern const char *ustcomm_get_readable_code(int code); extern int ustcomm_send_app_msg(int sock, struct ustcomm_ust_msg *lum); extern int ustcomm_recv_app_reply(int sock, struct ustcomm_ust_reply *lur, @@ -121,4 +122,10 @@ extern int ustcomm_send_app_cmd(int sock, struct ustcomm_ust_reply *lur); int ustcomm_recv_fd(int sock); +ssize_t ustcomm_recv_channel_from_sessiond(int sock, + void **chan_data, uint64_t len); +int ustcomm_recv_stream_from_sessiond(int sock, + uint64_t *memory_map_size, + int *shm_fd, int *wakeup_fd); + #endif /* _LTTNG_UST_COMM_H */ diff --git a/liblttng-ust-comm/lttng-ust-comm.c b/liblttng-ust-comm/lttng-ust-comm.c index db9910de..f4695676 100644 --- a/liblttng-ust-comm/lttng-ust-comm.c +++ b/liblttng-ust-comm/lttng-ust-comm.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2011 - David Goulet - * Copyright (C) 2011 - Mathieu Desnoyers + * Copyright (C) 2011-2013 - Mathieu Desnoyers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -32,11 +32,14 @@ #include #include +#include #include #define USTCOMM_CODE_OFFSET(code) \ (code == LTTNG_UST_OK ? 0 : (code - LTTNG_UST_ERR + 1)) +#define USTCOMM_MAX_SEND_FDS 4 + /* * Human readable error message. */ @@ -48,6 +51,7 @@ static const char *ustcomm_readable_code[] = { [ USTCOMM_CODE_OFFSET(LTTNG_UST_ERR_INVAL) ] = "Invalid argument", [ USTCOMM_CODE_OFFSET(LTTNG_UST_ERR_PERM) ] = "Permission denied", [ USTCOMM_CODE_OFFSET(LTTNG_UST_ERR_NOSYS) ] = "Not implemented", + [ USTCOMM_CODE_OFFSET(LTTNG_UST_ERR_EXITING) ] = "Process is exiting", }; /* @@ -70,9 +74,9 @@ const char *lttng_ust_strerror(int code) } /* - * ustcomm_connect_unix_sock + * ustcomm_connect_unix_sock * - * Connect to unix socket using the path name. + * Connect to unix socket using the path name. */ int ustcomm_connect_unix_sock(const char *pathname) { @@ -128,10 +132,10 @@ error: } /* - * ustcomm_accept_unix_sock + * ustcomm_accept_unix_sock * - * Do an accept(2) on the sock and return the - * new file descriptor. The socket MUST be bind(2) before. + * Do an accept(2) on the sock and return the + * new file descriptor. The socket MUST be bind(2) before. */ int ustcomm_accept_unix_sock(int sock) { @@ -149,10 +153,10 @@ int ustcomm_accept_unix_sock(int sock) } /* - * ustcomm_create_unix_sock + * ustcomm_create_unix_sock * - * Creates a AF_UNIX local socket using pathname - * bind the socket upon creation and return the fd. + * Creates a AF_UNIX local socket using pathname + * bind the socket upon creation and return the fd. */ int ustcomm_create_unix_sock(const char *pathname) { @@ -196,9 +200,9 @@ error: } /* - * ustcomm_listen_unix_sock + * ustcomm_listen_unix_sock * - * Make the socket listen using LTTNG_UST_COMM_MAX_LISTEN. + * Make the socket listen using LTTNG_UST_COMM_MAX_LISTEN. */ int ustcomm_listen_unix_sock(int sock) { @@ -214,11 +218,30 @@ int ustcomm_listen_unix_sock(int sock) } /* - * ustcomm_recv_unix_sock + * ustcomm_close_unix_sock + * + * Shutdown cleanly a unix socket. + */ +int ustcomm_close_unix_sock(int sock) +{ + int ret; + + ret = close(sock); + if (ret < 0) { + perror("close"); + ret = -errno; + } + + return ret; +} + +/* + * ustcomm_recv_unix_sock * - * Receive data of size len in put that data into - * the buf param. Using recvmsg API. - * Return the size of received data. + * Receive data of size len in put that data into + * the buf param. Using recvmsg API. + * Return the size of received data. + * Return 0 on orderly shutdown. */ ssize_t ustcomm_recv_unix_sock(int sock, void *buf, size_t len) { @@ -240,7 +263,7 @@ ssize_t ustcomm_recv_unix_sock(int sock, void *buf, size_t len) if (ret < 0) { int shutret; - if (errno != EPIPE) + if (errno != EPIPE && errno != ECONNRESET) perror("recvmsg"); ret = -errno; @@ -253,10 +276,10 @@ ssize_t ustcomm_recv_unix_sock(int sock, void *buf, size_t len) } /* - * ustcomm_send_unix_sock + * ustcomm_send_unix_sock * - * Send buf data of size len. Using sendmsg API. - * Return the size of sent data. + * Send buf data of size len. Using sendmsg API. + * Return the size of sent data. */ ssize_t ustcomm_send_unix_sock(int sock, void *buf, size_t len) { @@ -285,8 +308,8 @@ ssize_t ustcomm_send_unix_sock(int sock, void *buf, size_t len) if (ret < 0) { int shutret; - if (errno != EPIPE) - perror("recvmsg"); + if (errno != EPIPE && errno != ECONNRESET) + perror("sendmsg"); ret = -errno; shutret = shutdown(sock, SHUT_RDWR); @@ -298,29 +321,11 @@ ssize_t ustcomm_send_unix_sock(int sock, void *buf, size_t len) } /* - * ustcomm_close_unix_sock + * Send a message accompanied by fd(s) over a unix socket. * - * Shutdown cleanly a unix socket. + * Returns the size of data sent, or negative error value. */ -int ustcomm_close_unix_sock(int sock) -{ - int ret; - - ret = close(sock); - if (ret < 0) { - perror("close"); - ret = -errno; - } - - return ret; -} - -/* - * ustcomm_send_fds_unix_sock - * - * Send multiple fds on a unix socket. - */ -ssize_t ustcomm_send_fds_unix_sock(int sock, void *buf, int *fds, size_t nb_fd, size_t len) +ssize_t ustcomm_send_fds_unix_sock(int sock, int *fds, size_t nb_fd) { struct msghdr msg; struct cmsghdr *cmptr; @@ -328,14 +333,13 @@ ssize_t ustcomm_send_fds_unix_sock(int sock, void *buf, int *fds, size_t nb_fd, ssize_t ret = -1; unsigned int sizeof_fds = nb_fd * sizeof(int); char tmp[CMSG_SPACE(sizeof_fds)]; + char dummy = 0; memset(&msg, 0, sizeof(msg)); + memset(tmp, 0, CMSG_SPACE(sizeof_fds) * sizeof(char)); - /* - * Note: we currently only support sending a single FD per - * message. - */ - assert(nb_fd == 1); + if (nb_fd > USTCOMM_MAX_SEND_FDS) + return -EINVAL; msg.msg_control = (caddr_t)tmp; msg.msg_controllen = CMSG_LEN(sizeof_fds); @@ -348,27 +352,100 @@ ssize_t ustcomm_send_fds_unix_sock(int sock, void *buf, int *fds, size_t nb_fd, /* Sum of the length of all control messages in the buffer: */ msg.msg_controllen = cmptr->cmsg_len; - iov[0].iov_base = buf; - iov[0].iov_len = len; + iov[0].iov_base = &dummy; + iov[0].iov_len = 1; msg.msg_iov = iov; msg.msg_iovlen = 1; do { - ret = sendmsg(sock, &msg, MSG_NOSIGNAL); + ret = sendmsg(sock, &msg, 0); } while (ret < 0 && errno == EINTR); - if (ret < 0) { - int shutret; + /* + * We consider EPIPE and ECONNRESET as expected. + */ + if (errno != EPIPE && errno != ECONNRESET) { + perror("sendmsg"); + } + } + return ret; +} - if (errno != EPIPE) - perror("recvmsg"); - ret = -errno; +/* + * Recv a message accompanied by fd(s) from a unix socket. + * + * Returns the size of received data, or negative error value. + * + * Expect at most "nb_fd" file descriptors. Returns the number of fd + * actually received in nb_fd. + * Returns -EPIPE on orderly shutdown. + */ +ssize_t ustcomm_recv_fds_unix_sock(int sock, int *fds, size_t nb_fd) +{ + struct iovec iov[1]; + ssize_t ret = 0; + struct cmsghdr *cmsg; + size_t sizeof_fds = nb_fd * sizeof(int); + char recv_fd[CMSG_SPACE(sizeof_fds)]; + struct msghdr msg; + char dummy; - shutret = shutdown(sock, SHUT_RDWR); - if (shutret) - fprintf(stderr, "Socket shutdown error"); - } + memset(&msg, 0, sizeof(msg)); + /* Prepare to receive the structures */ + iov[0].iov_base = &dummy; + iov[0].iov_len = 1; + msg.msg_iov = iov; + msg.msg_iovlen = 1; + msg.msg_control = recv_fd; + msg.msg_controllen = sizeof(recv_fd); + + do { + ret = recvmsg(sock, &msg, 0); + } while (ret < 0 && errno == EINTR); + if (ret < 0) { + if (errno != EPIPE && errno != ECONNRESET) { + perror("recvmsg fds"); + } + if (errno == EPIPE || errno == ECONNRESET) + ret = -errno; + goto end; + } + if (ret == 0) { + /* orderly shutdown */ + ret = -EPIPE; + goto end; + } + if (ret != 1) { + fprintf(stderr, "Error: Received %zd bytes, expected %d\n", + ret, 1); + goto end; + } + if (msg.msg_flags & MSG_CTRUNC) { + fprintf(stderr, "Error: Control message truncated.\n"); + ret = -1; + goto end; + } + cmsg = CMSG_FIRSTHDR(&msg); + if (!cmsg) { + fprintf(stderr, "Error: Invalid control message header\n"); + ret = -1; + goto end; + } + if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { + fprintf(stderr, "Didn't received any fd\n"); + ret = -1; + goto end; + } + if (cmsg->cmsg_len != CMSG_LEN(sizeof_fds)) { + fprintf(stderr, "Error: Received %zu bytes of ancillary data, expected %zu\n", + (size_t) cmsg->cmsg_len, (size_t) CMSG_LEN(sizeof_fds)); + ret = -1; + goto end; + } + memcpy(fds, CMSG_DATA(cmsg), sizeof_fds); + ret = sizeof_fds; +end: return ret; } @@ -382,8 +459,6 @@ int ustcomm_send_app_msg(int sock, struct ustcomm_ust_msg *lum) break; default: if (len < 0) { - if (len == -ECONNRESET) - fprintf(stderr, "remote end closed connection\n"); return len; } else { fprintf(stderr, "incorrect message size: %zd\n", len); @@ -402,22 +477,26 @@ int ustcomm_recv_app_reply(int sock, struct ustcomm_ust_reply *lur, len = ustcomm_recv_unix_sock(sock, lur, sizeof(*lur)); switch (len) { case 0: /* orderly shutdown */ - return -EINVAL; + return -EPIPE; case sizeof(*lur): if (lur->handle != expected_handle) { - fprintf(stderr, "Unexpected result message handle\n"); + fprintf(stderr, "Unexpected result message handle: " + "expected: %u vs received: %u\n", + expected_handle, lur->handle); return -EINVAL; } if (lur->cmd != expected_cmd) { - fprintf(stderr, "Unexpected result message command\n"); + fprintf(stderr, "Unexpected result message command " + "expected: %u vs received: %u\n", + expected_cmd, lur->cmd); return -EINVAL; } return lur->ret_code; default: if (len < 0) { /* Transport level error */ - if (len == -ECONNRESET) - fprintf(stderr, "remote end closed connection\n"); + if (errno == EPIPE || errno == ECONNRESET) + len = -errno; return len; } else { fprintf(stderr, "incorrect message size: %zd\n", len); @@ -442,76 +521,62 @@ int ustcomm_send_app_cmd(int sock, } /* - * Receives a single fd from socket. - * - * Returns negative error value on error, or file descriptor number on - * success. + * chan_data is allocated internally if this function returns the + * expected var_len. */ -int ustcomm_recv_fd(int sock) +ssize_t ustcomm_recv_channel_from_sessiond(int sock, + void **_chan_data, uint64_t var_len) { - struct iovec iov[1]; - int ret = 0; - int data_fd; - struct cmsghdr *cmsg; - char recv_fd[CMSG_SPACE(sizeof(int))]; - struct msghdr msg; - union { - unsigned char vc[4]; - int vi; - } tmp; - int i; - - memset(&msg, 0, sizeof(msg)); - - /* Prepare to receive the structures */ - iov[0].iov_base = &data_fd; - iov[0].iov_len = sizeof(data_fd); - msg.msg_iov = iov; - msg.msg_iovlen = 1; - msg.msg_control = recv_fd; - msg.msg_controllen = sizeof(recv_fd); + void *chan_data; + ssize_t len; - do { - ret = recvmsg(sock, &msg, 0); - } while (ret < 0 && errno == EINTR); - if (ret < 0) { - if (errno != EPIPE) { - perror("recvmsg"); - } - ret = -errno; - goto end; - } - if (ret != sizeof(data_fd)) { - fprintf(stderr, "Received %d bytes, expected %zd", ret, sizeof(data_fd)); - ret = -EINVAL; - goto end; + if (var_len > LTTNG_UST_CHANNEL_DATA_MAX_LEN) { + len = -EINVAL; + goto error_check; } - cmsg = CMSG_FIRSTHDR(&msg); - if (!cmsg) { - fprintf(stderr, "Invalid control message header\n"); - ret = -EINVAL; - goto end; + /* Receive variable length data */ + chan_data = zmalloc(var_len); + if (!chan_data) { + len = -ENOMEM; + goto error_alloc; } - if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { - fprintf(stderr, "Didn't received any fd\n"); - ret = -EINVAL; - goto end; + len = ustcomm_recv_unix_sock(sock, chan_data, var_len); + if (len != var_len) { + goto error_recv; } - /* this is our fd */ - for (i = 0; i < sizeof(int); i++) - tmp.vc[i] = CMSG_DATA(cmsg)[i]; - ret = tmp.vi; - /* - * Useful for fd leak debug. - * fprintf(stderr, "received fd %d\n", ret); - */ -end: - if (ret < 0) { - int shutret; + *_chan_data = chan_data; + return len; + +error_recv: + free(chan_data); +error_alloc: +error_check: + return len; +} - shutret = shutdown(sock, SHUT_RDWR); - if (shutret) - fprintf(stderr, "Socket shutdown error"); +int ustcomm_recv_stream_from_sessiond(int sock, + uint64_t *memory_map_size, + int *shm_fd, int *wakeup_fd) +{ + ssize_t len; + int ret; + int fds[2]; + + /* recv shm fd and wakeup fd */ + len = ustcomm_recv_fds_unix_sock(sock, fds, 2); + if (len <= 0) { + if (len < 0) { + ret = len; + goto error; + } else { + ret = -EIO; + goto error; + } } + *shm_fd = fds[0]; + *wakeup_fd = fds[1]; + return 0; + +error: return ret; } diff --git a/liblttng-ust-ctl/Makefile.am b/liblttng-ust-ctl/Makefile.am index 42aee699..0fbc9496 100644 --- a/liblttng-ust-ctl/Makefile.am +++ b/liblttng-ust-ctl/Makefile.am @@ -3,7 +3,7 @@ AM_CFLAGS = -fno-strict-aliasing lib_LTLIBRARIES = liblttng-ust-ctl.la -liblttng_ust_ctl_la_SOURCES = ustctl.c +liblttng_ust_ctl_la_SOURCES = ustctl.c ust-ctl-private.h liblttng_ust_ctl_la_LDFLAGS = \ -version-info $(LTTNG_UST_CTL_LIBRARY_VERSION) diff --git a/liblttng-ust-ctl/ust-ctl-private.h b/liblttng-ust-ctl/ust-ctl-private.h new file mode 100644 index 00000000..0f2e0bbe --- /dev/null +++ b/liblttng-ust-ctl/ust-ctl-private.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2011 - Julien Desfossez + * Copyright (C) 2011-2013 - Mathieu Desnoyers + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License only. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _LTTNG_UST_CTL_PRIVATE_H +#define _LTTNG_UST_CTL_PRIVATE_H + +#include + +/* + * Map channel lttng_ust_shm_handle and add streams. Typically performed + * by the application to map the objects into its memory space. + */ +struct lttng_ust_shm_handle * + ustctl_map_channel(struct lttng_ust_object_data *chan_data); +int ustctl_add_stream(struct lttng_ust_shm_handle *lttng_ust_shm_handle, + struct lttng_ust_object_data *stream_data); +/* + * Note: the lttng_ust_object_data from which the lttng_ust_shm_handle + * is derived can only be released after unmapping the handle. + */ +void ustctl_unmap_channel(struct lttng_ust_shm_handle *lttng_ust_shm_handle); + +#endif /* _LTTNG_UST_CTL_PRIVATE_H */ diff --git a/liblttng-ust-ctl/ustctl.c b/liblttng-ust-ctl/ustctl.c index d443a297..aed40f26 100644 --- a/liblttng-ust-ctl/ustctl.c +++ b/liblttng-ust-ctl/ustctl.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2011 - Julien Desfossez - * Mathieu Desnoyers + * Copyright (C) 2011-2013 - Mathieu Desnoyers * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,37 +25,55 @@ #include #include +#include #include "../libringbuffer/backend.h" #include "../libringbuffer/frontend.h" -volatile enum ust_loglevel ust_loglevel; +/* + * Channel representation within consumer. + */ +struct ustctl_consumer_channel { + struct lttng_channel *chan; /* lttng channel buffers */ -static -void init_object(struct lttng_ust_object_data *data) -{ - data->handle = -1; - data->shm_fd = -1; - data->wait_fd = -1; - data->memory_map_size = 0; -} + /* initial attributes */ + struct ustctl_consumer_channel_attr attr; +}; + +/* + * Stream representation within consumer. + */ +struct ustctl_consumer_stream { + struct lttng_ust_shm_handle *handle; /* shared-memory handle */ + struct lttng_ust_lib_ring_buffer *buf; + struct ustctl_consumer_channel *chan; + int shm_fd, wait_fd, wakeup_fd; + int cpu; + uint64_t memory_map_size; +}; + +extern void lttng_ring_buffer_client_overwrite_init(void); +extern void lttng_ring_buffer_client_discard_init(void); +extern void lttng_ring_buffer_metadata_client_init(void); +extern void lttng_ring_buffer_client_overwrite_exit(void); +extern void lttng_ring_buffer_client_discard_exit(void); +extern void lttng_ring_buffer_metadata_client_exit(void); + +volatile enum ust_loglevel ust_loglevel; int ustctl_release_handle(int sock, int handle) { struct ustcomm_ust_msg lum; struct ustcomm_ust_reply lur; - int ret; - if (sock >= 0) { - memset(&lum, 0, sizeof(lum)); - lum.handle = handle; - lum.cmd = LTTNG_UST_RELEASE; - ret = ustcomm_send_app_cmd(sock, &lum, &lur); - if (ret) - return ret; - } - return 0; + if (sock < 0 || handle < 0) + return 0; + memset(&lum, 0, sizeof(lum)); + lum.handle = handle; + lum.cmd = LTTNG_UST_RELEASE; + return ustcomm_send_app_cmd(sock, &lum, &lur); } + /* * If sock is negative, it means we don't have to notify the other side * (e.g. application has already vanished). @@ -67,19 +85,28 @@ int ustctl_release_object(int sock, struct lttng_ust_object_data *data) if (!data) return -EINVAL; - if (data->shm_fd >= 0) { - ret = close(data->shm_fd); - if (ret < 0) { - ret = -errno; - return ret; + switch (data->type) { + case LTTNG_UST_OBJECT_TYPE_CHANNEL: + free(data->u.channel.data); + break; + case LTTNG_UST_OBJECT_TYPE_STREAM: + if (data->u.stream.shm_fd >= 0) { + ret = close(data->u.stream.shm_fd); + if (ret < 0) { + ret = -errno; + return ret; + } } - } - if (data->wait_fd >= 0) { - ret = close(data->wait_fd); - if (ret < 0) { - ret = -errno; - return ret; + if (data->u.stream.wakeup_fd >= 0) { + ret = close(data->u.stream.wakeup_fd); + if (ret < 0) { + ret = -errno; + return ret; + } } + break; + default: + assert(0); } return ustctl_release_handle(sock, data->handle); } @@ -124,188 +151,6 @@ int ustctl_create_session(int sock) return session_handle; } -/* open the metadata global channel */ -int ustctl_open_metadata(int sock, int session_handle, - struct lttng_ust_channel_attr *chops, - struct lttng_ust_object_data **_metadata_data) -{ - struct ustcomm_ust_msg lum; - struct ustcomm_ust_reply lur; - struct lttng_ust_object_data *metadata_data; - int ret, err = 0; - - if (!chops || !_metadata_data) - return -EINVAL; - - metadata_data = malloc(sizeof(*metadata_data)); - if (!metadata_data) - return -ENOMEM; - init_object(metadata_data); - /* Create metadata channel */ - memset(&lum, 0, sizeof(lum)); - lum.handle = session_handle; - lum.cmd = LTTNG_UST_METADATA; - lum.u.channel.overwrite = chops->overwrite; - lum.u.channel.subbuf_size = chops->subbuf_size; - lum.u.channel.num_subbuf = chops->num_subbuf; - lum.u.channel.switch_timer_interval = chops->switch_timer_interval; - lum.u.channel.read_timer_interval = chops->read_timer_interval; - lum.u.channel.output = chops->output; - ret = ustcomm_send_app_cmd(sock, &lum, &lur); - if (ret) { - free(metadata_data); - return ret; - } - 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) - err = ret; - else - metadata_data->shm_fd = ret; - /* - * 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) - err = ret; - else - metadata_data->wait_fd = ret; - if (err) - goto error; - *_metadata_data = metadata_data; - return 0; - -error: - (void) ustctl_release_object(sock, metadata_data); - free(metadata_data); - return err; -} - -int ustctl_create_channel(int sock, int session_handle, - struct lttng_ust_channel_attr *chops, - struct lttng_ust_object_data **_channel_data) -{ - struct ustcomm_ust_msg lum; - struct ustcomm_ust_reply lur; - struct lttng_ust_object_data *channel_data; - int ret, err = 0; - - if (!chops || !_channel_data) - return -EINVAL; - - channel_data = malloc(sizeof(*channel_data)); - if (!channel_data) - return -ENOMEM; - init_object(channel_data); - /* Create metadata channel */ - memset(&lum, 0, sizeof(lum)); - lum.handle = session_handle; - lum.cmd = LTTNG_UST_CHANNEL; - lum.u.channel.overwrite = chops->overwrite; - lum.u.channel.subbuf_size = chops->subbuf_size; - lum.u.channel.num_subbuf = chops->num_subbuf; - lum.u.channel.switch_timer_interval = chops->switch_timer_interval; - lum.u.channel.read_timer_interval = chops->read_timer_interval; - lum.u.channel.output = chops->output; - ret = ustcomm_send_app_cmd(sock, &lum, &lur); - if (ret) { - free(channel_data); - return ret; - } - 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) - err = ret; - else - channel_data->shm_fd = ret; - /* - * 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) - err = ret; - else - channel_data->wait_fd = ret; - if (err) - goto error; - *_channel_data = channel_data; - return 0; - -error: - (void) ustctl_release_object(sock, channel_data); - free(channel_data); - return err; -} - -/* - * Return -LTTNG_UST_ERR_NOENT if no more stream is available for creation. - * Return 0 on success. - * Return negative error value on system error. - * Return positive error value on UST error. - */ -int ustctl_create_stream(int sock, struct lttng_ust_object_data *channel_data, - struct lttng_ust_object_data **_stream_data) -{ - struct ustcomm_ust_msg lum; - struct ustcomm_ust_reply lur; - struct lttng_ust_object_data *stream_data; - int ret, fd, err = 0; - - if (!channel_data || !_stream_data) - return -EINVAL; - - stream_data = malloc(sizeof(*stream_data)); - if (!stream_data) - return -ENOMEM; - init_object(stream_data); - memset(&lum, 0, sizeof(lum)); - lum.handle = channel_data->handle; - lum.cmd = LTTNG_UST_STREAM; - ret = ustcomm_send_app_cmd(sock, &lum, &lur); - if (ret) { - free(stream_data); - return ret; - } - 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) - err = fd; - else - stream_data->shm_fd = fd; - /* - * 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) - err = fd; - else - stream_data->wait_fd = fd; - if (err) - goto error; - *_stream_data = stream_data; - return ret; - -error: - (void) ustctl_release_object(sock, stream_data); - free(stream_data); - return err; -} - int ustctl_create_event(int sock, struct lttng_ust_event *ev, struct lttng_ust_object_data *channel_data, struct lttng_ust_object_data **_event_data) @@ -318,10 +163,9 @@ int ustctl_create_event(int sock, struct lttng_ust_event *ev, if (!channel_data || !_event_data) return -EINVAL; - event_data = malloc(sizeof(*event_data)); + event_data = zmalloc(sizeof(*event_data)); if (!event_data) return -ENOMEM; - init_object(event_data); memset(&lum, 0, sizeof(lum)); lum.handle = channel_data->handle; lum.cmd = LTTNG_UST_EVENT; @@ -353,10 +197,9 @@ int ustctl_add_context(int sock, struct lttng_ust_context *ctx, if (!obj_data || !_context_data) return -EINVAL; - context_data = malloc(sizeof(*context_data)); + context_data = zmalloc(sizeof(*context_data)); if (!context_data) return -ENOMEM; - init_object(context_data); memset(&lum, 0, sizeof(lum)); lum.handle = obj_data->handle; lum.cmd = LTTNG_UST_CONTEXT; @@ -610,200 +453,516 @@ int ustctl_sock_flush_buffer(int sock, struct lttng_ust_object_data *object) return 0; } -/* Buffer operations */ +static +int ustctl_send_channel(int sock, + enum lttng_ust_chan_type type, + void *data, + uint64_t size, + int send_fd_only) +{ + ssize_t len; + + if (!send_fd_only) { + /* Send mmap size */ + len = ustcomm_send_unix_sock(sock, &size, sizeof(size)); + if (len != sizeof(size)) { + if (len < 0) + return len; + else + return -EIO; + } + + /* Send channel type */ + len = ustcomm_send_unix_sock(sock, &type, sizeof(type)); + if (len != sizeof(type)) { + if (len < 0) + return len; + else + return -EIO; + } + } + + /* Send channel data */ + len = ustcomm_send_unix_sock(sock, data, size); + if (len != size) { + if (len < 0) + return len; + else + return -EIO; + } -/* Map channel shm into process memory */ -struct lttng_ust_shm_handle *ustctl_map_channel(struct lttng_ust_object_data *chan_data) + return 0; +} + +static +int ustctl_send_stream(int sock, + uint32_t stream_nr, + uint64_t memory_map_size, + int shm_fd, int wakeup_fd, + int send_fd_only) { - struct lttng_ust_shm_handle *handle; - struct channel *chan; - size_t chan_size; - struct lttng_ust_lib_ring_buffer_config *config; + ssize_t len; + int fds[2]; + + if (!send_fd_only) { + if (shm_fd < 0) { + /* finish iteration */ + uint64_t v = -1; + + len = ustcomm_send_unix_sock(sock, &v, sizeof(v)); + if (len != sizeof(v)) { + if (len < 0) + return len; + else + return -EIO; + } + return 0; + } + + /* Send mmap size */ + len = ustcomm_send_unix_sock(sock, &memory_map_size, + sizeof(memory_map_size)); + if (len != sizeof(memory_map_size)) { + if (len < 0) + return len; + else + return -EIO; + } + + /* Send stream nr */ + len = ustcomm_send_unix_sock(sock, &stream_nr, + sizeof(stream_nr)); + if (len != sizeof(stream_nr)) { + if (len < 0) + return len; + else + return -EIO; + } + } + + /* Send shm fd and wakeup fd */ + fds[0] = shm_fd; + fds[1] = wakeup_fd; + len = ustcomm_send_fds_unix_sock(sock, fds, 2); + if (len <= 0) { + if (len < 0) + return len; + else + return -EIO; + } + return 0; +} + +int ustctl_recv_channel_from_consumer(int sock, + struct lttng_ust_object_data **_channel_data) +{ + struct lttng_ust_object_data *channel_data; + ssize_t len; int ret; - if (!chan_data) - return NULL; + channel_data = zmalloc(sizeof(*channel_data)); + if (!channel_data) { + ret = -ENOMEM; + goto error_alloc; + } + channel_data->type = LTTNG_UST_OBJECT_TYPE_CHANNEL; + + /* recv mmap size */ + len = ustcomm_recv_unix_sock(sock, &channel_data->size, + sizeof(channel_data->size)); + if (len != sizeof(channel_data->size)) { + if (len < 0) + ret = len; + else + ret = -EINVAL; + goto error; + } - handle = channel_handle_create(chan_data->shm_fd, - chan_data->wait_fd, - chan_data->memory_map_size); - if (!handle) { - ERR("create handle error"); - return NULL; + /* recv channel type */ + len = ustcomm_recv_unix_sock(sock, &channel_data->u.channel.type, + sizeof(channel_data->u.channel.type)); + if (len != sizeof(channel_data->u.channel.type)) { + if (len < 0) + ret = len; + else + ret = -EINVAL; + goto error; + } + + /* recv channel data */ + channel_data->u.channel.data = zmalloc(channel_data->size); + if (!channel_data->u.channel.data) { + ret = -ENOMEM; + goto error; + } + len = ustcomm_recv_unix_sock(sock, channel_data->u.channel.data, + channel_data->size); + if (len != channel_data->size) { + if (len < 0) + ret = len; + else + ret = -EINVAL; + goto error_recv_data; + } + + *_channel_data = channel_data; + return 0; + +error_recv_data: + free(channel_data->u.channel.data); +error: + free(channel_data); +error_alloc: + return ret; +} + +int ustctl_recv_stream_from_consumer(int sock, + struct lttng_ust_object_data **_stream_data) +{ + struct lttng_ust_object_data *stream_data; + ssize_t len; + int ret; + int fds[2]; + + stream_data = zmalloc(sizeof(*stream_data)); + if (!stream_data) { + ret = -ENOMEM; + goto error_alloc; } - /* - * Set to -1, and then close the shm fd, and set the handle shm - * fd to -1 too. We don't need the shm fds after they have been - * mapped. - * The wait_fd is set to -1 in chan_data because it is now owned - * by the handle. - */ - chan_data->shm_fd = -1; - chan_data->wait_fd = -1; - - /* chan is object 0. This is hardcoded. */ - if (handle->table->objects[0].shm_fd >= 0) { - ret = close(handle->table->objects[0].shm_fd); - if (ret) { - perror("Error closing shm_fd"); + + stream_data->type = LTTNG_UST_OBJECT_TYPE_STREAM; + stream_data->handle = -1; + + /* recv mmap size */ + len = ustcomm_recv_unix_sock(sock, &stream_data->size, + sizeof(stream_data->size)); + if (len != sizeof(stream_data->size)) { + if (len < 0) + ret = len; + else + ret = -EINVAL; + goto error; + } + if (stream_data->size == -1) { + ret = -LTTNG_UST_ERR_NOENT; + goto error; + } + + /* recv stream nr */ + len = ustcomm_recv_unix_sock(sock, &stream_data->u.stream.stream_nr, + sizeof(stream_data->u.stream.stream_nr)); + if (len != sizeof(stream_data->u.stream.stream_nr)) { + if (len < 0) + ret = len; + else + ret = -EINVAL; + goto error; + } + + /* recv shm fd and wakeup fd */ + len = ustcomm_recv_fds_unix_sock(sock, fds, 2); + if (len <= 0) { + if (len < 0) { + ret = len; + goto error; + } else { + ret = -EIO; + goto error; } - handle->table->objects[0].shm_fd = -1; } + stream_data->u.stream.shm_fd = fds[0]; + stream_data->u.stream.wakeup_fd = fds[1]; + *_stream_data = stream_data; + return 0; - /* - * TODO: add consistency checks to be resilient if the - * application try to feed us with incoherent channel structure - * values. - */ - chan = shmp(handle, handle->chan); - /* chan is object 0. This is hardcoded. */ - chan_size = handle->table->objects[0].allocated_len; - handle->shadow_chan = malloc(chan_size); - if (!handle->shadow_chan) { - channel_destroy(chan, handle, 1); - return NULL; +error: + free(stream_data); +error_alloc: + return ret; +} + +int ustctl_send_channel_to_ust(int sock, int session_handle, + struct lttng_ust_object_data *channel_data) +{ + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + int ret; + + if (!channel_data) + return -EINVAL; + + memset(&lum, 0, sizeof(lum)); + lum.handle = session_handle; + lum.cmd = LTTNG_UST_CHANNEL; + lum.u.channel.len = channel_data->size; + lum.u.channel.type = channel_data->u.channel.type; + ret = ustcomm_send_app_msg(sock, &lum); + if (ret) + return ret; + + ret = ustctl_send_channel(sock, + channel_data->u.channel.type, + channel_data->u.channel.data, + channel_data->size, + 1); + if (ret) + return ret; + ret = ustcomm_recv_app_reply(sock, &lur, lum.handle, lum.cmd); + if (!ret) { + if (lur.ret_val >= 0) { + channel_data->handle = lur.ret_val; + } } - memcpy(handle->shadow_chan, chan, chan_size); - /* - * The callback pointers in the producer are invalid in the - * consumer. We need to look them up here. - */ - config = &handle->shadow_chan->backend.config; - switch (config->client_type) { - case LTTNG_CLIENT_METADATA: - memcpy(&config->cb, lttng_client_callbacks_metadata, - sizeof(config->cb)); - break; - case LTTNG_CLIENT_DISCARD: - memcpy(&config->cb, lttng_client_callbacks_discard, - sizeof(config->cb)); + return ret; +} + +int ustctl_send_stream_to_ust(int sock, + struct lttng_ust_object_data *channel_data, + struct lttng_ust_object_data *stream_data) +{ + struct ustcomm_ust_msg lum; + struct ustcomm_ust_reply lur; + int ret; + + memset(&lum, 0, sizeof(lum)); + lum.handle = channel_data->handle; + lum.cmd = LTTNG_UST_STREAM; + lum.u.stream.len = stream_data->size; + lum.u.stream.stream_nr = stream_data->u.stream.stream_nr; + ret = ustcomm_send_app_msg(sock, &lum); + if (ret) + return ret; + + assert(stream_data); + assert(stream_data->type == LTTNG_UST_OBJECT_TYPE_STREAM); + + ret = ustctl_send_stream(sock, + stream_data->u.stream.stream_nr, + stream_data->size, + stream_data->u.stream.shm_fd, + stream_data->u.stream.wakeup_fd, 1); + if (ret) + return ret; + return ustcomm_recv_app_reply(sock, &lur, lum.handle, lum.cmd); +} + + +/* Buffer operations */ + +struct ustctl_consumer_channel * + ustctl_create_channel(struct ustctl_consumer_channel_attr *attr) +{ + struct ustctl_consumer_channel *chan; + const char *transport_name; + struct lttng_transport *transport; + + switch (attr->type) { + case LTTNG_UST_CHAN_PER_CPU: + if (attr->output == LTTNG_UST_MMAP) { + transport_name = attr->overwrite ? + "relay-overwrite-mmap" : "relay-discard-mmap"; + } else { + return NULL; + } break; - case LTTNG_CLIENT_OVERWRITE: - memcpy(&config->cb, lttng_client_callbacks_overwrite, - sizeof(config->cb)); + case LTTNG_UST_CHAN_METADATA: + if (attr->output == LTTNG_UST_MMAP) + transport_name = "relay-metadata-mmap"; + else + return NULL; break; default: - ERR("Unknown client type %d", config->client_type); - channel_destroy(chan, handle, 1); - free(handle->shadow_chan); + transport_name = ""; return NULL; } - /* Replace the object table pointer. */ - ret = munmap(handle->table->objects[0].memory_map, - handle->table->objects[0].memory_map_size); - if (ret) { - perror("munmap"); - assert(0); + + transport = lttng_transport_find(transport_name); + if (!transport) { + DBG("LTTng transport %s not found\n", + transport_name); + return NULL; } - handle->table->objects[0].memory_map = (char *) handle->shadow_chan; - handle->table->objects[0].is_shadow = 1; - return handle; + + chan = zmalloc(sizeof(*chan)); + if (!chan) + return NULL; + + chan->chan = transport->ops.channel_create(transport_name, NULL, + attr->subbuf_size, attr->num_subbuf, + attr->switch_timer_interval, + attr->read_timer_interval, + attr->uuid); + if (!chan->chan) { + goto chan_error; + } + chan->chan->ops = &transport->ops; + memcpy(&chan->attr, attr, sizeof(chan->attr)); + return chan; + +chan_error: + free(chan); + return NULL; } -/* Add stream to channel shm and map its shm into process memory */ -int ustctl_add_stream(struct lttng_ust_shm_handle *handle, - struct lttng_ust_object_data *stream_data) +void ustctl_destroy_channel(struct ustctl_consumer_channel *chan) { - int ret; + chan->chan->ops->channel_destroy(chan->chan); + free(chan); +} + +int ustctl_send_channel_to_sessiond(int sock, + struct ustctl_consumer_channel *channel) +{ + struct shm_object_table *table; - if (!handle || !stream_data) + table = channel->chan->handle->table; + if (table->size <= 0) return -EINVAL; + return ustctl_send_channel(sock, + channel->attr.type, + table->objects[0].memory_map, + table->objects[0].memory_map_size, + 0); +} - if (!stream_data->handle) - return -ENOENT; - /* map stream */ - ret = channel_handle_add_stream(handle, - stream_data->shm_fd, - stream_data->wait_fd, - stream_data->memory_map_size); - if (ret) { - ERR("add stream error\n"); - return ret; - } - /* - * Set to -1 because the lttng_ust_shm_handle destruction will take care - * of closing shm_fd and wait_fd. - */ - stream_data->shm_fd = -1; - stream_data->wait_fd = -1; - return 0; +int ustctl_send_stream_to_sessiond(int sock, + struct ustctl_consumer_stream *stream) +{ + if (!stream) + return ustctl_send_stream(sock, -1U, -1U, -1, -1, 0); + + return ustctl_send_stream(sock, + stream->cpu, + stream->memory_map_size, + stream->shm_fd, stream->wakeup_fd, + 0); } -void ustctl_unmap_channel(struct lttng_ust_shm_handle *handle) +int ustctl_stream_close_wait_fd(struct ustctl_consumer_stream *stream) { struct channel *chan; - assert(handle); - chan = shmp(handle, handle->chan); - channel_destroy(chan, handle, 1); - free(handle->shadow_chan); + chan = stream->chan->chan->chan; + return ring_buffer_close_wait_fd(&chan->backend.config, + chan, stream->handle, stream->cpu); } -/* - * ustctl closes the shm_fd fds after mapping it. - */ -struct lttng_ust_lib_ring_buffer *ustctl_open_stream_read(struct lttng_ust_shm_handle *handle, - int cpu) +int ustctl_stream_close_wakeup_fd(struct ustctl_consumer_stream *stream) { struct channel *chan; - int *shm_fd, *wait_fd; - uint64_t *memory_map_size; + + chan = stream->chan->chan->chan; + return ring_buffer_close_wakeup_fd(&chan->backend.config, + chan, stream->handle, stream->cpu); +} + +struct ustctl_consumer_stream * + ustctl_create_stream(struct ustctl_consumer_channel *channel, + int cpu) +{ + struct ustctl_consumer_stream *stream; + struct lttng_ust_shm_handle *handle; + struct channel *chan; + int shm_fd, wait_fd, wakeup_fd; + uint64_t memory_map_size; struct lttng_ust_lib_ring_buffer *buf; int ret; + if (!channel) + return NULL; + handle = channel->chan->handle; if (!handle) return NULL; - chan = handle->shadow_chan; + chan = channel->chan->chan; buf = channel_get_ring_buffer(&chan->backend.config, - chan, cpu, handle, &shm_fd, &wait_fd, &memory_map_size); + chan, cpu, handle, &shm_fd, &wait_fd, + &wakeup_fd, &memory_map_size); if (!buf) return NULL; - ret = lib_ring_buffer_open_read(buf, handle, 1); + ret = lib_ring_buffer_open_read(buf, handle); if (ret) return NULL; - /* - * We can close shm_fd early, right after is has been mapped. - */ - if (*shm_fd >= 0) { - ret = close(*shm_fd); - if (ret) { - perror("Error closing shm_fd"); - } - *shm_fd = -1; - } - return buf; + + stream = zmalloc(sizeof(*stream)); + if (!stream) + goto alloc_error; + stream->handle = handle; + stream->buf = buf; + stream->chan = channel; + stream->shm_fd = shm_fd; + stream->wait_fd = wait_fd; + stream->wakeup_fd = wakeup_fd; + stream->memory_map_size = memory_map_size; + stream->cpu = cpu; + return stream; + +alloc_error: + return NULL; +} + +void ustctl_destroy_stream(struct ustctl_consumer_stream *stream) +{ + struct lttng_ust_lib_ring_buffer *buf; + struct ustctl_consumer_channel *consumer_chan; + + assert(stream); + buf = stream->buf; + consumer_chan = stream->chan; + lib_ring_buffer_release_read(buf, consumer_chan->chan->handle); + free(stream); } -void ustctl_close_stream_read(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf) +int ustctl_get_wait_fd(struct ustctl_consumer_stream *stream) { - assert(handle && buf); - lib_ring_buffer_release_read(buf, handle, 1); + struct lttng_ust_lib_ring_buffer *buf; + struct ustctl_consumer_channel *consumer_chan; + + if (!stream) + return -EINVAL; + buf = stream->buf; + consumer_chan = stream->chan; + return shm_get_wait_fd(consumer_chan->chan->handle, &buf->self._ref); +} + +int ustctl_get_wakeup_fd(struct ustctl_consumer_stream *stream) +{ + struct lttng_ust_lib_ring_buffer *buf; + struct ustctl_consumer_channel *consumer_chan; + + if (!stream) + return -EINVAL; + buf = stream->buf; + consumer_chan = stream->chan; + return shm_get_wakeup_fd(consumer_chan->chan->handle, &buf->self._ref); } /* For mmap mode, readable without "get" operation */ -void *ustctl_get_mmap_base(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf) +void *ustctl_get_mmap_base(struct ustctl_consumer_stream *stream) { - if (!handle || !buf) + struct lttng_ust_lib_ring_buffer *buf; + struct ustctl_consumer_channel *consumer_chan; + + if (!stream) return NULL; - return shmp(handle, buf->backend.memory_map); + buf = stream->buf; + consumer_chan = stream->chan; + return shmp(consumer_chan->chan->handle, buf->backend.memory_map); } /* returns the length to mmap. */ -int ustctl_get_mmap_len(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf, +int ustctl_get_mmap_len(struct ustctl_consumer_stream *stream, unsigned long *len) { + struct ustctl_consumer_channel *consumer_chan; unsigned long mmap_buf_len; struct channel *chan; - if (!handle || !buf || !len) + if (!stream) return -EINVAL; - - chan = handle->shadow_chan; + consumer_chan = stream->chan; + chan = consumer_chan->chan->chan; if (chan->backend.config.output != RING_BUFFER_MMAP) return -EINVAL; mmap_buf_len = chan->backend.buf_size; @@ -816,16 +975,16 @@ int ustctl_get_mmap_len(struct lttng_ust_shm_handle *handle, } /* returns the maximum size for sub-buffers. */ -int ustctl_get_max_subbuf_size(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf, +int ustctl_get_max_subbuf_size(struct ustctl_consumer_stream *stream, unsigned long *len) { + struct ustctl_consumer_channel *consumer_chan; struct channel *chan; - if (!handle || !buf || !len) + if (!stream) return -EINVAL; - - chan = handle->shadow_chan; + consumer_chan = stream->chan; + chan = consumer_chan->chan->chan; *len = chan->backend.subbuf_size; return 0; } @@ -836,139 +995,193 @@ int ustctl_get_max_subbuf_size(struct lttng_ust_shm_handle *handle, */ /* returns the offset of the subbuffer belonging to the mmap reader. */ -int ustctl_get_mmap_read_offset(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf, unsigned long *off) +int ustctl_get_mmap_read_offset(struct ustctl_consumer_stream *stream, + unsigned long *off) { struct channel *chan; unsigned long sb_bindex; + struct lttng_ust_lib_ring_buffer *buf; + struct ustctl_consumer_channel *consumer_chan; - if (!handle || !buf || !off) + if (!stream) return -EINVAL; - - chan = handle->shadow_chan; + buf = stream->buf; + consumer_chan = stream->chan; + chan = consumer_chan->chan->chan; if (chan->backend.config.output != RING_BUFFER_MMAP) return -EINVAL; sb_bindex = subbuffer_id_get_index(&chan->backend.config, buf->backend.buf_rsb.id); - *off = shmp(handle, shmp_index(handle, buf->backend.array, sb_bindex)->shmp)->mmap_offset; + *off = shmp(consumer_chan->chan->handle, + shmp_index(consumer_chan->chan->handle, buf->backend.array, sb_bindex)->shmp)->mmap_offset; return 0; } /* returns the size of the current sub-buffer, without padding (for mmap). */ -int ustctl_get_subbuf_size(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf, unsigned long *len) +int ustctl_get_subbuf_size(struct ustctl_consumer_stream *stream, + unsigned long *len) { + struct ustctl_consumer_channel *consumer_chan; struct channel *chan; + struct lttng_ust_lib_ring_buffer *buf; - if (!handle || !buf || !len) + if (!stream) return -EINVAL; - chan = handle->shadow_chan; + buf = stream->buf; + consumer_chan = stream->chan; + chan = consumer_chan->chan->chan; *len = lib_ring_buffer_get_read_data_size(&chan->backend.config, buf, - handle); + consumer_chan->chan->handle); return 0; } /* returns the size of the current sub-buffer, without padding (for mmap). */ -int ustctl_get_padded_subbuf_size(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf, unsigned long *len) +int ustctl_get_padded_subbuf_size(struct ustctl_consumer_stream *stream, + unsigned long *len) { + struct ustctl_consumer_channel *consumer_chan; struct channel *chan; + struct lttng_ust_lib_ring_buffer *buf; - if (!handle || !buf || !len) + if (!stream) return -EINVAL; - - chan = handle->shadow_chan; + buf = stream->buf; + consumer_chan = stream->chan; + chan = consumer_chan->chan->chan; *len = lib_ring_buffer_get_read_data_size(&chan->backend.config, buf, - handle); + consumer_chan->chan->handle); *len = PAGE_ALIGN(*len); return 0; } /* Get exclusive read access to the next sub-buffer that can be read. */ -int ustctl_get_next_subbuf(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf) +int ustctl_get_next_subbuf(struct ustctl_consumer_stream *stream) { - if (!handle || !buf) - return -EINVAL; + struct lttng_ust_lib_ring_buffer *buf; + struct ustctl_consumer_channel *consumer_chan; - return lib_ring_buffer_get_next_subbuf(buf, handle); + if (!stream) + return -EINVAL; + buf = stream->buf; + consumer_chan = stream->chan; + return lib_ring_buffer_get_next_subbuf(buf, + consumer_chan->chan->handle); } /* Release exclusive sub-buffer access, move consumer forward. */ -int ustctl_put_next_subbuf(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf) +int ustctl_put_next_subbuf(struct ustctl_consumer_stream *stream) { - if (!handle || !buf) - return -EINVAL; + struct lttng_ust_lib_ring_buffer *buf; + struct ustctl_consumer_channel *consumer_chan; - lib_ring_buffer_put_next_subbuf(buf, handle); + if (!stream) + return -EINVAL; + buf = stream->buf; + consumer_chan = stream->chan; + lib_ring_buffer_put_next_subbuf(buf, consumer_chan->chan->handle); return 0; } /* snapshot */ /* Get a snapshot of the current ring buffer producer and consumer positions */ -int ustctl_snapshot(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf) +int ustctl_snapshot(struct ustctl_consumer_stream *stream) { - if (!handle || !buf) - return -EINVAL; + struct lttng_ust_lib_ring_buffer *buf; + struct ustctl_consumer_channel *consumer_chan; + if (!stream) + return -EINVAL; + buf = stream->buf; + consumer_chan = stream->chan; return lib_ring_buffer_snapshot(buf, &buf->cons_snapshot, - &buf->prod_snapshot, handle); + &buf->prod_snapshot, consumer_chan->chan->handle); } /* Get the consumer position (iteration start) */ -int ustctl_snapshot_get_consumed(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf, unsigned long *pos) +int ustctl_snapshot_get_consumed(struct ustctl_consumer_stream *stream, + unsigned long *pos) { - if (!handle || !buf || !pos) - return -EINVAL; + struct lttng_ust_lib_ring_buffer *buf; + if (!stream) + return -EINVAL; + buf = stream->buf; *pos = buf->cons_snapshot; return 0; } /* Get the producer position (iteration end) */ -int ustctl_snapshot_get_produced(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf, unsigned long *pos) +int ustctl_snapshot_get_produced(struct ustctl_consumer_stream *stream, + unsigned long *pos) { - if (!handle || !buf || !pos) - return -EINVAL; + struct lttng_ust_lib_ring_buffer *buf; + if (!stream) + return -EINVAL; + buf = stream->buf; *pos = buf->prod_snapshot; return 0; } /* Get exclusive read access to the specified sub-buffer position */ -int ustctl_get_subbuf(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf, unsigned long *pos) +int ustctl_get_subbuf(struct ustctl_consumer_stream *stream, + unsigned long *pos) { - if (!handle || !buf || !pos) - return -EINVAL; + struct lttng_ust_lib_ring_buffer *buf; + struct ustctl_consumer_channel *consumer_chan; - return lib_ring_buffer_get_subbuf(buf, *pos, handle); + if (!stream) + return -EINVAL; + buf = stream->buf; + consumer_chan = stream->chan; + return lib_ring_buffer_get_subbuf(buf, *pos, + consumer_chan->chan->handle); } /* Release exclusive sub-buffer access */ -int ustctl_put_subbuf(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf) +int ustctl_put_subbuf(struct ustctl_consumer_stream *stream) { - if (!handle || !buf) - return -EINVAL; + struct lttng_ust_lib_ring_buffer *buf; + struct ustctl_consumer_channel *consumer_chan; - lib_ring_buffer_put_subbuf(buf, handle); + if (!stream) + return -EINVAL; + buf = stream->buf; + consumer_chan = stream->chan; + lib_ring_buffer_put_subbuf(buf, consumer_chan->chan->handle); return 0; } -void ustctl_flush_buffer(struct lttng_ust_shm_handle *handle, - struct lttng_ust_lib_ring_buffer *buf, +void ustctl_flush_buffer(struct ustctl_consumer_stream *stream, int producer_active) { - assert(handle && buf); + struct lttng_ust_lib_ring_buffer *buf; + struct ustctl_consumer_channel *consumer_chan; + + assert(stream); + buf = stream->buf; + consumer_chan = stream->chan; lib_ring_buffer_switch_slow(buf, producer_active ? SWITCH_ACTIVE : SWITCH_FLUSH, - handle); + consumer_chan->chan->handle); +} + +static __attribute__((constructor)) +void ustctl_init(void) +{ + init_usterr(); + lttng_ring_buffer_metadata_client_init(); + lttng_ring_buffer_client_overwrite_init(); + lttng_ring_buffer_client_discard_init(); +} + +static __attribute__((destructor)) +void ustctl_exit(void) +{ + lttng_ring_buffer_client_discard_exit(); + lttng_ring_buffer_client_overwrite_exit(); + lttng_ring_buffer_metadata_client_exit(); } diff --git a/liblttng-ust/Makefile.am b/liblttng-ust/Makefile.am index f8b334aa..86661c6b 100644 --- a/liblttng-ust/Makefile.am +++ b/liblttng-ust/Makefile.am @@ -40,8 +40,8 @@ liblttng_ust_runtime_la_SOURCES = \ compat.h \ wait.h \ jhash.h \ - error.h \ - lttng-ust-uuid.h + lttng-ust-uuid.h \ + error.h liblttng_ust_support_la_SOURCES = \ lttng-tracer.h \ @@ -69,11 +69,4 @@ liblttng_ust_la_LIBADD = \ $(top_builddir)/liblttng-ust-comm/liblttng-ust-comm.la \ liblttng-ust-runtime.la liblttng-ust-support.la -if LTTNG_UST_BUILD_WITH_LIBUUID -liblttng_ust_la_LIBADD += -luuid -endif -if LTTNG_UST_BUILD_WITH_LIBC_UUID -liblttng_ust_la_LIBADD += -lc -endif - liblttng_ust_la_CFLAGS = -DUST_COMPONENT="liblttng_ust" -fno-strict-aliasing diff --git a/liblttng-ust/lttng-events.c b/liblttng-ust/lttng-events.c index 8d316b27..90b23078 100644 --- a/liblttng-ust/lttng-events.c +++ b/liblttng-ust/lttng-events.c @@ -76,7 +76,6 @@ void ust_unlock(void) static CDS_LIST_HEAD(sessions); static void _lttng_event_destroy(struct lttng_event *event); -static void _lttng_channel_destroy(struct lttng_channel *chan); static int _lttng_event_unregister(struct lttng_event *event); static int _lttng_event_metadata_statedump(struct lttng_session *session, @@ -127,7 +126,7 @@ void synchronize_trace(void) struct lttng_session *lttng_session_create(void) { struct lttng_session *session; - int ret, i; + int i; session = zmalloc(sizeof(struct lttng_session)); if (!session) @@ -137,14 +136,30 @@ struct lttng_session *lttng_session_create(void) CDS_INIT_LIST_HEAD(&session->enablers_head); for (i = 0; i < LTTNG_UST_EVENT_HT_SIZE; i++) CDS_INIT_HLIST_HEAD(&session->events_ht.table[i]); - ret = lttng_ust_uuid_generate(session->uuid); - if (ret != 0) { - session->uuid[0] = '\0'; - } cds_list_add(&session->node, &sessions); return session; } +/* + * Only used internally at session destruction. + */ +static +void _lttng_channel_unmap(struct lttng_channel *lttng_chan) +{ + struct channel *chan; + struct lttng_ust_shm_handle *handle; + + cds_list_del(<tng_chan->node); + lttng_destroy_context(lttng_chan->ctx); + chan = lttng_chan->chan; + handle = lttng_chan->handle; + /* + * note: lttng_chan is private data contained within handle. It + * will be freed along with the handle. + */ + channel_destroy(chan, handle, 0); +} + void lttng_session_destroy(struct lttng_session *session) { struct lttng_channel *chan, *tmpchan; @@ -165,7 +180,7 @@ void lttng_session_destroy(struct lttng_session *session) &session->events_head, node) _lttng_event_destroy(event); cds_list_for_each_entry_safe(chan, tmpchan, &session->chan_head, node) - _lttng_channel_destroy(chan); + _lttng_channel_unmap(chan); cds_list_del(&session->node); free(session); } @@ -266,62 +281,6 @@ int lttng_event_disable(struct lttng_event *event) return 0; } -struct lttng_channel *lttng_channel_create(struct lttng_session *session, - const char *transport_name, - 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, - struct lttng_channel *chan_priv_init) -{ - struct lttng_channel *chan = NULL; - struct lttng_transport *transport; - - if (session->been_active) - goto active; /* Refuse to add channel to active session */ - transport = lttng_transport_find(transport_name); - if (!transport) { - DBG("LTTng transport %s not found\n", - transport_name); - goto notransport; - } - chan_priv_init->id = session->free_chan_id++; - chan_priv_init->session = session; - /* - * Note: the channel creation op already writes into the packet - * headers. Therefore the "chan" information used as input - * should be already accessible. - */ - 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); - if (!chan) - goto create_error; - chan->enabled = 1; - chan->ops = &transport->ops; - cds_list_add(&chan->node, &session->chan_head); - return chan; - -create_error: -notransport: -active: - return NULL; -} - -/* - * Only used internally at session destruction. - */ -static -void _lttng_channel_destroy(struct lttng_channel *chan) -{ - cds_list_del(&chan->node); - lttng_destroy_context(chan->ctx); - chan->ops->channel_destroy(chan); -} - /* * Supports event creation while tracing session is active. */ @@ -1088,7 +1047,7 @@ uint64_t measure_clock_offset(void) static int _lttng_session_metadata_statedump(struct lttng_session *session) { - unsigned char *uuid_c = session->uuid; + unsigned char *uuid_c; char uuid_s[LTTNG_UST_UUID_STR_LEN], clock_uuid_s[LTTNG_UST_UUID_STR_LEN]; struct lttng_channel *chan; @@ -1105,6 +1064,7 @@ int _lttng_session_metadata_statedump(struct lttng_session *session) DBG("LTTng: attempt to start tracing, but metadata channel is not found. Operation abort.\n"); return -EPERM; } + uuid_c = session->metadata->uuid; snprintf(uuid_s, sizeof(uuid_s), "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", @@ -1435,16 +1395,3 @@ void lttng_session_lazy_sync_enablers(struct lttng_session *session) return; lttng_session_sync_enablers(session); } - -/* - * Take the TLS "fault" in libuuid if dlopen'd, which can take the - * dynamic linker mutex, outside of the UST lock, since the UST lock is - * taken in constructors, which are called with dynamic linker mutex - * held. - */ -void lttng_fixup_event_tls(void) -{ - unsigned char uuid[LTTNG_UST_UUID_STR_LEN]; - - (void) lttng_ust_uuid_generate(uuid); -} diff --git a/liblttng-ust/lttng-ring-buffer-client.h b/liblttng-ust/lttng-ring-buffer-client.h index ad77802f..8c531cbf 100644 --- a/liblttng-ust/lttng-ring-buffer-client.h +++ b/liblttng-ust/lttng-ring-buffer-client.h @@ -24,7 +24,6 @@ #include #include "lttng/bitfield.h" #include "clock.h" -#include "lttng-ust-uuid.h" #include "lttng-tracer.h" #include "../libringbuffer/frontend_types.h" @@ -415,58 +414,32 @@ struct lttng_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, - uint64_t **memory_map_size, - struct lttng_channel *chan_priv_init) + unsigned char *uuid) { - void *priv; - struct lttng_channel *lttng_chan = NULL; + struct lttng_channel chan_priv_init; struct lttng_ust_shm_handle *handle; + struct lttng_channel *lttng_chan; + void *priv; + memset(&chan_priv_init, 0, sizeof(chan_priv_init)); + memcpy(chan_priv_init.uuid, uuid, LTTNG_UST_UUID_LEN); handle = channel_create(&client_config, name, &priv, __alignof__(*lttng_chan), sizeof(*lttng_chan), - chan_priv_init, + &chan_priv_init, buf_addr, subbuf_size, num_subbuf, - switch_timer_interval, read_timer_interval, - shm_fd, wait_fd, memory_map_size); + switch_timer_interval, read_timer_interval); if (!handle) return NULL; lttng_chan = priv; lttng_chan->handle = handle; - lttng_chan->chan = shmp(lttng_chan->handle, lttng_chan->handle->chan); + lttng_chan->chan = shmp(handle, handle->chan); return lttng_chan; } static -void lttng_channel_destroy(struct lttng_channel *lttng_chan) -{ - channel_destroy(lttng_chan->chan, lttng_chan->handle, 0); -} - -static -struct lttng_ust_lib_ring_buffer *lttng_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_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); - if (!lib_ring_buffer_open_read(buf, handle, 0)) - return buf; - } - return NULL; -} - -static -void lttng_buffer_read_close(struct lttng_ust_lib_ring_buffer *buf, - struct lttng_ust_shm_handle *handle) +void lttng_channel_destroy(struct lttng_channel *chan) { - lib_ring_buffer_release_read(buf, handle, 0); + channel_destroy(chan->chan, chan->handle, 1); } static @@ -551,12 +524,12 @@ int lttng_flush_buffer(struct channel *chan, struct lttng_ust_shm_handle *handle int cpu; for_each_channel_cpu(cpu, chan) { - int *shm_fd, *wait_fd; - uint64_t *memory_map_size; + int shm_fd, wait_fd, wakeup_fd; + uint64_t memory_map_size; buf = channel_get_ring_buffer(&client_config, chan, cpu, handle, &shm_fd, &wait_fd, - &memory_map_size); + &wakeup_fd, &memory_map_size); lib_ring_buffer_switch(&client_config, buf, SWITCH_ACTIVE, handle); } @@ -568,8 +541,6 @@ static struct lttng_transport lttng_relay_transport = { .ops = { .channel_create = _channel_create, .channel_destroy = lttng_channel_destroy, - .buffer_read_open = lttng_buffer_read_open, - .buffer_read_close = lttng_buffer_read_close, .event_reserve = lttng_event_reserve, .event_commit = lttng_event_commit, .event_write = lttng_event_write, @@ -580,6 +551,7 @@ static struct lttng_transport lttng_relay_transport = { .is_disabled = lttng_is_disabled, .flush_buffer = lttng_flush_buffer, }, + .client_config = &client_config, }; void RING_BUFFER_MODE_TEMPLATE_INIT(void) diff --git a/liblttng-ust/lttng-ring-buffer-metadata-client.h b/liblttng-ust/lttng-ring-buffer-metadata-client.h index 8bffe547..1e1b8a76 100644 --- a/liblttng-ust/lttng-ring-buffer-metadata-client.h +++ b/liblttng-ust/lttng-ring-buffer-metadata-client.h @@ -110,7 +110,6 @@ static void client_buffer_begin(struct lttng_ust_lib_ring_buffer *buf, uint64_t header->checksum_scheme = 0; /* 0 if unused */ header->major = CTF_SPEC_MAJOR; header->minor = CTF_SPEC_MINOR; - } /* @@ -183,54 +182,32 @@ struct lttng_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, - uint64_t **memory_map_size, - struct lttng_channel *chan_priv_init) + unsigned char *uuid) { - void *priv; - struct lttng_channel *lttng_chan = NULL; + struct lttng_channel chan_priv_init; struct lttng_ust_shm_handle *handle; + struct lttng_channel *lttng_chan; + void *priv; + memset(&chan_priv_init, 0, sizeof(chan_priv_init)); + memcpy(chan_priv_init.uuid, uuid, LTTNG_UST_UUID_LEN); handle = channel_create(&client_config, name, &priv, __alignof__(*lttng_chan), sizeof(*lttng_chan), - chan_priv_init, + &chan_priv_init, buf_addr, subbuf_size, num_subbuf, - switch_timer_interval, read_timer_interval, - shm_fd, wait_fd, memory_map_size); + switch_timer_interval, read_timer_interval); if (!handle) return NULL; lttng_chan = priv; lttng_chan->handle = handle; - lttng_chan->chan = shmp(lttng_chan->handle, lttng_chan->handle->chan); + lttng_chan->chan = shmp(handle, handle->chan); return lttng_chan; } static -void lttng_channel_destroy(struct lttng_channel *lttng_chan) -{ - channel_destroy(lttng_chan->chan, lttng_chan->handle, 0); -} - -static -struct lttng_ust_lib_ring_buffer *lttng_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_lib_ring_buffer *buf; - - 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, 0)) - return buf; - return NULL; -} - -static -void lttng_buffer_read_close(struct lttng_ust_lib_ring_buffer *buf, - struct lttng_ust_shm_handle *handle) +void lttng_channel_destroy(struct lttng_channel *chan) { - lib_ring_buffer_release_read(buf, handle, 0); + channel_destroy(chan->chan, chan->handle, 1); } static @@ -299,11 +276,11 @@ static int lttng_flush_buffer(struct channel *chan, struct lttng_ust_shm_handle *handle) { struct lttng_ust_lib_ring_buffer *buf; - int *shm_fd, *wait_fd; - uint64_t *memory_map_size; + int shm_fd, wait_fd, wakeup_fd; + uint64_t memory_map_size; buf = channel_get_ring_buffer(&client_config, chan, - 0, handle, &shm_fd, &wait_fd, + 0, handle, &shm_fd, &wait_fd, &wakeup_fd, &memory_map_size); lib_ring_buffer_switch(&client_config, buf, SWITCH_ACTIVE, handle); @@ -315,8 +292,6 @@ static struct lttng_transport lttng_relay_transport = { .ops = { .channel_create = _channel_create, .channel_destroy = lttng_channel_destroy, - .buffer_read_open = lttng_buffer_read_open, - .buffer_read_close = lttng_buffer_read_close, .event_reserve = lttng_event_reserve, .event_commit = lttng_event_commit, .event_write = lttng_event_write, @@ -327,6 +302,7 @@ static struct lttng_transport lttng_relay_transport = { .is_disabled = lttng_is_disabled, .flush_buffer = lttng_flush_buffer, }, + .client_config = &client_config, }; void RING_BUFFER_MODE_TEMPLATE_INIT(void) diff --git a/liblttng-ust/lttng-tracer-core.h b/liblttng-ust/lttng-tracer-core.h index 09289c33..f2e95674 100644 --- a/liblttng-ust/lttng-tracer-core.h +++ b/liblttng-ust/lttng-tracer-core.h @@ -41,4 +41,6 @@ void lttng_fixup_event_tls(void); void lttng_fixup_vtid_tls(void); void lttng_fixup_procname_tls(void); +const char *lttng_ust_obj_get_name(int id); + #endif /* _LTTNG_TRACER_CORE_H */ diff --git a/liblttng-ust/lttng-ust-abi.c b/liblttng-ust/lttng-ust-abi.c index 1985d018..006e9962 100644 --- a/liblttng-ust/lttng-ust-abi.c +++ b/liblttng-ust/lttng-ust-abi.c @@ -48,6 +48,8 @@ #include #include #include "lttng-tracer.h" +#include "../libringbuffer/shm.h" +#include "../libringbuffer/frontend_types.h" #define OBJ_NAME_LEN 16 @@ -218,6 +220,15 @@ void objd_table_destroy(void) objd_table.freelist_head = -1; } +const char *lttng_ust_obj_get_name(int id) +{ + struct lttng_ust_obj *obj = _objd_get(id); + + if (!obj) + return NULL; + return obj->u.s.name; +} + void lttng_ust_objd_table_owner_cleanup(void *owner) { int i; @@ -243,17 +254,10 @@ void lttng_ust_objd_table_owner_cleanup(void *owner) static const struct lttng_ust_objd_ops lttng_ops; static const struct lttng_ust_objd_ops lttng_session_ops; static const struct lttng_ust_objd_ops lttng_channel_ops; -static const struct lttng_ust_objd_ops lttng_metadata_ops; static const struct lttng_ust_objd_ops lttng_enabler_ops; -static const struct lttng_ust_objd_ops lib_ring_buffer_objd_ops; static const struct lttng_ust_objd_ops lttng_tracepoint_list_ops; static const struct lttng_ust_objd_ops lttng_tracepoint_field_list_ops; -enum channel_type { - PER_CPU_CHANNEL, - METADATA_CHANNEL, -}; - int lttng_abi_create_root_handle(void) { int root_handle; @@ -263,6 +267,18 @@ int lttng_abi_create_root_handle(void) return root_handle; } +static +int lttng_is_channel_ready(struct lttng_channel *lttng_chan) +{ + struct channel *chan; + unsigned int nr_streams, exp_streams; + + chan = lttng_chan->chan; + nr_streams = channel_handle_get_nr_streams(lttng_chan->handle); + exp_streams = chan->nr_streams; + return nr_streams == exp_streams; +} + static int lttng_abi_create_session(void *owner) { @@ -385,86 +401,133 @@ create_error: return; /* not allowed to return error */ } -int lttng_abi_create_channel(int session_objd, - struct lttng_ust_channel *chan_param, - enum channel_type channel_type, - union ust_args *uargs, - void *owner) +int lttng_abi_map_channel(int session_objd, + struct lttng_ust_channel *ust_chan, + union ust_args *uargs, + void *owner) { struct lttng_session *session = objd_private(session_objd); - const struct lttng_ust_objd_ops *ops; const char *transport_name; - struct lttng_channel *chan; + const struct lttng_transport *transport; + const char *chan_name; int chan_objd; - int ret = 0; - struct lttng_channel chan_priv_init; + struct lttng_ust_shm_handle *channel_handle; + struct lttng_channel *lttng_chan; + struct channel *chan; + struct lttng_ust_lib_ring_buffer_config *config; + void *chan_data; + uint64_t len; + int ret; + enum lttng_ust_chan_type type; + + chan_data = uargs->channel.chan_data; + len = ust_chan->len; + type = ust_chan->type; + + switch (type) { + case LTTNG_UST_CHAN_PER_CPU: + case LTTNG_UST_CHAN_METADATA: + break; + default: + return -EINVAL; + } + + if (session->been_active) { + ret = -EBUSY; + goto active; /* Refuse to add channel to active session */ + } - switch (channel_type) { - case PER_CPU_CHANNEL: - if (chan_param->output == LTTNG_UST_MMAP) { - transport_name = chan_param->overwrite ? + channel_handle = channel_handle_create(chan_data, len); + if (!channel_handle) { + ret = -EINVAL; + goto handle_error; + } + + chan = shmp(channel_handle, channel_handle->chan); + assert(chan); + config = &chan->backend.config; + lttng_chan = channel_get_private(chan); + if (!lttng_chan) { + ret = -EINVAL; + goto alloc_error; + } + + /* Lookup transport name */ + switch (type) { + case LTTNG_UST_CHAN_PER_CPU: + if (config->output == RING_BUFFER_MMAP) { + transport_name = config->mode == RING_BUFFER_OVERWRITE ? "relay-overwrite-mmap" : "relay-discard-mmap"; } else { - return -EINVAL; + ret = -EINVAL; + goto notransport; } - ops = <tng_channel_ops; + chan_name = "channel"; break; - case METADATA_CHANNEL: - if (chan_param->output == LTTNG_UST_MMAP) + case LTTNG_UST_CHAN_METADATA: + if (config->output == RING_BUFFER_MMAP) { transport_name = "relay-metadata-mmap"; - else - return -EINVAL; - ops = <tng_metadata_ops; + } else { + ret = -EINVAL; + goto notransport; + } + chan_name = "metadata"; break; default: transport_name = ""; - return -EINVAL; + chan_name = ""; + ret = -EINVAL; + goto notransport; } - chan_objd = objd_alloc(NULL, ops, owner, "channel"); + transport = lttng_transport_find(transport_name); + if (!transport) { + DBG("LTTng transport %s not found\n", + transport_name); + ret = -EINVAL; + goto notransport; + } + + chan_objd = objd_alloc(NULL, <tng_channel_ops, owner, chan_name); if (chan_objd < 0) { ret = chan_objd; goto objd_error; } - memset(&chan_priv_init, 0, sizeof(chan_priv_init)); - /* Copy of session UUID for consumer (availability through shm) */ - memcpy(chan_priv_init.uuid, session->uuid, sizeof(session->uuid)); - + + /* Initialize our lttng chan */ + lttng_chan->chan = chan; + lttng_chan->enabled = 1; + lttng_chan->ctx = NULL; + lttng_chan->session = session; + lttng_chan->free_event_id = 0; + lttng_chan->used_event_id = 0; + lttng_chan->ops = &transport->ops; + memcpy(<tng_chan->chan->backend.config, + transport->client_config, + sizeof(lttng_chan->chan->backend.config)); + cds_list_add(<tng_chan->node, &session->chan_head); + lttng_chan->header_type = 0; + lttng_chan->handle = channel_handle; + lttng_chan->metadata_dumped = 0; + lttng_chan->id = session->free_chan_id++; + lttng_chan->type = type; + /* * We tolerate no failure path after channel creation. It will stay * invariant for the rest of the session. */ - chan = lttng_channel_create(session, transport_name, NULL, - chan_param->subbuf_size, - chan_param->num_subbuf, - chan_param->switch_timer_interval, - chan_param->read_timer_interval, - &uargs->channel.shm_fd, - &uargs->channel.wait_fd, - &uargs->channel.memory_map_size, - &chan_priv_init); - if (!chan) { - ret = -EINVAL; - goto chan_error; - } - objd_set_private(chan_objd, chan); - chan->objd = chan_objd; - if (channel_type == METADATA_CHANNEL) { - session->metadata = chan; - lttng_metadata_create_events(chan_objd); - } + objd_set_private(chan_objd, lttng_chan); + lttng_chan->objd = chan_objd; /* The channel created holds a reference on the session */ objd_ref(session_objd); - return chan_objd; -chan_error: - { - int err; - - err = lttng_ust_objd_unref(chan_objd); - assert(!err); - } objd_error: +notransport: + free(lttng_chan); +alloc_error: + channel_destroy(chan, channel_handle, 0); +handle_error: +active: return ret; } @@ -497,19 +560,15 @@ long lttng_session_cmd(int objd, unsigned int cmd, unsigned long arg, switch (cmd) { case LTTNG_UST_CHANNEL: - return lttng_abi_create_channel(objd, + return lttng_abi_map_channel(objd, (struct lttng_ust_channel *) arg, - PER_CPU_CHANNEL, uargs, owner); + uargs, owner); case LTTNG_UST_SESSION_START: case LTTNG_UST_ENABLE: return lttng_session_enable(session); case LTTNG_UST_SESSION_STOP: case LTTNG_UST_DISABLE: return lttng_session_disable(session); - case LTTNG_UST_METADATA: - return lttng_abi_create_channel(objd, - (struct lttng_ust_channel *) arg, - METADATA_CHANNEL, uargs, owner); default: return -EINVAL; } @@ -707,47 +766,22 @@ static const struct lttng_ust_objd_ops lttng_tracepoint_field_list_ops = { .cmd = lttng_tracepoint_field_list_cmd, }; -struct stream_priv_data { - struct lttng_ust_lib_ring_buffer *buf; - struct lttng_channel *lttng_chan; -}; - static -int lttng_abi_open_stream(int channel_objd, struct lttng_ust_stream *info, +int lttng_abi_map_stream(int channel_objd, struct lttng_ust_stream *info, union ust_args *uargs, void *owner) { struct lttng_channel *channel = objd_private(channel_objd); - struct lttng_ust_lib_ring_buffer *buf; - struct stream_priv_data *priv; - 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); - if (!buf) - return -ENOENT; - - priv = zmalloc(sizeof(*priv)); - if (!priv) { - ret = -ENOMEM; - goto alloc_error; - } - priv->buf = buf; - priv->lttng_chan = channel; - stream_objd = objd_alloc(priv, &lib_ring_buffer_objd_ops, owner, "open_stream"); - if (stream_objd < 0) { - ret = stream_objd; - goto objd_error; - } - /* Hold a reference on the channel object descriptor */ - objd_ref(channel_objd); - return stream_objd; + int ret; -objd_error: - free(priv); -alloc_error: - channel->ops->buffer_read_close(buf, channel->handle); + ret = channel_handle_add_stream(channel->handle, + uargs->stream.shm_fd, uargs->stream.wakeup_fd, + info->stream_nr, info->len); + if (ret) + goto error_add_stream; + + return 0; + +error_add_stream: return ret; } @@ -792,6 +826,40 @@ objd_error: return ret; } +static +long lttng_metadata_cmd(int objd, unsigned int cmd, unsigned long arg, + union ust_args *uargs, void *owner) +{ + struct lttng_channel *channel = objd_private(objd); + struct lttng_session *session = channel->session; + + switch (cmd) { + case LTTNG_UST_STREAM: + { + struct lttng_ust_stream *stream; + int ret; + + stream = (struct lttng_ust_stream *) arg; + /* stream used as output */ + ret = lttng_abi_map_stream(objd, stream, uargs, owner); + if (ret == 0) { + session->metadata = channel; + lttng_metadata_create_events(objd); + } + return ret; + } + case LTTNG_UST_FLUSH_BUFFER: + { + if (!session->metadata) { + return -ENOENT; + } + return channel->ops->flush_buffer(channel->chan, channel->handle); + } + default: + return -EINVAL; + } +} + /** * lttng_channel_cmd - lttng control through object descriptors * @@ -822,6 +890,18 @@ long lttng_channel_cmd(int objd, unsigned int cmd, unsigned long arg, { struct lttng_channel *channel = objd_private(objd); + if (cmd != LTTNG_UST_STREAM) { + /* + * Check if channel received all streams. + */ + if (!lttng_is_channel_ready(channel)) + return -EPERM; + } + + if (channel->type == LTTNG_UST_CHAN_METADATA) { + return lttng_metadata_cmd(objd, cmd, arg, uargs, owner); + } + switch (cmd) { case LTTNG_UST_STREAM: { @@ -829,7 +909,7 @@ long lttng_channel_cmd(int objd, unsigned int cmd, unsigned long arg, stream = (struct lttng_ust_stream *) arg; /* stream used as output */ - return lttng_abi_open_stream(objd, stream, uargs, owner); + return lttng_abi_map_stream(objd, stream, uargs, owner); } case LTTNG_UST_EVENT: { @@ -859,43 +939,6 @@ long lttng_channel_cmd(int objd, unsigned int cmd, unsigned long arg, } } -/** - * lttng_metadata_cmd - lttng control through object descriptors - * - * @objd: the object descriptor - * @cmd: the command - * @arg: command arg - * @uargs: UST arguments (internal) - * @owner: objd owner - * - * This object descriptor implements lttng commands: - * LTTNG_UST_STREAM - * Returns an event stream file descriptor or failure. - * - * Channel and event file descriptors also hold a reference on the session. - */ -static -long lttng_metadata_cmd(int objd, unsigned int cmd, unsigned long arg, - union ust_args *uargs, void *owner) -{ - struct lttng_channel *channel = objd_private(objd); - - switch (cmd) { - case LTTNG_UST_STREAM: - { - struct lttng_ust_stream *stream; - - stream = (struct lttng_ust_stream *) arg; - /* stream used as output */ - return lttng_abi_open_stream(objd, stream, uargs, owner); - } - case LTTNG_UST_FLUSH_BUFFER: - return channel->ops->flush_buffer(channel->chan, channel->handle); - default: - return -EINVAL; - } -} - static int lttng_channel_release(int objd) { @@ -911,70 +954,6 @@ static const struct lttng_ust_objd_ops lttng_channel_ops = { .cmd = lttng_channel_cmd, }; -static const struct lttng_ust_objd_ops lttng_metadata_ops = { - .release = lttng_channel_release, - .cmd = lttng_metadata_cmd, -}; - -/** - * lttng_rb_cmd - lttng ring buffer control through object descriptors - * - * @objd: the object descriptor - * @cmd: the command - * @arg: command arg - * @uargs: UST arguments (internal) - * @owner: objd owner - * - * This object descriptor implements lttng commands: - * (None for now. Access is done directly though shm.) - */ -static -long lttng_rb_cmd(int objd, unsigned int cmd, unsigned long arg, - union ust_args *uargs, void *owner) -{ - switch (cmd) { - default: - return -EINVAL; - } -} - -static -int lttng_rb_release(int objd) -{ - struct stream_priv_data *priv = objd_private(objd); - struct lttng_ust_lib_ring_buffer *buf; - struct lttng_channel *channel; - - if (priv) { - buf = priv->buf; - channel = priv->lttng_chan; - free(priv); - /* - * If we are at ABI exit, we don't want to close the - * buffer opened for read: it is being shared between - * the parent and child (right after fork), and we don't - * want the child to close it for the parent. For a real - * exit, we don't care about marking it as closed, as - * the consumer daemon (if there is one) will do fine - * even if we don't mark it as "closed" for reading on - * our side. - * We only mark it as closed if it is being explicitely - * released by the session daemon with an explicit - * release command. - */ - if (!lttng_ust_abi_close_in_progress) - channel->ops->buffer_read_close(buf, channel->handle); - - return lttng_ust_objd_unref(channel->objd); - } - return 0; -} - -static const struct lttng_ust_objd_ops lib_ring_buffer_objd_ops = { - .release = lttng_rb_release, - .cmd = lttng_rb_cmd, -}; - /** * lttng_enabler_cmd - lttng control through object descriptors * diff --git a/liblttng-ust/lttng-ust-comm.c b/liblttng-ust/lttng-ust-comm.c index d7214370..bfc9bc5a 100644 --- a/liblttng-ust/lttng-ust-comm.c +++ b/liblttng-ust/lttng-ust-comm.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -134,6 +135,41 @@ struct sock_info local_apps = { static int wait_poll_fallback; +static const char *cmd_name_mapping[] = { + [ LTTNG_UST_RELEASE ] = "Release", + [ LTTNG_UST_SESSION ] = "Create Session", + [ LTTNG_UST_TRACER_VERSION ] = "Get Tracer Version", + + [ LTTNG_UST_TRACEPOINT_LIST ] = "Create Tracepoint List", + [ LTTNG_UST_WAIT_QUIESCENT ] = "Wait for Quiescent State", + [ LTTNG_UST_REGISTER_DONE ] = "Registration Done", + [ LTTNG_UST_TRACEPOINT_FIELD_LIST ] = "Create Tracepoint Field List", + + /* Session FD commands */ + [ LTTNG_UST_CHANNEL ] = "Create Channel", + [ LTTNG_UST_SESSION_START ] = "Start Session", + [ LTTNG_UST_SESSION_STOP ] = "Stop Session", + + /* Channel FD commands */ + [ LTTNG_UST_STREAM ] = "Create Stream", + [ LTTNG_UST_EVENT ] = "Create Event", + + /* Event and Channel FD commands */ + [ LTTNG_UST_CONTEXT ] = "Create Context", + [ LTTNG_UST_FLUSH_BUFFER ] = "Flush Buffer", + + /* Event, Channel and Session commands */ + [ LTTNG_UST_ENABLE ] = "Enable", + [ LTTNG_UST_DISABLE ] = "Disable", + + /* Tracepoint list commands */ + [ LTTNG_UST_TRACEPOINT_LIST_GET ] = "List Next Tracepoint", + [ LTTNG_UST_TRACEPOINT_FIELD_LIST_GET ] = "List Next Tracepoint Field", + + /* Event FD commands */ + [ LTTNG_UST_FILTER ] = "Create Filter", +}; + extern void lttng_ring_buffer_client_overwrite_init(void); extern void lttng_ring_buffer_client_discard_init(void); extern void lttng_ring_buffer_metadata_client_init(void); @@ -150,6 +186,18 @@ void lttng_fixup_nest_count_tls(void) asm volatile ("" : : "m" (lttng_ust_nest_count)); } +static +void print_cmd(int cmd, int handle) +{ + const char *cmd_name = "Unknown"; + + if (cmd_name_mapping[cmd]) { + cmd_name = cmd_name_mapping[cmd]; + } + DBG("Message Received \"%s\", Handle \"%s\" (%d)", cmd_name, + lttng_ust_obj_get_name(handle), handle); +} + static int setup_local_apps(void) { @@ -256,7 +304,6 @@ int handle_message(struct sock_info *sock_info, int ret = 0; const struct lttng_ust_objd_ops *ops; struct ustcomm_ust_reply lur; - int shm_fd, wait_fd; union ust_args args; ssize_t len; @@ -265,7 +312,7 @@ int handle_message(struct sock_info *sock_info, memset(&lur, 0, sizeof(lur)); if (lttng_ust_comm_should_quit) { - ret = -EPERM; + ret = -LTTNG_UST_ERR_EXITING; goto end; } @@ -357,6 +404,62 @@ int handle_message(struct sock_info *sock_info, } break; } + case LTTNG_UST_CHANNEL: + { + void *chan_data; + + len = ustcomm_recv_channel_from_sessiond(sock, + &chan_data, lum->u.channel.len); + switch (len) { + case 0: /* orderly shutdown */ + ret = 0; + goto error; + default: + if (len == lum->u.channel.len) { + DBG("channel data received"); + break; + } else if (len < 0) { + DBG("Receive failed from lttng-sessiond with errno %d", (int) -len); + if (len == -ECONNRESET) { + ERR("%s remote end closed connection", sock_info->name); + ret = len; + goto error; + } + ret = len; + goto end; + } else { + DBG("incorrect channel data message size: %zd", len); + ret = -EINVAL; + goto end; + } + } + args.channel.chan_data = chan_data; + if (ops->cmd) + ret = ops->cmd(lum->handle, lum->cmd, + (unsigned long) &lum->u, + &args, sock_info); + else + ret = -ENOSYS; + break; + } + case LTTNG_UST_STREAM: + { + /* Receive shm_fd, wakeup_fd */ + ret = ustcomm_recv_stream_from_sessiond(sock, + &lum->u.stream.len, + &args.stream.shm_fd, + &args.stream.wakeup_fd); + if (ret) { + goto end; + } + if (ops->cmd) + ret = ops->cmd(lum->handle, lum->cmd, + (unsigned long) &lum->u, + &args, sock_info); + else + ret = -ENOSYS; + break; + } default: if (ops->cmd) ret = ops->cmd(lum->handle, lum->cmd, @@ -408,21 +511,6 @@ end: } if (ret >= 0) { switch (lum->cmd) { - case LTTNG_UST_STREAM: - /* - * Special-case reply to send stream info. - * 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; - 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; - break; case LTTNG_UST_TRACER_VERSION: lur.u.version = lum->u.version; break; @@ -431,42 +519,13 @@ end: break; } } + DBG("Return value: %d", lur.ret_val); ret = send_reply(sock, &lur); if (ret < 0) { DBG("error sending reply"); goto error; } - if ((lum->cmd == LTTNG_UST_STREAM - || lum->cmd == LTTNG_UST_CHANNEL - || lum->cmd == LTTNG_UST_METADATA) - && lur.ret_code == LTTNG_UST_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)); - if (ret < 0) { - ERR("send shm_fd"); - 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)); - if (ret < 0) { - perror("send wait_fd"); - goto error; - } - if (sendret) { - ret = sendret; - goto error; - } - } /* * LTTNG_UST_TRACEPOINT_FIELD_LIST_GET needs to send the field * after the reply. @@ -487,49 +546,6 @@ end: } } } - /* - * We still have the memory map reference, and the fds have been - * sent to the sessiond. We can therefore close those fds. Note - * that we keep the write side of the wait_fd open, but close - * the read side. - */ - if (lur.ret_code == LTTNG_UST_OK) { - switch (lum->cmd) { - case LTTNG_UST_STREAM: - if (shm_fd >= 0) { - ret = close(shm_fd); - if (ret) { - PERROR("Error closing stream shm_fd"); - } - *args.stream.shm_fd = -1; - } - if (wait_fd >= 0) { - ret = close(wait_fd); - if (ret) { - PERROR("Error closing stream wait_fd"); - } - *args.stream.wait_fd = -1; - } - break; - case LTTNG_UST_METADATA: - case LTTNG_UST_CHANNEL: - if (shm_fd >= 0) { - ret = close(shm_fd); - if (ret) { - PERROR("Error closing channel shm_fd"); - } - *args.channel.shm_fd = -1; - } - if (wait_fd >= 0) { - ret = close(wait_fd); - if (ret) { - PERROR("Error closing channel wait_fd"); - } - *args.channel.wait_fd = -1; - } - break; - } - } error: ust_unlock(); @@ -903,7 +919,7 @@ restart: ust_unlock(); goto end; case sizeof(lum): - DBG("message received"); + print_cmd(lum.cmd, lum.handle); ret = handle_message(sock_info, sock, &lum); if (ret) { ERR("Error handling message for %s socket", sock_info->name); @@ -999,7 +1015,6 @@ void __attribute__((constructor)) lttng_ust_init(void) * to be the dynamic linker mutex) and ust_lock, taken within * the ust lock. */ - lttng_fixup_event_tls(); lttng_fixup_ringbuffer_tls(); lttng_fixup_vtid_tls(); lttng_fixup_nest_count_tls(); diff --git a/liblttng-ust/lttng-ust-uuid.h b/liblttng-ust/lttng-ust-uuid.h index 765e8d13..add11e1f 100644 --- a/liblttng-ust/lttng-ust-uuid.h +++ b/liblttng-ust/lttng-ust-uuid.h @@ -23,41 +23,11 @@ * SOFTWARE. */ -#include #include /* For LTTNG_UST_UUID_LEN */ + /* * Includes final \0. */ -#define LTTNG_UST_UUID_STR_LEN 37 - -#ifdef LTTNG_UST_HAVE_LIBUUID -#include - -static inline -int lttng_ust_uuid_generate(unsigned char *uuid_out) -{ - uuid_generate(uuid_out); - return 0; -} - -#elif defined(LTTNG_UST_HAVE_LIBC_UUID) -#include -#include - -static inline -int lttng_ust_uuid_generate(unsigned char *uuid_out) -{ - uint32_t status; - - uuid_create((uuid_t *) uuid_out, &status); - if (status == uuid_s_ok) - return 0; - else - return -1; -} - -#else -#error "LTTng-UST needs to have a UUID generator configured." -#endif +#define LTTNG_UST_UUID_STR_LEN 37 #endif /* _LTTNG_UST_UUID_H */ diff --git a/libringbuffer/frontend.h b/libringbuffer/frontend.h index b1ccddec..b59948df 100644 --- a/libringbuffer/frontend.h +++ b/libringbuffer/frontend.h @@ -64,19 +64,7 @@ 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); - -/* channel_handle_create - for consumer. */ -extern -struct lttng_ust_shm_handle *channel_handle_create(int shm_fd, int wait_fd, - uint64_t memory_map_size); - -/* channel_handle_add_stream - for consumer. */ -extern -int channel_handle_add_stream(struct lttng_ust_shm_handle *handle, - int shm_fd, int wait_fd, uint64_t memory_map_size); + unsigned int read_timer_interval); /* * channel_destroy finalizes all channel's buffers, waits for readers to @@ -84,7 +72,7 @@ int channel_handle_add_stream(struct lttng_ust_shm_handle *handle, */ extern void channel_destroy(struct channel *chan, struct lttng_ust_shm_handle *handle, - int shadow); + int consumer); /* Buffer read operations */ @@ -102,14 +90,24 @@ 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, - uint64_t **memory_map_size); + int *shm_fd, int *wait_fd, + int *wakeup_fd, + uint64_t *memory_map_size); +extern +int ring_buffer_close_wait_fd(const struct lttng_ust_lib_ring_buffer_config *config, + struct channel *chan, + struct lttng_ust_shm_handle *handle, + int cpu); +extern +int ring_buffer_close_wakeup_fd(const struct lttng_ust_lib_ring_buffer_config *config, + struct channel *chan, + struct lttng_ust_shm_handle *handle, + int cpu); + extern int lib_ring_buffer_open_read(struct lttng_ust_lib_ring_buffer *buf, - struct lttng_ust_shm_handle *handle, - int shadow); + struct lttng_ust_shm_handle *handle); extern void lib_ring_buffer_release_read(struct lttng_ust_lib_ring_buffer *buf, - struct lttng_ust_shm_handle *handle, - int shadow); + struct lttng_ust_shm_handle *handle); /* * Read sequence: snapshot, many get_subbuf/put_subbuf, move_consumer. diff --git a/libringbuffer/frontend_internal.h b/libringbuffer/frontend_internal.h index 2d3b1071..de705d5b 100644 --- a/libringbuffer/frontend_internal.h +++ b/libringbuffer/frontend_internal.h @@ -393,8 +393,7 @@ void lib_ring_buffer_check_deliver(const struct lttng_ust_lib_ring_buffer_config * RING_BUFFER_WAKEUP_BY_WRITER wakeup is not lock-free. */ if (config->wakeup == RING_BUFFER_WAKEUP_BY_WRITER - && (uatomic_read(&buf->active_readers) - || uatomic_read(&buf->active_shadow_readers)) + && uatomic_read(&buf->active_readers) && lib_ring_buffer_poll_deliver(config, buf, chan, handle)) { int wakeup_fd = shm_get_wakeup_fd(handle, &buf->self._ref); diff --git a/libringbuffer/frontend_types.h b/libringbuffer/frontend_types.h index b6b34470..9d3932d8 100644 --- a/libringbuffer/frontend_types.h +++ b/libringbuffer/frontend_types.h @@ -46,6 +46,7 @@ enum switch_mode { SWITCH_ACTIVE, SWITCH_FLUSH }; /* channel: collection of per-cpu ring buffers. */ +#define RB_CHANNEL_PADDING 32 struct channel { int record_disabled; unsigned long commit_count_mask; /* @@ -60,7 +61,8 @@ struct channel { //wait_queue_head_t read_wait; /* reader wait queue */ int finalized; /* Has channel been finalized */ size_t priv_data_offset; - /* Note: padding field is missing */ + unsigned int nr_streams; /* Number of streams */ + char padding[RB_CHANNEL_PADDING]; /* * Associated backend contains a variable-length array. Needs to * be last member. @@ -108,7 +110,6 @@ struct lttng_ust_lib_ring_buffer { * Active readers count * standard atomic access (shared) */ - long active_shadow_readers; /* Dropped records */ union v_atomic records_lost_full; /* Buffer full */ union v_atomic records_lost_wrap; /* Nested wrap-around */ diff --git a/libringbuffer/ring_buffer_backend.c b/libringbuffer/ring_buffer_backend.c index ae836522..e7a00144 100644 --- a/libringbuffer/ring_buffer_backend.c +++ b/libringbuffer/ring_buffer_backend.c @@ -280,7 +280,8 @@ int channel_backend_init(struct channel_backend *chanb, for_each_possible_cpu(i) { struct shm_object *shmobj; - shmobj = shm_object_table_append(handle->table, shmsize); + shmobj = shm_object_table_alloc(handle->table, shmsize, + SHM_OBJECT_SHM); if (!shmobj) goto end; align_shm(shmobj, __alignof__(struct lttng_ust_lib_ring_buffer)); @@ -298,7 +299,8 @@ int channel_backend_init(struct channel_backend *chanb, struct shm_object *shmobj; struct lttng_ust_lib_ring_buffer *buf; - shmobj = shm_object_table_append(handle->table, shmsize); + shmobj = shm_object_table_alloc(handle->table, shmsize, + SHM_OBJECT_SHM); if (!shmobj) goto end; align_shm(shmobj, __alignof__(struct lttng_ust_lib_ring_buffer)); diff --git a/libringbuffer/ring_buffer_frontend.c b/libringbuffer/ring_buffer_frontend.c index d1704dbf..6f94040e 100644 --- a/libringbuffer/ring_buffer_frontend.c +++ b/libringbuffer/ring_buffer_frontend.c @@ -255,7 +255,7 @@ static void switch_buffer_timer(unsigned long data) /* * Only flush buffers periodically if readers are active. */ - if (uatomic_read(&buf->active_readers) || uatomic_read(&buf->active_shadow_readers)) + if (uatomic_read(&buf->active_readers)) lib_ring_buffer_switch_slow(buf, SWITCH_ACTIVE, handle); //TODO timers @@ -313,7 +313,7 @@ static void read_buffer_timer(unsigned long data) CHAN_WARN_ON(chan, !buf->backend.allocated); - if (uatomic_read(&buf->active_readers) || uatomic_read(&buf->active_shadow_readers)) + if (uatomic_read(&buf->active_readers)) && lib_ring_buffer_poll_deliver(config, buf, chan)) { //TODO //wake_up_interruptible(&buf->read_wait); @@ -401,11 +401,9 @@ static void channel_unregister_notifiers(struct channel *chan, //channel_backend_unregister_notifiers(&chan->backend); } -static void channel_free(struct channel *chan, struct lttng_ust_shm_handle *handle, - int shadow) +static void channel_free(struct channel *chan, struct lttng_ust_shm_handle *handle) { - if (!shadow) - channel_backend_free(&chan->backend, handle); + channel_backend_free(&chan->backend, handle); /* chan is freed by shm teardown */ shm_object_table_destroy(handle->table); free(handle); @@ -439,15 +437,19 @@ struct lttng_ust_shm_handle *channel_create(const struct lttng_ust_lib_ring_buff void *priv_data_init, 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) + unsigned int read_timer_interval) { int ret, cpu; size_t shmsize, chansize; struct channel *chan; struct lttng_ust_shm_handle *handle; struct shm_object *shmobj; - struct shm_ref *ref; + unsigned int nr_streams; + + if (config->alloc == RING_BUFFER_ALLOC_PER_CPU) + nr_streams = num_possible_cpus(); + else + nr_streams = 1; if (lib_ring_buffer_check_config(config, switch_timer_interval, read_timer_interval)) @@ -465,15 +467,14 @@ struct lttng_ust_shm_handle *channel_create(const struct lttng_ust_lib_ring_buff /* Calculate the shm allocation layout */ shmsize = sizeof(struct channel); shmsize += offset_align(shmsize, __alignof__(struct lttng_ust_lib_ring_buffer_shmp)); - if (config->alloc == RING_BUFFER_ALLOC_PER_CPU) - shmsize += sizeof(struct lttng_ust_lib_ring_buffer_shmp) * num_possible_cpus(); - else - shmsize += sizeof(struct lttng_ust_lib_ring_buffer_shmp); + shmsize += sizeof(struct lttng_ust_lib_ring_buffer_shmp) * nr_streams; chansize = shmsize; - shmsize += offset_align(shmsize, priv_data_align); + if (priv_data_align) + shmsize += offset_align(shmsize, priv_data_align); shmsize += priv_data_size; - shmobj = shm_object_table_append(handle->table, shmsize); + /* Allocate normal memory for channel (not shared) */ + shmobj = shm_object_table_alloc(handle->table, shmsize, SHM_OBJECT_MEM); if (!shmobj) goto error_append; /* struct channel is at object 0, offset 0 (hardcoded) */ @@ -483,6 +484,7 @@ struct lttng_ust_shm_handle *channel_create(const struct lttng_ust_lib_ring_buff chan = shmp(handle, handle->chan); if (!chan) goto error_append; + chan->nr_streams = nr_streams; /* space for private data */ if (priv_data_size) { @@ -497,7 +499,8 @@ struct lttng_ust_shm_handle *channel_create(const struct lttng_ust_lib_ring_buff memcpy(*priv_data, priv_data_init, priv_data_size); } else { chan->priv_data_offset = -1; - *priv_data = NULL; + if (priv_data) + *priv_data = NULL; } ret = channel_backend_init(&chan->backend, name, config, @@ -530,8 +533,6 @@ struct lttng_ust_shm_handle *channel_create(const struct lttng_ust_lib_ring_buff lib_ring_buffer_start_switch_timer(buf, handle); 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); return handle; error_backend_init: @@ -542,7 +543,7 @@ error_table_alloc: return NULL; } -struct lttng_ust_shm_handle *channel_handle_create(int shm_fd, int wait_fd, +struct lttng_ust_shm_handle *channel_handle_create(void *data, uint64_t memory_map_size) { struct lttng_ust_shm_handle *handle; @@ -557,8 +558,8 @@ struct lttng_ust_shm_handle *channel_handle_create(int shm_fd, int wait_fd, if (!handle->table) goto error_table_alloc; /* Add channel object */ - object = shm_object_table_append_shadow(handle->table, - shm_fd, wait_fd, memory_map_size); + object = shm_object_table_append_mem(handle->table, data, + memory_map_size); if (!object) goto error_table_object; /* struct channel is at object 0, offset 0 (hardcoded) */ @@ -574,23 +575,30 @@ error_table_alloc: } int channel_handle_add_stream(struct lttng_ust_shm_handle *handle, - int shm_fd, int wait_fd, uint64_t memory_map_size) + int shm_fd, int wakeup_fd, uint32_t stream_nr, + uint64_t memory_map_size) { struct shm_object *object; /* Add stream object */ - object = shm_object_table_append_shadow(handle->table, - shm_fd, wait_fd, memory_map_size); + object = shm_object_table_append_shm(handle->table, + shm_fd, wakeup_fd, stream_nr, + memory_map_size); if (!object) - return -1; + return -EINVAL; return 0; } +unsigned int channel_handle_get_nr_streams(struct lttng_ust_shm_handle *handle) +{ + assert(handle->table); + return handle->table->allocated_len - 1; +} + static -void channel_release(struct channel *chan, struct lttng_ust_shm_handle *handle, - int shadow) +void channel_release(struct channel *chan, struct lttng_ust_shm_handle *handle) { - channel_free(chan, handle, shadow); + channel_free(chan, handle); } /** @@ -604,25 +612,21 @@ void channel_release(struct channel *chan, struct lttng_ust_shm_handle *handle, * They should release their handle at that point. */ void channel_destroy(struct channel *chan, struct lttng_ust_shm_handle *handle, - int shadow) + int consumer) { - if (shadow) { - channel_release(chan, handle, shadow); - return; + if (consumer) { + /* + * Note: the consumer takes care of finalizing and + * switching the buffers. + */ + channel_unregister_notifiers(chan, handle); } - channel_unregister_notifiers(chan, handle); - - /* - * Note: the consumer takes care of finalizing and switching the - * buffers. - */ - /* * sessiond/consumer are keeping a reference on the shm file * descriptor directly. No need to refcount. */ - channel_release(chan, handle, shadow); + channel_release(chan, handle); return; } @@ -630,36 +634,64 @@ 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, - uint64_t **memory_map_size) + int *shm_fd, int *wait_fd, + int *wakeup_fd, + 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); - return shmp(handle, chan->backend.buf[0].shmp); + cpu = 0; } 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); - return shmp(handle, chan->backend.buf[cpu].shmp); } + ref = &chan->backend.buf[cpu].shmp._ref; + *shm_fd = shm_get_shm_fd(handle, ref); + *wait_fd = shm_get_wait_fd(handle, ref); + *wakeup_fd = shm_get_wakeup_fd(handle, ref); + if (shm_get_shm_size(handle, ref, memory_map_size)) + return NULL; + return shmp(handle, chan->backend.buf[cpu].shmp); } -int lib_ring_buffer_open_read(struct lttng_ust_lib_ring_buffer *buf, - struct lttng_ust_shm_handle *handle, - int shadow) +int ring_buffer_close_wait_fd(const struct lttng_ust_lib_ring_buffer_config *config, + struct channel *chan, + struct lttng_ust_shm_handle *handle, + int cpu) { - if (shadow) { - if (uatomic_cmpxchg(&buf->active_shadow_readers, 0, 1) != 0) - return -EBUSY; - cmm_smp_mb(); - return 0; + struct shm_ref *ref; + + if (config->alloc == RING_BUFFER_ALLOC_GLOBAL) { + cpu = 0; + } else { + if (cpu >= num_possible_cpus()) + return -EINVAL; } + ref = &chan->backend.buf[cpu].shmp._ref; + return shm_close_wait_fd(handle, ref); +} + +int ring_buffer_close_wakeup_fd(const struct lttng_ust_lib_ring_buffer_config *config, + struct channel *chan, + struct lttng_ust_shm_handle *handle, + int cpu) +{ + struct shm_ref *ref; + + if (config->alloc == RING_BUFFER_ALLOC_GLOBAL) { + cpu = 0; + } else { + if (cpu >= num_possible_cpus()) + return -EINVAL; + } + ref = &chan->backend.buf[cpu].shmp._ref; + return shm_close_wakeup_fd(handle, ref); +} + +int lib_ring_buffer_open_read(struct lttng_ust_lib_ring_buffer *buf, + struct lttng_ust_shm_handle *handle) +{ if (uatomic_cmpxchg(&buf->active_readers, 0, 1) != 0) return -EBUSY; cmm_smp_mb(); @@ -667,17 +699,10 @@ int lib_ring_buffer_open_read(struct lttng_ust_lib_ring_buffer *buf, } void lib_ring_buffer_release_read(struct lttng_ust_lib_ring_buffer *buf, - struct lttng_ust_shm_handle *handle, - int shadow) + struct lttng_ust_shm_handle *handle) { struct channel *chan = shmp(handle, buf->backend.chan); - if (shadow) { - CHAN_WARN_ON(chan, uatomic_read(&buf->active_shadow_readers) != 1); - cmm_smp_mb(); - uatomic_dec(&buf->active_shadow_readers); - return; - } CHAN_WARN_ON(chan, uatomic_read(&buf->active_readers) != 1); cmm_smp_mb(); uatomic_dec(&buf->active_readers); @@ -755,8 +780,7 @@ void lib_ring_buffer_move_consumer(struct lttng_ust_lib_ring_buffer *buf, struct channel *chan = shmp(handle, bufb->chan); unsigned long consumed; - CHAN_WARN_ON(chan, uatomic_read(&buf->active_readers) != 1 - && uatomic_read(&buf->active_shadow_readers) != 1); + CHAN_WARN_ON(chan, uatomic_read(&buf->active_readers) != 1); /* * Only push the consumed value forward. @@ -879,8 +903,7 @@ void lib_ring_buffer_put_subbuf(struct lttng_ust_lib_ring_buffer *buf, const struct lttng_ust_lib_ring_buffer_config *config = &chan->backend.config; unsigned long read_sb_bindex, consumed_idx, consumed; - CHAN_WARN_ON(chan, uatomic_read(&buf->active_readers) != 1 - && uatomic_read(&buf->active_shadow_readers) != 1); + CHAN_WARN_ON(chan, uatomic_read(&buf->active_readers) != 1); if (!buf->get_subbuf) { /* diff --git a/libringbuffer/shm.c b/libringbuffer/shm.c index dbd3f348..85b1e4b7 100644 --- a/libringbuffer/shm.c +++ b/libringbuffer/shm.c @@ -81,7 +81,8 @@ struct shm_object_table *shm_object_table_create(size_t max_nb_obj) return table; } -struct shm_object *shm_object_table_append(struct shm_object_table *table, +static +struct shm_object *_shm_object_table_alloc_shm(struct shm_object_table *table, size_t memory_map_size) { int shmfd, waitfd[2], ret, i, sigblocked = 0; @@ -186,6 +187,7 @@ struct shm_object *shm_object_table_append(struct shm_object_table *table, PERROR("mmap"); goto error_mmap; } + obj->type = SHM_OBJECT_SHM; obj->memory_map = memory_map; obj->memory_map_size = memory_map_size; obj->allocated_len = 0; @@ -221,24 +223,87 @@ error_fcntl: } error_pipe: return NULL; - } -struct shm_object *shm_object_table_append_shadow(struct shm_object_table *table, - int shm_fd, int wait_fd, size_t memory_map_size) +static +struct shm_object *_shm_object_table_alloc_mem(struct shm_object_table *table, + size_t memory_map_size) +{ + struct shm_object *obj; + void *memory_map; + + if (table->allocated_len >= table->size) + return NULL; + obj = &table->objects[table->allocated_len]; + + memory_map = zmalloc(memory_map_size); + if (!memory_map) + goto alloc_error; + + obj->wait_fd[0] = -1; + obj->wait_fd[1] = -1; + obj->shm_fd = -1; + + obj->type = SHM_OBJECT_MEM; + obj->memory_map = memory_map; + obj->memory_map_size = memory_map_size; + obj->allocated_len = 0; + obj->index = table->allocated_len++; + + return obj; + +alloc_error: + return NULL; +} + +struct shm_object *shm_object_table_alloc(struct shm_object_table *table, + size_t memory_map_size, + enum shm_object_type type) +{ + switch (type) { + case SHM_OBJECT_SHM: + return _shm_object_table_alloc_shm(table, memory_map_size); + case SHM_OBJECT_MEM: + return _shm_object_table_alloc_mem(table, memory_map_size); + default: + assert(0); + } + return NULL; +} + +struct shm_object *shm_object_table_append_shm(struct shm_object_table *table, + int shm_fd, int wakeup_fd, uint32_t stream_nr, + size_t memory_map_size) { struct shm_object *obj; char *memory_map; + int ret; if (table->allocated_len >= table->size) return NULL; + /* streams _must_ be received in sequential order, else fail. */ + if (stream_nr + 1 != table->allocated_len) + return NULL; + obj = &table->objects[table->allocated_len]; - /* wait_fd: set read end of the pipe. */ - obj->wait_fd[0] = wait_fd; - obj->wait_fd[1] = -1; /* write end is unset. */ + /* wait_fd: set write end of the pipe. */ + obj->wait_fd[0] = -1; /* read end is unset */ + obj->wait_fd[1] = wakeup_fd; obj->shm_fd = shm_fd; + ret = fcntl(obj->wait_fd[1], F_SETFD, FD_CLOEXEC); + if (ret < 0) { + PERROR("fcntl"); + goto error_fcntl; + } + /* The write end of the pipe needs to be non-blocking */ + ret = fcntl(obj->wait_fd[1], F_SETFL, O_NONBLOCK); + if (ret < 0) { + PERROR("fcntl"); + goto error_fcntl; + } + /* memory_map: mmap */ memory_map = mmap(NULL, memory_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); @@ -246,6 +311,7 @@ struct shm_object *shm_object_table_append_shadow(struct shm_object_table *table PERROR("mmap"); goto error_mmap; } + obj->type = SHM_OBJECT_SHM; obj->memory_map = memory_map; obj->memory_map_size = memory_map_size; obj->allocated_len = memory_map_size; @@ -253,37 +319,70 @@ struct shm_object *shm_object_table_append_shadow(struct shm_object_table *table return obj; +error_fcntl: error_mmap: return NULL; } +/* + * Passing ownership of mem to object. + */ +struct shm_object *shm_object_table_append_mem(struct shm_object_table *table, + void *mem, size_t memory_map_size) +{ + struct shm_object *obj; + + if (table->allocated_len >= table->size) + return NULL; + obj = &table->objects[table->allocated_len]; + + obj->wait_fd[0] = -1; + obj->wait_fd[1] = -1; + obj->shm_fd = -1; + + obj->type = SHM_OBJECT_MEM; + obj->memory_map = mem; + obj->memory_map_size = memory_map_size; + obj->allocated_len = memory_map_size; + obj->index = table->allocated_len++; + + return obj; +} + static void shmp_object_destroy(struct shm_object *obj) { - int ret, i; + switch (obj->type) { + case SHM_OBJECT_SHM: + { + int ret, i; - if (!obj->is_shadow) { ret = munmap(obj->memory_map, obj->memory_map_size); if (ret) { PERROR("umnmap"); assert(0); } - } - if (obj->shm_fd >= 0) { ret = close(obj->shm_fd); if (ret) { PERROR("close"); assert(0); } - } - for (i = 0; i < 2; i++) { - if (obj->wait_fd[i] < 0) - continue; - ret = close(obj->wait_fd[i]); - if (ret) { - PERROR("close"); - assert(0); + for (i = 0; i < 2; i++) { + if (obj->wait_fd[i] < 0) + continue; + ret = close(obj->wait_fd[i]); + if (ret) { + PERROR("close"); + assert(0); + } } + break; + } + case SHM_OBJECT_MEM: + free(obj->memory_map); + break; + default: + assert(0); } } diff --git a/libringbuffer/shm.h b/libringbuffer/shm.h index 8987f72a..3d22a313 100644 --- a/libringbuffer/shm.h +++ b/libringbuffer/shm.h @@ -26,6 +26,20 @@ #include #include "shm_types.h" +/* channel_handle_create - for UST. */ +extern +struct lttng_ust_shm_handle *channel_handle_create(void *data, + uint64_t memory_map_size); +/* channel_handle_add_stream - for UST. */ +extern +int channel_handle_add_stream(struct lttng_ust_shm_handle *handle, + int shm_fd, int wakeup_fd, uint32_t stream_nr, + uint64_t memory_map_size); +unsigned int channel_handle_get_nr_streams(struct lttng_ust_shm_handle *handle); +extern +void channel_destroy(struct channel *chan, struct lttng_ust_shm_handle *handle, + int consumer); + /* * Pointer dereferencing. We don't trust the shm_ref, so we validate * both the index and offset with known boundaries. @@ -72,11 +86,16 @@ void _set_shmp(struct shm_ref *ref, struct shm_ref src) #define set_shmp(ref, src) _set_shmp(&(ref)._ref, src) struct shm_object_table *shm_object_table_create(size_t max_nb_obj); -struct shm_object *shm_object_table_append_shadow(struct shm_object_table *table, - int shm_fd, int wait_fd, size_t memory_map_size); +struct shm_object *shm_object_table_alloc(struct shm_object_table *table, + size_t memory_map_size, + enum shm_object_type type); +struct shm_object *shm_object_table_append_shm(struct shm_object_table *table, + int shm_fd, int wakeup_fd, uint32_t stream_nr, + size_t memory_map_size); +/* mem ownership is passed to shm_object_table_append_mem(). */ +struct shm_object *shm_object_table_append_mem(struct shm_object_table *table, + void *mem, size_t memory_map_size); void shm_object_table_destroy(struct shm_object_table *table); -struct shm_object *shm_object_table_append(struct shm_object_table *table, - size_t memory_map_size); /* * zalloc_shm - allocate memory within a shm object. @@ -88,6 +107,20 @@ struct shm_object *shm_object_table_append(struct shm_object_table *table, struct shm_ref zalloc_shm(struct shm_object *obj, size_t len); void align_shm(struct shm_object *obj, size_t align); +static inline +int shm_get_wait_fd(struct lttng_ust_shm_handle *handle, struct shm_ref *ref) +{ + struct shm_object_table *table = handle->table; + struct shm_object *obj; + size_t index; + + index = (size_t) ref->index; + if (caa_unlikely(index >= table->allocated_len)) + return -EPERM; + obj = &table->objects[index]; + return obj->wait_fd[0]; +} + static inline int shm_get_wakeup_fd(struct lttng_ust_shm_handle *handle, struct shm_ref *ref) { @@ -100,26 +133,74 @@ int shm_get_wakeup_fd(struct lttng_ust_shm_handle *handle, struct shm_ref *ref) return -EPERM; obj = &table->objects[index]; return obj->wait_fd[1]; +} + +static inline +int shm_close_wait_fd(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 ret; + index = (size_t) ref->index; + if (caa_unlikely(index >= table->allocated_len)) + return -EPERM; + obj = &table->objects[index]; + if (obj->wait_fd[0] < 0) + return -ENOENT; + ret = close(obj->wait_fd[0]); + if (ret) { + ret = -errno; + return ret; + } + obj->wait_fd[0] = -1; + return 0; } static inline -int shm_get_wait_fd(struct lttng_ust_shm_handle *handle, struct shm_ref *ref) +int shm_close_wakeup_fd(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 ret; index = (size_t) ref->index; if (caa_unlikely(index >= table->allocated_len)) return -EPERM; obj = &table->objects[index]; - return obj->wait_fd[0]; + if (obj->wait_fd[1] < 0) + return -ENOENT; + ret = close(obj->wait_fd[1]); + if (ret) { + ret = -errno; + return ret; + } + obj->wait_fd[1] = -1; + return 0; } 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_get_shm_fd(struct lttng_ust_shm_handle *handle, struct shm_ref *ref) +{ + struct shm_object_table *table = handle->table; + struct shm_object *obj; + size_t index; + + index = (size_t) ref->index; + if (caa_unlikely(index >= table->allocated_len)) + return -EPERM; + obj = &table->objects[index]; + return obj->shm_fd; +} + + +static inline +int shm_get_shm_size(struct lttng_ust_shm_handle *handle, struct shm_ref *ref, + uint64_t *size) { struct shm_object_table *table = handle->table; struct shm_object *obj; @@ -129,9 +210,7 @@ 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]; - *memory_map_size = &obj->allocated_len; + *size = obj->memory_map_size; return 0; } diff --git a/libringbuffer/shm_types.h b/libringbuffer/shm_types.h index 8b01d803..ba7f4b23 100644 --- a/libringbuffer/shm_types.h +++ b/libringbuffer/shm_types.h @@ -26,12 +26,17 @@ struct channel; +enum shm_object_type { + SHM_OBJECT_SHM, + SHM_OBJECT_MEM, +}; + struct shm_object { + enum shm_object_type type; size_t index; /* within the object table */ int shm_fd; /* shm fd */ int wait_fd[2]; /* fd for wait/wakeup */ char *memory_map; - int is_shadow; size_t memory_map_size; uint64_t allocated_len; }; @@ -45,12 +50,6 @@ struct shm_object_table { struct lttng_ust_shm_handle { struct shm_object_table *table; DECLARE_SHMP(struct channel, chan); - /* - * In the consumer, chan points to a shadow copy, validated upon - * reception. The chan object is overridden in the consumer to - * point to this shadow copy. - */ - struct channel *shadow_chan; }; #endif /* _LIBRINGBUFFER_SHM_TYPES_H */ diff --git a/tests/Makefile.am b/tests/Makefile.am index 7365ce47..9eee9d9c 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,5 +1,5 @@ -SUBDIRS = . hello hello-static-lib fork ust-basic-tracing ust-multi-test \ - demo daemon +SUBDIRS = . hello hello-static-lib fork demo daemon +#ust-basic-tracing ust-multi-test #SUBDIRS = . hello2 basic basic_long simple_include snprintf test-nevents test-libustinstr-malloc dlopen same_line_marker trace_event register_test tracepoint libustctl_function_tests exit-fast if CXX_WORKS