From 32ce85691c17b331072b1c0df96f69e8b388d134 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Mon, 11 Feb 2013 18:00:34 -0500 Subject: [PATCH] Move UST registry into sessiond and implement notifiers Needs to be use in locked-step with lttng-tools "Move UST registry into sessiond and implement notifiers" commit. Signed-off-by: Mathieu Desnoyers --- include/lttng/ust-abi.h | 20 +- include/lttng/ust-ctl.h | 193 +++++++++++- include/lttng/ust-error.h | 4 + include/lttng/ust-events.h | 7 +- include/ust-comm.h | 130 +++++++- liblttng-ust-comm/lttng-ust-comm.c | 482 +++++++++++++++++++++++++++-- liblttng-ust-ctl/ustctl.c | 356 ++++++++++++++++++++- liblttng-ust/lttng-events.c | 87 ++++-- liblttng-ust/lttng-tracer-core.h | 2 + liblttng-ust/lttng-ust-abi.c | 10 +- liblttng-ust/lttng-ust-comm.c | 134 +++++--- 11 files changed, 1290 insertions(+), 135 deletions(-) diff --git a/include/lttng/ust-abi.h b/include/lttng/ust-abi.h index 8c065fca..3c9f4600 100644 --- a/include/lttng/ust-abi.h +++ b/include/lttng/ust-abi.h @@ -30,16 +30,20 @@ #include #include -#define LTTNG_UST_SYM_NAME_LEN 256 +#ifndef __ust_stringify +#define __ust_stringify1(x) #x +#define __ust_stringify(x) __ust_stringify1(x) +#endif /* __ust_stringify */ -/* Version for comm protocol between sessiond and ust */ -#define LTTNG_UST_COMM_VERSION_MAJOR 2 -#define LTTNG_UST_COMM_VERSION_MINOR 1 +#define LTTNG_UST_SYM_NAME_LEN 256 +#define LTTNG_UST_ABI_PROCNAME_LEN 16 + +/* UST comm magic number, used to validate protocol and endianness. */ +#define LTTNG_UST_COMM_MAGIC 0xC57C57C5 /* Version for ABI between liblttng-ust, sessiond, consumerd */ -#define LTTNG_UST_INTERNAL_MAJOR_VERSION 3 -#define LTTNG_UST_INTERNAL_MINOR_VERSION 0 -#define LTTNG_UST_INTERNAL_PATCHLEVEL_VERSION 0 +#define LTTNG_UST_ABI_MAJOR_VERSION 4 +#define LTTNG_UST_ABI_MINOR_VERSION 0 enum lttng_ust_instrumentation { LTTNG_UST_TRACEPOINT = 0, @@ -171,6 +175,8 @@ enum lttng_ust_object_type { LTTNG_UST_OBJECT_TYPE_UNKNOWN = -1, LTTNG_UST_OBJECT_TYPE_CHANNEL = 0, LTTNG_UST_OBJECT_TYPE_STREAM = 1, + LTTNG_UST_OBJECT_TYPE_EVENT = 2, + LTTNG_UST_OBJECT_TYPE_CONTEXT = 3, }; #define LTTNG_UST_OBJECT_DATA_PADDING1 32 diff --git a/include/lttng/ust-ctl.h b/include/lttng/ust-ctl.h index 06b9f92b..ae4f3089 100644 --- a/include/lttng/ust-ctl.h +++ b/include/lttng/ust-ctl.h @@ -20,15 +20,25 @@ #define _LTTNG_UST_CTL_H #include - -#ifndef LTTNG_PACKED -#define LTTNG_PACKED __attribute__((packed)) -#endif +#include #ifndef LTTNG_UST_UUID_LEN #define LTTNG_UST_UUID_LEN 16 #endif +/* Default unix socket path */ +#define LTTNG_UST_SOCK_FILENAME \ + "lttng-ust-sock-" \ + __ust_stringify(LTTNG_UST_ABI_MAJOR_VERSION) + +/* + * Shared memory files path are automatically related to shm root, e.g. + * /dev/shm under linux. + */ +#define LTTNG_UST_WAIT_FILENAME \ + "lttng-ust-wait-" \ + __ust_stringify(LTTNG_UST_ABI_MAJOR_VERSION) + struct lttng_ust_shm_handle; struct lttng_ust_lib_ring_buffer; @@ -188,4 +198,179 @@ int ustctl_put_subbuf(struct ustctl_consumer_stream *stream); void ustctl_flush_buffer(struct ustctl_consumer_stream *stream, int producer_active); +/* event registry management */ + +enum ustctl_socket_type { + USTCTL_SOCKET_CMD = 0, + USTCTL_SOCKET_NOTIFY = 1, +}; + +enum ustctl_notify_cmd { + USTCTL_NOTIFY_CMD_EVENT = 0, + USTCTL_NOTIFY_CMD_CHANNEL = 1, +}; + +enum ustctl_channel_header { + USTCTL_CHANNEL_HEADER_UNKNOWN = 0, + USTCTL_CHANNEL_HEADER_COMPACT = 1, + USTCTL_CHANNEL_HEADER_LARGE = 2, +}; + +/* event type structures */ + +enum ustctl_abstract_types { + ustctl_atype_integer, + ustctl_atype_enum, + ustctl_atype_array, + ustctl_atype_sequence, + ustctl_atype_string, + ustctl_atype_float, + NR_USTCTL_ABSTRACT_TYPES, +}; + +enum ustctl_string_encodings { + ustctl_encode_none = 0, + ustctl_encode_UTF8 = 1, + ustctl_encode_ASCII = 2, + NR_USTCTL_STRING_ENCODINGS, +}; + +#define USTCTL_UST_INTEGER_TYPE_PADDING 24 +struct ustctl_integer_type { + uint32_t size; /* in bits */ + uint32_t signedness; + uint32_t reverse_byte_order; + uint32_t base; /* 2, 8, 10, 16, for pretty print */ + enum ustctl_string_encodings encoding; + uint16_t alignment; /* in bits */ + char padding[USTCTL_UST_INTEGER_TYPE_PADDING]; +} LTTNG_PACKED; + +#define USTCTL_UST_FLOAT_TYPE_PADDING 24 +struct ustctl_float_type { + uint32_t exp_dig; /* exponent digits, in bits */ + uint32_t mant_dig; /* mantissa digits, in bits */ + uint32_t reverse_byte_order; + uint16_t alignment; /* in bits */ + char padding[USTCTL_UST_FLOAT_TYPE_PADDING]; +} LTTNG_PACKED; + +#define USTCTL_UST_BASIC_TYPE_PADDING 296 +union _ustctl_basic_type { + struct ustctl_integer_type integer; + struct { + enum ustctl_string_encodings encoding; + } string; + struct ustctl_float_type _float; + char padding[USTCTL_UST_BASIC_TYPE_PADDING]; +} LTTNG_PACKED; + +struct ustctl_basic_type { + enum ustctl_abstract_types atype; + union { + union _ustctl_basic_type basic; + } u; +} LTTNG_PACKED; + +#define USTCTL_UST_TYPE_PADDING 128 +struct ustctl_type { + enum ustctl_abstract_types atype; + union { + union _ustctl_basic_type basic; + struct { + struct ustctl_basic_type elem_type; + uint32_t length; /* num. elems. */ + } array; + struct { + struct ustctl_basic_type length_type; + struct ustctl_basic_type elem_type; + } sequence; + char padding[USTCTL_UST_TYPE_PADDING]; + } u; +} LTTNG_PACKED; + +#define USTCTL_UST_FIELD_PADDING 28 +struct ustctl_field { + char name[LTTNG_UST_SYM_NAME_LEN]; + struct ustctl_type type; + char padding[USTCTL_UST_FIELD_PADDING]; +} LTTNG_PACKED; + +/* + * Returns 0 on success, negative error value on error. + * If an error other than -LTTNG_UST_ERR_UNSUP_MAJOR is returned, + * the output fields are not populated. + */ +int ustctl_recv_reg_msg(int sock, + enum ustctl_socket_type *type, + uint32_t *major, + uint32_t *minor, + uint32_t *pid, + uint32_t *ppid, + uint32_t *uid, + uint32_t *gid, + uint32_t *bits_per_long, + uint32_t *uint8_t_alignment, + uint32_t *uint16_t_alignment, + uint32_t *uint32_t_alignment, + uint32_t *uint64_t_alignment, + uint32_t *long_alignment, + int *byte_order, + char *name); /* size LTTNG_UST_ABI_PROCNAME_LEN */ + +/* + * Returns 0 on success, negative UST or system error value on error. + * Receive the notification command. The "notify_cmd" can then be used + * by the caller to find out which ustctl_recv_* function should be + * called to receive the notification, and which ustctl_reply_* is + * appropriate. + */ +int ustctl_recv_notify(int sock, enum ustctl_notify_cmd *notify_cmd); + +/* + * Returns 0 on success, negative UST or system error value on error. + */ +int ustctl_recv_register_event(int sock, + int *session_objd, /* session descriptor (output) */ + int *channel_objd, /* channel descriptor (output) */ + char *event_name, /* + * event name (output, + * size LTTNG_UST_SYM_NAME_LEN) + */ + int *loglevel, + char **signature, /* + * event signature + * (output, dynamically + * allocated, must be free(3)'d + * by the caller if function + * returns success.) + */ + size_t *nr_fields, + struct ustctl_field **fields, + char **model_emf_uri); + +/* + * Returns 0 on success, negative error value on error. + */ +int ustctl_reply_register_event(int sock, + uint32_t id, /* event id (input) */ + int ret_code); /* return code. 0 ok, negative error */ + +/* + * Returns 0 on success, negative UST or system error value on error. + */ +int ustctl_recv_register_channel(int sock, + int *session_objd, /* session descriptor (output) */ + int *channel_objd, /* channel descriptor (output) */ + size_t *nr_fields, /* context fields */ + struct ustctl_field **fields); + +/* + * Returns 0 on success, negative error value on error. + */ +int ustctl_reply_register_channel(int sock, + uint32_t chan_id, + enum ustctl_channel_header header_type, + int ret_code); /* return code. 0 ok, negative error */ + #endif /* _LTTNG_UST_CTL_H */ diff --git a/include/lttng/ust-error.h b/include/lttng/ust-error.h index bf6b7f33..05cc3bee 100644 --- a/include/lttng/ust-error.h +++ b/include/lttng/ust-error.h @@ -43,6 +43,10 @@ enum lttng_ust_error_code { LTTNG_UST_ERR_NOSYS = 1029, /* Not implemented */ LTTNG_UST_ERR_EXITING = 1030, /* Process is exiting */ + LTTNG_UST_ERR_INVAL_MAGIC = 1031, /* Invalid magic number */ + LTTNG_UST_ERR_INVAL_SOCKET_TYPE = 1032, /* Invalid socket type */ + LTTNG_UST_ERR_UNSUP_MAJOR = 1033, /* Unsupported major version */ + /* 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 c87a82c0..663ffbe3 100644 --- a/include/lttng/ust-events.h +++ b/include/lttng/ust-events.h @@ -420,8 +420,8 @@ struct lttng_channel { /* Event ID management */ struct lttng_session *session; int objd; /* Object associated to channel */ - unsigned int free_event_id; /* Next event ID to allocate */ - unsigned int used_event_id; /* Max allocated event IDs */ + unsigned int _deprecated1; + unsigned int _deprecated2; struct cds_list_head node; /* Channel list in session */ const struct lttng_channel_ops *ops; int header_type; /* 0: unset, 1: compact, 2: large */ @@ -455,13 +455,14 @@ struct lttng_session { struct cds_list_head events_head; /* list of events */ struct cds_list_head _deprecated1; struct cds_list_head node; /* Session list */ - unsigned int free_chan_id; /* Next chan ID to allocate */ + int _deprecated2; unsigned int metadata_dumped:1; /* New UST 2.1 */ /* List of enablers */ struct cds_list_head enablers_head; struct lttng_ust_event_ht events_ht; /* ht of events */ + void *owner; /* object owner */ }; struct lttng_transport { diff --git a/include/ust-comm.h b/include/ust-comm.h index 0eca73a9..97141160 100644 --- a/include/ust-comm.h +++ b/include/ust-comm.h @@ -40,27 +40,43 @@ */ #define LTTNG_UST_DEFAULT_CONSTRUCTOR_TIMEOUT_MS 3000 -#define LTTNG_RUNDIR "/var/run/lttng" -#define LTTNG_HOME_RUNDIR "%s/.lttng" - -/* Default unix socket path */ -#define DEFAULT_GLOBAL_CLIENT_UNIX_SOCK LTTNG_RUNDIR "/client-lttng-sessiond" -#define DEFAULT_GLOBAL_APPS_UNIX_SOCK LTTNG_RUNDIR "/apps-lttng-sessiond" -#define DEFAULT_HOME_APPS_UNIX_SOCK LTTNG_HOME_RUNDIR "/apps-lttng-sessiond" -#define DEFAULT_HOME_CLIENT_UNIX_SOCK LTTNG_HOME_RUNDIR "/client-lttng-sessiond" - -#define DEFAULT_GLOBAL_APPS_WAIT_SHM_PATH "/lttng-ust-apps-wait" -#define DEFAULT_HOME_APPS_WAIT_SHM_PATH "/lttng-ust-apps-wait-%u" +#define LTTNG_DEFAULT_RUNDIR "/var/run/lttng" +#define LTTNG_DEFAULT_HOME_RUNDIR ".lttng" /* Queue size of listen(2) */ -#define LTTNG_UST_COMM_MAX_LISTEN 10 +#define LTTNG_UST_COMM_MAX_LISTEN 10 +#define LTTNG_UST_COMM_REG_MSG_PADDING 64 + +struct lttng_event_field; + +struct ustctl_reg_msg { + uint32_t magic; + uint32_t major; + uint32_t minor; + uint32_t pid; + uint32_t ppid; + uint32_t uid; + uint32_t gid; + uint32_t bits_per_long; + uint32_t uint8_t_alignment; + uint32_t uint16_t_alignment; + uint32_t uint32_t_alignment; + uint32_t uint64_t_alignment; + uint32_t long_alignment; + uint32_t socket_type; /* enum ustctl_socket_type */ + char name[LTTNG_UST_ABI_PROCNAME_LEN]; /* process name */ + char padding[LTTNG_UST_COMM_REG_MSG_PADDING]; +} LTTNG_PACKED; /* * Data structure for the commands sent from sessiond to UST. */ +#define USTCOMM_MSG_PADDING1 32 +#define USTCOMM_MSG_PADDING2 32 struct ustcomm_ust_msg { uint32_t handle; uint32_t cmd; + char padding[USTCOMM_MSG_PADDING1]; union { struct lttng_ust_channel channel; struct lttng_ust_stream stream; @@ -73,6 +89,7 @@ struct ustcomm_ust_msg { uint32_t reloc_offset; uint64_t seqnum; } LTTNG_PACKED filter; + char padding[USTCOMM_MSG_PADDING2]; } u; } LTTNG_PACKED; @@ -80,11 +97,14 @@ struct ustcomm_ust_msg { * Data structure for the response from UST to the session daemon. * cmd_type is sent back in the reply for validation. */ +#define USTCOMM_REPLY_PADDING1 32 +#define USTCOMM_REPLY_PADDING2 32 struct ustcomm_ust_reply { uint32_t handle; uint32_t cmd; - uint32_t ret_code; /* enum enum ustcomm_return_code */ + uint32_t ret_code; /* enum ustcomm_return_code */ uint32_t ret_val; /* return value */ + char padding[USTCOMM_REPLY_PADDING1]; union { struct { uint64_t memory_map_size; @@ -94,9 +114,51 @@ struct ustcomm_ust_reply { } LTTNG_PACKED stream; struct lttng_ust_tracer_version version; struct lttng_ust_tracepoint_iter tracepoint; + char padding[USTCOMM_REPLY_PADDING2]; } u; } LTTNG_PACKED; +struct ustcomm_notify_hdr { + uint32_t notify_cmd; +} LTTNG_PACKED; + +#define USTCOMM_NOTIFY_EVENT_MSG_PADDING 32 +struct ustcomm_notify_event_msg { + uint32_t session_objd; + uint32_t channel_objd; + char event_name[LTTNG_UST_SYM_NAME_LEN]; + int32_t loglevel; + uint32_t signature_len; + uint32_t fields_len; + uint32_t model_emf_uri_len; + char padding[USTCOMM_NOTIFY_EVENT_MSG_PADDING]; + /* followed by signature, fields, and model_emf_uri */ +} LTTNG_PACKED; + +#define USTCOMM_NOTIFY_EVENT_REPLY_PADDING 32 +struct ustcomm_notify_event_reply { + int32_t ret_code; /* 0: ok, negative: error code */ + uint32_t event_id; + char padding[USTCOMM_NOTIFY_EVENT_REPLY_PADDING]; +} LTTNG_PACKED; + +#define USTCOMM_NOTIFY_CHANNEL_MSG_PADDING 32 +struct ustcomm_notify_channel_msg { + uint32_t session_objd; + uint32_t channel_objd; + uint32_t ctx_fields_len; + char padding[USTCOMM_NOTIFY_CHANNEL_MSG_PADDING]; + /* followed by context fields */ +} LTTNG_PACKED; + +#define USTCOMM_NOTIFY_CHANNEL_REPLY_PADDING 32 +struct ustcomm_notify_channel_reply { + int32_t ret_code; /* 0: ok, negative: error code */ + uint32_t chan_id; + uint32_t header_type; /* enum ustctl_channel_header */ + char padding[USTCOMM_NOTIFY_CHANNEL_REPLY_PADDING]; +} LTTNG_PACKED; + /* * LTTNG_UST_TRACEPOINT_FIELD_LIST reply is followed by a * struct lttng_ust_field_iter field. @@ -109,7 +171,7 @@ extern int ustcomm_listen_unix_sock(int sock); extern int ustcomm_close_unix_sock(int sock); 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_unix_sock(int sock, const 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); @@ -128,4 +190,44 @@ int ustcomm_recv_stream_from_sessiond(int sock, uint64_t *memory_map_size, int *shm_fd, int *wakeup_fd); +/* + * Returns 0 on success, negative error value on error. + * Returns -EPIPE or -ECONNRESET if other end has hung up. + */ +int ustcomm_send_reg_msg(int sock, + enum ustctl_socket_type type, + uint32_t bits_per_long, + uint32_t uint8_t_alignment, + uint32_t uint16_t_alignment, + uint32_t uint32_t_alignment, + uint32_t uint64_t_alignment, + uint32_t long_alignment); + +/* + * Returns 0 on success, negative error value on error. + * Returns -EPIPE or -ECONNRESET if other end has hung up. + */ +int ustcomm_register_event(int sock, + int session_objd, /* session descriptor */ + int channel_objd, /* channel descriptor */ + const char *event_name, /* event name (input) */ + int loglevel, + const char *signature, /* event signature (input) */ + size_t nr_fields, /* fields */ + const struct lttng_event_field *fields, + const char *model_emf_uri, + uint32_t *id); /* event id (output) */ + +/* + * Returns 0 on success, negative error value on error. + * Returns -EPIPE or -ECONNRESET if other end has hung up. + */ +int ustcomm_register_channel(int sock, + int session_objd, /* session descriptor */ + int channel_objd, /* channel descriptor */ + size_t nr_ctx_fields, + const struct lttng_event_field *ctx_fields, + uint32_t *chan_id, /* channel id (output) */ + int *header_type); /* header type (output) */ + #endif /* _LTTNG_UST_COMM_H */ diff --git a/liblttng-ust-comm/lttng-ust-comm.c b/liblttng-ust-comm/lttng-ust-comm.c index f4695676..1395eee2 100644 --- a/liblttng-ust-comm/lttng-ust-comm.c +++ b/liblttng-ust-comm/lttng-ust-comm.c @@ -31,9 +31,14 @@ #include #include +#include #include #include #include +#include +#include + +#include "../liblttng-ust/compat.h" #define USTCOMM_CODE_OFFSET(code) \ (code == LTTNG_UST_OK ? 0 : (code - LTTNG_UST_ERR + 1)) @@ -52,6 +57,10 @@ static const char *ustcomm_readable_code[] = { [ 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", + + [ USTCOMM_CODE_OFFSET(LTTNG_UST_ERR_INVAL_MAGIC) ] = "Invalid magic number", + [ USTCOMM_CODE_OFFSET(LTTNG_UST_ERR_INVAL_SOCKET_TYPE) ] = "Invalid socket type", + [ USTCOMM_CODE_OFFSET(LTTNG_UST_ERR_UNSUP_MAJOR) ] = "Unsupported major version", }; /* @@ -89,13 +98,13 @@ int ustcomm_connect_unix_sock(const char *pathname) */ fd = socket(PF_UNIX, SOCK_STREAM, 0); if (fd < 0) { - perror("socket"); + PERROR("socket"); ret = -errno; goto error; } ret = fcntl(fd, F_SETFD, FD_CLOEXEC); if (ret < 0) { - perror("fcntl"); + PERROR("fcntl"); ret = -errno; goto error_fcntl; } @@ -125,7 +134,7 @@ error_fcntl: closeret = close(fd); if (closeret) - perror("close"); + PERROR("close"); } error: return ret; @@ -146,7 +155,7 @@ int ustcomm_accept_unix_sock(int sock) /* Blocking call */ new_fd = accept(sock, (struct sockaddr *) &sun, &len); if (new_fd < 0) { - perror("accept"); + PERROR("accept"); return -errno; } return new_fd; @@ -165,7 +174,7 @@ int ustcomm_create_unix_sock(const char *pathname) /* Create server socket */ if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { - perror("socket"); + PERROR("socket"); ret = -errno; goto error; } @@ -179,7 +188,7 @@ int ustcomm_create_unix_sock(const char *pathname) (void) unlink(pathname); ret = bind(fd, (struct sockaddr *) &sun, sizeof(sun)); if (ret < 0) { - perror("bind"); + PERROR("bind"); ret = -errno; goto error_close; } @@ -192,7 +201,7 @@ error_close: closeret = close(fd); if (closeret) { - perror("close"); + PERROR("close"); } } error: @@ -211,7 +220,7 @@ int ustcomm_listen_unix_sock(int sock) ret = listen(sock, LTTNG_UST_COMM_MAX_LISTEN); if (ret < 0) { ret = -errno; - perror("listen"); + PERROR("listen"); } return ret; @@ -228,7 +237,7 @@ int ustcomm_close_unix_sock(int sock) ret = close(sock); if (ret < 0) { - perror("close"); + PERROR("close"); ret = -errno; } @@ -264,12 +273,12 @@ ssize_t ustcomm_recv_unix_sock(int sock, void *buf, size_t len) int shutret; if (errno != EPIPE && errno != ECONNRESET) - perror("recvmsg"); + PERROR("recvmsg"); ret = -errno; shutret = shutdown(sock, SHUT_RDWR); if (shutret) - fprintf(stderr, "Socket shutdown error"); + ERR("Socket shutdown error"); } return ret; @@ -281,7 +290,7 @@ ssize_t ustcomm_recv_unix_sock(int sock, void *buf, size_t len) * 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) +ssize_t ustcomm_send_unix_sock(int sock, const void *buf, size_t len) { struct msghdr msg; struct iovec iov[1]; @@ -289,7 +298,7 @@ ssize_t ustcomm_send_unix_sock(int sock, void *buf, size_t len) memset(&msg, 0, sizeof(msg)); - iov[0].iov_base = buf; + iov[0].iov_base = (void *) buf; iov[0].iov_len = len; msg.msg_iov = iov; msg.msg_iovlen = 1; @@ -309,12 +318,12 @@ ssize_t ustcomm_send_unix_sock(int sock, void *buf, size_t len) int shutret; if (errno != EPIPE && errno != ECONNRESET) - perror("sendmsg"); + PERROR("sendmsg"); ret = -errno; shutret = shutdown(sock, SHUT_RDWR); if (shutret) - fprintf(stderr, "Socket shutdown error"); + ERR("Socket shutdown error"); } return ret; @@ -365,7 +374,7 @@ ssize_t ustcomm_send_fds_unix_sock(int sock, int *fds, size_t nb_fd) * We consider EPIPE and ECONNRESET as expected. */ if (errno != EPIPE && errno != ECONNRESET) { - perror("sendmsg"); + PERROR("sendmsg"); } } return ret; @@ -405,7 +414,7 @@ ssize_t ustcomm_recv_fds_unix_sock(int sock, int *fds, size_t nb_fd) } while (ret < 0 && errno == EINTR); if (ret < 0) { if (errno != EPIPE && errno != ECONNRESET) { - perror("recvmsg fds"); + PERROR("recvmsg fds"); } if (errno == EPIPE || errno == ECONNRESET) ret = -errno; @@ -417,28 +426,28 @@ ssize_t ustcomm_recv_fds_unix_sock(int sock, int *fds, size_t nb_fd) goto end; } if (ret != 1) { - fprintf(stderr, "Error: Received %zd bytes, expected %d\n", + ERR("Error: Received %zd bytes, expected %d\n", ret, 1); goto end; } if (msg.msg_flags & MSG_CTRUNC) { - fprintf(stderr, "Error: Control message truncated.\n"); + ERR("Error: Control message truncated.\n"); ret = -1; goto end; } cmsg = CMSG_FIRSTHDR(&msg); if (!cmsg) { - fprintf(stderr, "Error: Invalid control message header\n"); + ERR("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"); + ERR("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", + ERR("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; @@ -461,7 +470,7 @@ int ustcomm_send_app_msg(int sock, struct ustcomm_ust_msg *lum) if (len < 0) { return len; } else { - fprintf(stderr, "incorrect message size: %zd\n", len); + ERR("incorrect message size: %zd\n", len); return -EINVAL; } } @@ -480,13 +489,13 @@ int ustcomm_recv_app_reply(int sock, struct ustcomm_ust_reply *lur, return -EPIPE; case sizeof(*lur): if (lur->handle != expected_handle) { - fprintf(stderr, "Unexpected result message handle: " + ERR("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 " + ERR("Unexpected result message command " "expected: %u vs received: %u\n", expected_cmd, lur->cmd); return -EINVAL; @@ -499,7 +508,7 @@ int ustcomm_recv_app_reply(int sock, struct ustcomm_ust_reply *lur, len = -errno; return len; } else { - fprintf(stderr, "incorrect message size: %zd\n", len); + ERR("incorrect message size: %zd\n", len); return len; } } @@ -580,3 +589,424 @@ int ustcomm_recv_stream_from_sessiond(int sock, error: return ret; } + +/* + * Returns 0 on success, negative error value on error. + */ +int ustcomm_send_reg_msg(int sock, + enum ustctl_socket_type type, + uint32_t bits_per_long, + uint32_t uint8_t_alignment, + uint32_t uint16_t_alignment, + uint32_t uint32_t_alignment, + uint32_t uint64_t_alignment, + uint32_t long_alignment) +{ + ssize_t len; + struct ustctl_reg_msg reg_msg; + + reg_msg.magic = LTTNG_UST_COMM_MAGIC; + reg_msg.major = LTTNG_UST_ABI_MAJOR_VERSION; + reg_msg.minor = LTTNG_UST_ABI_MINOR_VERSION; + reg_msg.pid = getpid(); + reg_msg.ppid = getppid(); + reg_msg.uid = getuid(); + reg_msg.gid = getgid(); + reg_msg.bits_per_long = bits_per_long; + reg_msg.uint8_t_alignment = uint8_t_alignment; + reg_msg.uint16_t_alignment = uint16_t_alignment; + reg_msg.uint32_t_alignment = uint32_t_alignment; + reg_msg.uint64_t_alignment = uint64_t_alignment; + reg_msg.long_alignment = long_alignment; + reg_msg.socket_type = type; + lttng_ust_getprocname(reg_msg.name); + memset(reg_msg.padding, 0, sizeof(reg_msg.padding)); + + len = ustcomm_send_unix_sock(sock, ®_msg, sizeof(reg_msg)); + if (len > 0 && len != sizeof(reg_msg)) + return -EIO; + if (len < 0) + return len; + return 0; +} + +static +int serialize_basic_type(enum lttng_abstract_types atype, + union _ustctl_basic_type *ubt, + const union _lttng_basic_type *lbt) +{ + switch (atype) { + case atype_integer: + { + struct ustctl_integer_type *uit; + const struct lttng_integer_type *lit; + + uit = &ubt->integer; + lit = &lbt->integer; + uit->size = lit->size; + uit->signedness = lit->signedness; + uit->reverse_byte_order = lit->reverse_byte_order; + uit->base = lit->base; + uit->encoding = lit->encoding; + uit->alignment = lit->alignment; + break; + } + case atype_string: + { + ubt->string.encoding = lbt->string.encoding; + break; + } + case atype_float: + { + struct ustctl_float_type *uft; + const struct lttng_float_type *lft; + + uft = &ubt->_float; + lft = &lbt->_float; + uft->exp_dig = lft->exp_dig; + uft->mant_dig = lft->mant_dig; + uft->alignment = lft->alignment; + uft->reverse_byte_order = lft->reverse_byte_order; + break; + } + case atype_enum: + case atype_array: + case atype_sequence: + default: + return -EINVAL; + } + return 0; + +} + +static +int serialize_one_type(struct ustctl_type *ut, const struct lttng_type *lt) +{ + int ret; + + switch (lt->atype) { + case atype_integer: + case atype_float: + case atype_string: + ret = serialize_basic_type(lt->atype, + &ut->u.basic, <->u.basic); + if (ret) + return ret; + break; + case atype_array: + { + struct ustctl_basic_type *ubt; + const struct lttng_basic_type *lbt; + int ret; + + ubt = &ut->u.array.elem_type; + lbt = <->u.array.elem_type; + ut->u.array.length = lt->u.array.length; + ret = serialize_basic_type(lbt->atype, + &ubt->u.basic, &lbt->u.basic); + if (ret) + return -EINVAL; + break; + } + case atype_sequence: + { + struct ustctl_basic_type *ubt; + const struct lttng_basic_type *lbt; + int ret; + + ubt = &ut->u.sequence.length_type; + lbt = <->u.sequence.length_type; + ret = serialize_basic_type(lbt->atype, + &ubt->u.basic, &lbt->u.basic); + if (ret) + return -EINVAL; + ubt = &ut->u.sequence.elem_type; + lbt = <->u.sequence.elem_type; + ret = serialize_basic_type(lbt->atype, + &ubt->u.basic, &lbt->u.basic); + if (ret) + return -EINVAL; + break; + } + case atype_enum: + default: + return -EINVAL; + } + return 0; +} + +static +int serialize_fields(size_t *_nr_write_fields, + struct ustctl_field **ustctl_fields, + size_t nr_fields, + const struct lttng_event_field *lttng_fields) +{ + struct ustctl_field *fields; + int i, ret; + size_t nr_write_fields = 0; + + fields = zmalloc(nr_fields * sizeof(*fields)); + if (!fields) + return -ENOMEM; + + for (i = 0; i < nr_fields; i++) { + struct ustctl_field *f; + const struct lttng_event_field *lf; + + f = &fields[nr_write_fields]; + lf = <tng_fields[i]; + + /* skip 'nowrite' fields */ + if (lf->nowrite) + continue; + strncpy(f->name, lf->name, LTTNG_UST_SYM_NAME_LEN); + f->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0'; + ret = serialize_one_type(&f->type, &lf->type); + if (ret) + goto error_type; + nr_write_fields++; + } + + *_nr_write_fields = nr_write_fields; + *ustctl_fields = fields; + return 0; + +error_type: + free(fields); + return ret; +} + +/* + * Returns 0 on success, negative error value on error. + */ +int ustcomm_register_event(int sock, + int session_objd, /* session descriptor */ + int channel_objd, /* channel descriptor */ + const char *event_name, /* event name (input) */ + int loglevel, + const char *signature, /* event signature (input) */ + size_t nr_fields, /* fields */ + const struct lttng_event_field *lttng_fields, + const char *model_emf_uri, + uint32_t *id) /* event id (output) */ +{ + ssize_t len; + struct { + struct ustcomm_notify_hdr header; + struct ustcomm_notify_event_msg m; + } msg; + struct { + struct ustcomm_notify_hdr header; + struct ustcomm_notify_event_reply r; + } reply; + size_t signature_len, fields_len, model_emf_uri_len; + struct ustctl_field *fields; + size_t nr_write_fields = 0; + int ret; + + memset(&msg, 0, sizeof(msg)); + msg.header.notify_cmd = USTCTL_NOTIFY_CMD_EVENT; + msg.m.session_objd = session_objd; + msg.m.channel_objd = channel_objd; + strncpy(msg.m.event_name, event_name, LTTNG_UST_SYM_NAME_LEN); + msg.m.event_name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0'; + msg.m.loglevel = loglevel; + signature_len = strlen(signature) + 1; + msg.m.signature_len = signature_len; + + /* Calculate fields len, serialize fields. */ + if (nr_fields > 0) { + ret = serialize_fields(&nr_write_fields, &fields, + nr_fields, lttng_fields); + if (ret) + return ret; + } + + fields_len = sizeof(*fields) * nr_write_fields; + msg.m.fields_len = fields_len; + if (model_emf_uri) { + model_emf_uri_len = strlen(model_emf_uri) + 1; + } else { + model_emf_uri_len = 0; + } + msg.m.model_emf_uri_len = model_emf_uri_len; + len = ustcomm_send_unix_sock(sock, &msg, sizeof(msg)); + if (len > 0 && len != sizeof(msg)) { + free(fields); + return -EIO; + } + if (len < 0) { + free(fields); + return len; + } + + /* send signature */ + len = ustcomm_send_unix_sock(sock, signature, signature_len); + if (len > 0 && len != signature_len) { + free(fields); + return -EIO; + } + if (len < 0) { + free(fields); + return len; + } + + /* send fields */ + if (fields_len > 0) { + len = ustcomm_send_unix_sock(sock, fields, fields_len); + free(fields); + if (len > 0 && len != fields_len) { + return -EIO; + } + if (len < 0) { + return len; + } + } + + if (model_emf_uri_len) { + /* send model_emf_uri */ + len = ustcomm_send_unix_sock(sock, model_emf_uri, + model_emf_uri_len); + if (len > 0 && len != model_emf_uri_len) + return -EIO; + if (len < 0) + return len; + } + + /* receive reply */ + len = ustcomm_recv_unix_sock(sock, &reply, sizeof(reply)); + switch (len) { + case 0: /* orderly shutdown */ + return -EPIPE; + case sizeof(reply): + if (reply.header.notify_cmd != msg.header.notify_cmd) { + ERR("Unexpected result message command " + "expected: %u vs received: %u\n", + msg.header.notify_cmd, reply.header.notify_cmd); + return -EINVAL; + } + if (reply.r.ret_code > 0) + return -EINVAL; + if (reply.r.ret_code < 0) + return reply.r.ret_code; + *id = reply.r.event_id; + DBG("Sent register event notification for name \"%s\": ret_code %d, event_id %u\n", + event_name, reply.r.ret_code, reply.r.event_id); + return 0; + default: + if (len < 0) { + /* Transport level error */ + if (errno == EPIPE || errno == ECONNRESET) + len = -errno; + return len; + } else { + ERR("incorrect message size: %zd\n", len); + return len; + } + } +} + +/* + * Returns 0 on success, negative error value on error. + * Returns -EPIPE or -ECONNRESET if other end has hung up. + */ +int ustcomm_register_channel(int sock, + int session_objd, /* session descriptor */ + int channel_objd, /* channel descriptor */ + size_t nr_ctx_fields, + const struct lttng_event_field *ctx_fields, + uint32_t *chan_id, /* channel id (output) */ + int *header_type) /* header type (output) */ +{ + ssize_t len; + struct { + struct ustcomm_notify_hdr header; + struct ustcomm_notify_channel_msg m; + } msg; + struct { + struct ustcomm_notify_hdr header; + struct ustcomm_notify_channel_reply r; + } reply; + size_t fields_len; + struct ustctl_field *fields; + int ret; + size_t nr_write_fields = 0; + + memset(&msg, 0, sizeof(msg)); + msg.header.notify_cmd = USTCTL_NOTIFY_CMD_CHANNEL; + msg.m.session_objd = session_objd; + msg.m.channel_objd = channel_objd; + + /* Calculate fields len, serialize fields. */ + if (nr_ctx_fields > 0) { + ret = serialize_fields(&nr_write_fields, &fields, + nr_ctx_fields, ctx_fields); + if (ret) + return ret; + } + + fields_len = sizeof(*fields) * nr_write_fields; + msg.m.ctx_fields_len = fields_len; + len = ustcomm_send_unix_sock(sock, &msg, sizeof(msg)); + if (len > 0 && len != sizeof(msg)) { + free(fields); + return -EIO; + } + if (len < 0) { + free(fields); + return len; + } + + /* send fields */ + if (fields_len > 0) { + len = ustcomm_send_unix_sock(sock, fields, fields_len); + free(fields); + if (len > 0 && len != fields_len) { + return -EIO; + } + if (len < 0) { + return len; + } + } + + len = ustcomm_recv_unix_sock(sock, &reply, sizeof(reply)); + switch (len) { + case 0: /* orderly shutdown */ + return -EPIPE; + case sizeof(reply): + if (reply.header.notify_cmd != msg.header.notify_cmd) { + ERR("Unexpected result message command " + "expected: %u vs received: %u\n", + msg.header.notify_cmd, reply.header.notify_cmd); + return -EINVAL; + } + if (reply.r.ret_code > 0) + return -EINVAL; + if (reply.r.ret_code < 0) + return reply.r.ret_code; + *chan_id = reply.r.chan_id; + switch (reply.r.header_type) { + case 1: + case 2: + *header_type = reply.r.header_type; + break; + default: + ERR("Unexpected channel header type %u\n", + reply.r.header_type); + return -EINVAL; + } + DBG("Sent register channel notification: chan_id %d, header_type %d\n", + reply.r.chan_id, reply.r.header_type); + return 0; + default: + if (len < 0) { + /* Transport level error */ + if (errno == EPIPE || errno == ECONNRESET) + len = -errno; + return len; + } else { + ERR("incorrect message size: %zd\n", len); + return len; + } + } +} diff --git a/liblttng-ust-ctl/ustctl.c b/liblttng-ust-ctl/ustctl.c index aed40f26..d47a5b50 100644 --- a/liblttng-ust-ctl/ustctl.c +++ b/liblttng-ust-ctl/ustctl.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -105,6 +106,9 @@ int ustctl_release_object(int sock, struct lttng_ust_object_data *data) } } break; + case LTTNG_UST_OBJECT_TYPE_EVENT: + case LTTNG_UST_OBJECT_TYPE_CONTEXT: + break; default: assert(0); } @@ -166,6 +170,7 @@ int ustctl_create_event(int sock, struct lttng_ust_event *ev, event_data = zmalloc(sizeof(*event_data)); if (!event_data) return -ENOMEM; + event_data->type = LTTNG_UST_OBJECT_TYPE_EVENT; memset(&lum, 0, sizeof(lum)); lum.handle = channel_data->handle; lum.cmd = LTTNG_UST_EVENT; @@ -200,6 +205,7 @@ int ustctl_add_context(int sock, struct lttng_ust_context *ctx, context_data = zmalloc(sizeof(*context_data)); if (!context_data) return -ENOMEM; + context_data->type = LTTNG_UST_OBJECT_TYPE_CONTEXT; memset(&lum, 0, sizeof(lum)); lum.handle = obj_data->handle; lum.cmd = LTTNG_UST_CONTEXT; @@ -209,8 +215,8 @@ int ustctl_add_context(int sock, struct lttng_ust_context *ctx, free(context_data); return ret; } - context_data->handle = lur.ret_val; - DBG("received context handle %u", context_data->handle); + context_data->handle = -1; + DBG("Context created successfully"); *_context_data = context_data; return ret; } @@ -779,7 +785,7 @@ struct ustctl_consumer_channel * transport = lttng_transport_find(transport_name); if (!transport) { DBG("LTTng transport %s not found\n", - transport_name); + transport_name); return NULL; } @@ -788,9 +794,9 @@ struct ustctl_consumer_channel * return NULL; chan->chan = transport->ops.channel_create(transport_name, NULL, - attr->subbuf_size, attr->num_subbuf, + attr->subbuf_size, attr->num_subbuf, attr->switch_timer_interval, - attr->read_timer_interval, + attr->read_timer_interval, attr->uuid); if (!chan->chan) { goto chan_error; @@ -1011,7 +1017,7 @@ int ustctl_get_mmap_read_offset(struct ustctl_consumer_stream *stream, if (chan->backend.config.output != RING_BUFFER_MMAP) return -EINVAL; sb_bindex = subbuffer_id_get_index(&chan->backend.config, - buf->backend.buf_rsb.id); + buf->backend.buf_rsb.id); *off = shmp(consumer_chan->chan->handle, shmp_index(consumer_chan->chan->handle, buf->backend.array, sb_bindex)->shmp)->mmap_offset; return 0; @@ -1169,6 +1175,344 @@ void ustctl_flush_buffer(struct ustctl_consumer_stream *stream, consumer_chan->chan->handle); } +/* + * Returns 0 on success, negative error value on error. + */ +int ustctl_recv_reg_msg(int sock, + enum ustctl_socket_type *type, + uint32_t *major, + uint32_t *minor, + uint32_t *pid, + uint32_t *ppid, + uint32_t *uid, + uint32_t *gid, + uint32_t *bits_per_long, + uint32_t *uint8_t_alignment, + uint32_t *uint16_t_alignment, + uint32_t *uint32_t_alignment, + uint32_t *uint64_t_alignment, + uint32_t *long_alignment, + int *byte_order, + char *name) +{ + ssize_t len; + struct ustctl_reg_msg reg_msg; + + len = ustcomm_recv_unix_sock(sock, ®_msg, sizeof(reg_msg)); + if (len > 0 && len != sizeof(reg_msg)) + return -EIO; + if (len == 0) + return -EPIPE; + if (len < 0) + return len; + + if (reg_msg.magic == LTTNG_UST_COMM_MAGIC) { + *byte_order = BYTE_ORDER == BIG_ENDIAN ? + BIG_ENDIAN : LITTLE_ENDIAN; + } else if (reg_msg.magic == bswap_32(LTTNG_UST_COMM_MAGIC)) { + *byte_order = BYTE_ORDER == BIG_ENDIAN ? + LITTLE_ENDIAN : BIG_ENDIAN; + } else { + return -LTTNG_UST_ERR_INVAL_MAGIC; + } + switch (reg_msg.socket_type) { + case 0: *type = USTCTL_SOCKET_CMD; + break; + case 1: *type = USTCTL_SOCKET_NOTIFY; + break; + default: + return -LTTNG_UST_ERR_INVAL_SOCKET_TYPE; + } + *major = reg_msg.major; + *minor = reg_msg.minor; + *pid = reg_msg.pid; + *ppid = reg_msg.ppid; + *uid = reg_msg.uid; + *gid = reg_msg.gid; + *bits_per_long = reg_msg.bits_per_long; + *uint8_t_alignment = reg_msg.uint8_t_alignment; + *uint16_t_alignment = reg_msg.uint16_t_alignment; + *uint32_t_alignment = reg_msg.uint32_t_alignment; + *uint64_t_alignment = reg_msg.uint64_t_alignment; + *long_alignment = reg_msg.long_alignment; + memcpy(name, reg_msg.name, LTTNG_UST_ABI_PROCNAME_LEN); + if (reg_msg.major != LTTNG_UST_ABI_MAJOR_VERSION) { + return -LTTNG_UST_ERR_UNSUP_MAJOR; + } + + return 0; +} + +int ustctl_recv_notify(int sock, enum ustctl_notify_cmd *notify_cmd) +{ + struct ustcomm_notify_hdr header; + ssize_t len; + + len = ustcomm_recv_unix_sock(sock, &header, sizeof(header)); + if (len > 0 && len != sizeof(header)) + return -EIO; + if (len == 0) + return -EPIPE; + if (len < 0) + return len; + switch (header.notify_cmd) { + case 0: + *notify_cmd = USTCTL_NOTIFY_CMD_EVENT; + break; + case 1: + *notify_cmd = USTCTL_NOTIFY_CMD_CHANNEL; + break; + default: + return -EINVAL; + } + return 0; +} + +/* + * Returns 0 on success, negative error value on error. + */ +int ustctl_recv_register_event(int sock, + int *session_objd, + int *channel_objd, + char *event_name, + int *loglevel, + char **signature, + size_t *nr_fields, + struct ustctl_field **fields, + char **model_emf_uri) +{ + ssize_t len; + struct ustcomm_notify_event_msg msg; + size_t signature_len, fields_len, model_emf_uri_len; + char *a_sign = NULL, *a_model_emf_uri = NULL; + struct ustctl_field *a_fields = NULL; + + len = ustcomm_recv_unix_sock(sock, &msg, sizeof(msg)); + if (len > 0 && len != sizeof(msg)) + return -EIO; + if (len == 0) + return -EPIPE; + if (len < 0) + return len; + + *session_objd = msg.session_objd; + *channel_objd = msg.channel_objd; + strncpy(event_name, msg.event_name, LTTNG_UST_SYM_NAME_LEN); + event_name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0'; + *loglevel = msg.loglevel; + signature_len = msg.signature_len; + fields_len = msg.fields_len; + + if (fields_len % sizeof(*a_fields) != 0) { + return -EINVAL; + } + + model_emf_uri_len = msg.model_emf_uri_len; + + /* recv signature. contains at least \0. */ + a_sign = zmalloc(signature_len); + if (!a_sign) + return -ENOMEM; + len = ustcomm_recv_unix_sock(sock, a_sign, signature_len); + if (len > 0 && len != signature_len) { + len = -EIO; + goto signature_error; + } + if (len == 0) { + len = -EPIPE; + goto signature_error; + } + if (len < 0) { + goto signature_error; + } + /* Enforce end of string */ + signature[signature_len - 1] = '\0'; + + /* recv fields */ + if (fields_len) { + a_fields = zmalloc(fields_len); + if (!a_fields) { + len = -ENOMEM; + goto signature_error; + } + len = ustcomm_recv_unix_sock(sock, a_fields, fields_len); + if (len > 0 && len != fields_len) { + len = -EIO; + goto fields_error; + } + if (len == 0) { + len = -EPIPE; + goto fields_error; + } + if (len < 0) { + goto fields_error; + } + } + + if (model_emf_uri_len) { + /* recv model_emf_uri_len */ + a_model_emf_uri = zmalloc(model_emf_uri_len); + if (!a_model_emf_uri) { + len = -ENOMEM; + goto fields_error; + } + len = ustcomm_recv_unix_sock(sock, a_model_emf_uri, + model_emf_uri_len); + if (len > 0 && len != model_emf_uri_len) { + len = -EIO; + goto model_error; + } + if (len == 0) { + len = -EPIPE; + goto model_error; + } + if (len < 0) { + goto model_error; + } + /* Enforce end of string */ + a_model_emf_uri[model_emf_uri_len - 1] = '\0'; + } + + *signature = a_sign; + *nr_fields = fields_len / sizeof(*a_fields); + *fields = a_fields; + *model_emf_uri = a_model_emf_uri; + + return 0; + +model_error: + free(a_model_emf_uri); +fields_error: + free(a_fields); +signature_error: + free(a_sign); + return len; +} + +/* + * Returns 0 on success, negative error value on error. + */ +int ustctl_reply_register_event(int sock, + uint32_t id, + int ret_code) +{ + ssize_t len; + struct { + struct ustcomm_notify_hdr header; + struct ustcomm_notify_event_reply r; + } reply; + + memset(&reply, 0, sizeof(reply)); + reply.header.notify_cmd = USTCTL_NOTIFY_CMD_EVENT; + reply.r.ret_code = ret_code; + reply.r.event_id = id; + len = ustcomm_send_unix_sock(sock, &reply, sizeof(reply)); + if (len > 0 && len != sizeof(reply)) + return -EIO; + if (len < 0) + return len; + return 0; +} + +/* + * Returns 0 on success, negative UST or system error value on error. + */ +int ustctl_recv_register_channel(int sock, + int *session_objd, /* session descriptor (output) */ + int *channel_objd, /* channel descriptor (output) */ + size_t *nr_fields, + struct ustctl_field **fields) +{ + ssize_t len; + struct ustcomm_notify_channel_msg msg; + size_t fields_len; + struct ustctl_field *a_fields; + + len = ustcomm_recv_unix_sock(sock, &msg, sizeof(msg)); + if (len > 0 && len != sizeof(msg)) + return -EIO; + if (len == 0) + return -EPIPE; + if (len < 0) + return len; + + *session_objd = msg.session_objd; + *channel_objd = msg.channel_objd; + fields_len = msg.ctx_fields_len; + + if (fields_len % sizeof(*a_fields) != 0) { + return -EINVAL; + } + + /* recv fields */ + if (fields_len) { + a_fields = zmalloc(fields_len); + if (!a_fields) { + len = -ENOMEM; + goto alloc_error; + } + len = ustcomm_recv_unix_sock(sock, a_fields, fields_len); + if (len > 0 && len != fields_len) { + len = -EIO; + goto fields_error; + } + if (len == 0) { + len = -EPIPE; + goto fields_error; + } + if (len < 0) { + goto fields_error; + } + *fields = a_fields; + } else { + *fields = NULL; + } + *nr_fields = fields_len / sizeof(*a_fields); + return 0; + +fields_error: + free(a_fields); +alloc_error: + return len; +} + +/* + * Returns 0 on success, negative error value on error. + */ +int ustctl_reply_register_channel(int sock, + uint32_t chan_id, + enum ustctl_channel_header header_type, + int ret_code) +{ + ssize_t len; + struct { + struct ustcomm_notify_hdr header; + struct ustcomm_notify_channel_reply r; + } reply; + + memset(&reply, 0, sizeof(reply)); + reply.header.notify_cmd = USTCTL_NOTIFY_CMD_CHANNEL; + reply.r.ret_code = ret_code; + reply.r.chan_id = chan_id; + switch (header_type) { + case USTCTL_CHANNEL_HEADER_COMPACT: + reply.r.header_type = 1; + break; + case USTCTL_CHANNEL_HEADER_LARGE: + reply.r.header_type = 2; + break; + default: + reply.r.header_type = 0; + break; + } + len = ustcomm_send_unix_sock(sock, &reply, sizeof(reply)); + if (len > 0 && len != sizeof(reply)) + return -EIO; + if (len < 0) + return len; + return 0; +} + static __attribute__((constructor)) void ustctl_init(void) { diff --git a/liblttng-ust/lttng-events.c b/liblttng-ust/lttng-events.c index 3bf1ede3..f77db60c 100644 --- a/liblttng-ust/lttng-events.c +++ b/liblttng-ust/lttng-events.c @@ -45,6 +45,8 @@ #include #include +#include +#include #include "error.h" #include "compat.h" #include "lttng-ust-uuid.h" @@ -203,12 +205,17 @@ int lttng_session_enable(struct lttng_session *session) { int ret = 0; struct lttng_channel *chan; + int notify_socket; if (session->active) { ret = -EBUSY; goto end; } + notify_socket = lttng_get_notify_socket(session->owner); + if (notify_socket < 0) + return notify_socket; + /* We need to sync enablers with session before activation. */ lttng_session_sync_enablers(session); @@ -217,12 +224,27 @@ int lttng_session_enable(struct lttng_session *session) * we need to use. */ cds_list_for_each_entry(chan, &session->chan_head, node) { + const struct lttng_ctx *ctx; + const struct lttng_event_field *fields = NULL; + size_t nr_fields = 0; + + /* don't change it if session stop/restart */ if (chan->header_type) - continue; /* don't change it if session stop/restart */ - if (chan->free_event_id < 31) - chan->header_type = 1; /* compact */ - else - chan->header_type = 2; /* large */ + continue; + ctx = chan->ctx; + if (ctx) { + nr_fields = ctx->nr_fields; + fields = &ctx->fields->event_field; + } + ret = ustcomm_register_channel(notify_socket, + session->objd, + chan->objd, + nr_fields, + fields, + &chan->id, + &chan->header_type); + if (ret) + return ret; } CMM_ACCESS_ONCE(session->active) = 1; @@ -304,16 +326,15 @@ int lttng_event_create(const struct lttng_event_desc *desc, { const char *event_name = desc->name; struct lttng_event *event; + struct lttng_session *session = chan->session; struct cds_hlist_head *head; struct cds_hlist_node *node; int ret = 0; size_t name_len = strlen(event_name); uint32_t hash; + int notify_socket, loglevel; + const char *uri; - if (chan->used_event_id == -1U) { - ret = -ENOMEM; - goto full; - } hash = jhash(event_name, name_len, 0); head = &chan->session->events_ht.table[hash & (LTTNG_UST_EVENT_HT_SIZE - 1)]; cds_hlist_for_each_entry(event, node, head, hlist) { @@ -326,6 +347,12 @@ int lttng_event_create(const struct lttng_event_desc *desc, } } + notify_socket = lttng_get_notify_socket(session->owner); + if (notify_socket < 0) { + ret = notify_socket; + goto socket_error; + } + /* * Check if loglevel match. Refuse to connect event if not. */ @@ -336,23 +363,42 @@ int lttng_event_create(const struct lttng_event_desc *desc, } event->chan = chan; - /* - * used_event_id counts the maximum number of event IDs that can - * register if all probes register. - */ - chan->used_event_id++; event->enabled = 1; CDS_INIT_LIST_HEAD(&event->bytecode_runtime_head); CDS_INIT_LIST_HEAD(&event->enablers_ref_head); event->desc = desc; + + if (desc->loglevel) + loglevel = *(*event->desc->loglevel); + else + loglevel = TRACE_DEFAULT; + if (desc->u.ext.model_emf_uri) + uri = *(desc->u.ext.model_emf_uri); + else + uri = NULL; + + /* Fetch event ID from sessiond */ + ret = ustcomm_register_event(notify_socket, + session->objd, + chan->objd, + event_name, + loglevel, + desc->signature, + desc->nr_fields, + desc->fields, + uri, + &event->id); + if (ret < 0) { + goto sessiond_register_error; + } /* Populate lttng_event structure before tracepoint registration. */ cmm_smp_wmb(); ret = __tracepoint_probe_register(event_name, desc->probe_callback, event, desc->signature); if (ret) - goto register_error; - event->id = chan->free_event_id++; + goto tracepoint_register_error; + ret = _lttng_event_metadata_statedump(chan->session, chan, event); if (ret) goto statedump_error; @@ -364,11 +410,12 @@ statedump_error: WARN_ON_ONCE(__tracepoint_probe_unregister(event_name, desc->probe_callback, event)); -register_error: +tracepoint_register_error: +sessiond_register_error: free(event); cache_error: +socket_error: exist: -full: return ret; } @@ -507,8 +554,8 @@ void lttng_create_event_if_missing(struct lttng_enabler *enabler) ret = lttng_event_create(probe_desc->event_desc[i], enabler->chan); if (ret) { - DBG("Unable to create event %s\n", - probe_desc->event_desc[i]->name); + DBG("Unable to create event %s, error %d\n", + probe_desc->event_desc[i]->name, ret); } } } diff --git a/liblttng-ust/lttng-tracer-core.h b/liblttng-ust/lttng-tracer-core.h index f2e95674..f643a7e5 100644 --- a/liblttng-ust/lttng-tracer-core.h +++ b/liblttng-ust/lttng-tracer-core.h @@ -43,4 +43,6 @@ void lttng_fixup_procname_tls(void); const char *lttng_ust_obj_get_name(int id); +int lttng_get_notify_socket(void *owner); + #endif /* _LTTNG_TRACER_CORE_H */ diff --git a/liblttng-ust/lttng-ust-abi.c b/liblttng-ust/lttng-ust-abi.c index 006e9962..1e146e61 100644 --- a/liblttng-ust/lttng-ust-abi.c +++ b/liblttng-ust/lttng-ust-abi.c @@ -294,6 +294,7 @@ int lttng_abi_create_session(void *owner) goto objd_error; } session->objd = session_objd; + session->owner = owner; return session_objd; objd_error: @@ -305,9 +306,9 @@ static long lttng_abi_tracer_version(int objd, struct lttng_ust_tracer_version *v) { - v->major = LTTNG_UST_INTERNAL_MAJOR_VERSION; - v->minor = LTTNG_UST_INTERNAL_MINOR_VERSION; - v->patchlevel = LTTNG_UST_INTERNAL_PATCHLEVEL_VERSION; + v->major = LTTNG_UST_MAJOR_VERSION; + v->minor = LTTNG_UST_MINOR_VERSION; + v->patchlevel = LTTNG_UST_PATCHLEVEL_VERSION; return 0; } @@ -498,8 +499,6 @@ int lttng_abi_map_channel(int session_objd, 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, @@ -508,7 +507,6 @@ int lttng_abi_map_channel(int session_objd, 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; /* diff --git a/liblttng-ust/lttng-ust-comm.c b/liblttng-ust/lttng-ust-comm.c index a1ebcbe6..5a4b6bd8 100644 --- a/liblttng-ust/lttng-ust-comm.c +++ b/liblttng-ust/lttng-ust-comm.c @@ -102,6 +102,7 @@ struct sock_info { char sock_path[PATH_MAX]; int socket; + int notify_socket; char wait_shm_path[PATH_MAX]; char *wait_shm_mmap; @@ -116,10 +117,11 @@ struct sock_info global_apps = { .allowed = 1, .thread_active = 0, - .sock_path = DEFAULT_GLOBAL_APPS_UNIX_SOCK, + .sock_path = LTTNG_DEFAULT_RUNDIR "/" LTTNG_UST_SOCK_FILENAME, .socket = -1, + .notify_socket = -1, - .wait_shm_path = DEFAULT_GLOBAL_APPS_WAIT_SHM_PATH, + .wait_shm_path = "/" LTTNG_UST_WAIT_FILENAME, }; /* TODO: allow global_apps_sock_path override */ @@ -132,6 +134,7 @@ struct sock_info local_apps = { .thread_active = 0, .socket = -1, + .notify_socket = -1, }; static int wait_poll_fallback; @@ -187,6 +190,13 @@ void lttng_fixup_nest_count_tls(void) asm volatile ("" : : "m" (URCU_TLS(lttng_ust_nest_count))); } +int lttng_get_notify_socket(void *owner) +{ + struct sock_info *info = owner; + + return info->notify_socket; +} + static void print_cmd(int cmd, int handle) { @@ -220,41 +230,27 @@ int setup_local_apps(void) return -ENOENT; } local_apps.allowed = 1; - snprintf(local_apps.sock_path, PATH_MAX, - DEFAULT_HOME_APPS_UNIX_SOCK, home_dir); - snprintf(local_apps.wait_shm_path, PATH_MAX, - DEFAULT_HOME_APPS_WAIT_SHM_PATH, uid); + snprintf(local_apps.sock_path, PATH_MAX, "%s/%s/%s", + home_dir, + LTTNG_DEFAULT_HOME_RUNDIR, + LTTNG_UST_SOCK_FILENAME); + snprintf(local_apps.wait_shm_path, PATH_MAX, "/%s-%u", + LTTNG_UST_WAIT_FILENAME, + uid); return 0; } static -int register_app_to_sessiond(int socket) +int register_to_sessiond(int socket, enum ustctl_socket_type type) { - ssize_t ret; - struct { - uint32_t major; - uint32_t minor; - pid_t pid; - pid_t ppid; - uid_t uid; - gid_t gid; - uint32_t bits_per_long; - char name[16]; /* process name */ - } reg_msg; - - reg_msg.major = LTTNG_UST_COMM_VERSION_MAJOR; - reg_msg.minor = LTTNG_UST_COMM_VERSION_MINOR; - reg_msg.pid = getpid(); - reg_msg.ppid = getppid(); - reg_msg.uid = getuid(); - reg_msg.gid = getgid(); - reg_msg.bits_per_long = CAA_BITS_PER_LONG; - lttng_ust_getprocname(reg_msg.name); - - ret = ustcomm_send_unix_sock(socket, ®_msg, sizeof(reg_msg)); - if (ret >= 0 && ret != sizeof(reg_msg)) - return -EIO; - return ret; + return ustcomm_send_reg_msg(socket, + type, + CAA_BITS_PER_LONG, + lttng_alignof(uint8_t) * CHAR_BIT, + lttng_alignof(uint16_t) * CHAR_BIT, + lttng_alignof(uint32_t) * CHAR_BIT, + lttng_alignof(uint64_t) * CHAR_BIT, + lttng_alignof(unsigned long) * CHAR_BIT); } static @@ -561,10 +557,17 @@ void cleanup_sock_info(struct sock_info *sock_info, int exiting) if (sock_info->socket != -1) { ret = ustcomm_close_unix_sock(sock_info->socket); if (ret) { - ERR("Error closing apps socket"); + ERR("Error closing ust cmd socket"); } sock_info->socket = -1; } + if (sock_info->notify_socket != -1) { + ret = ustcomm_close_unix_sock(sock_info->notify_socket); + if (ret) { + ERR("Error closing ust notify socket"); + } + sock_info->notify_socket = -1; + } if (sock_info->root_handle != -1) { ret = lttng_ust_objd_unref(sock_info->root_handle); if (ret) { @@ -815,6 +818,8 @@ void *ust_listener_thread(void *arg) { struct sock_info *sock_info = arg; int sock, ret, prev_connect_failed = 0, has_waited = 0; + int open_sock[2]; + int i; /* Restart trying to connect to the session daemon */ restart: @@ -842,27 +847,40 @@ restart: if (sock_info->socket != -1) { ret = ustcomm_close_unix_sock(sock_info->socket); if (ret) { - ERR("Error closing %s apps socket", sock_info->name); + ERR("Error closing %s ust cmd socket", + sock_info->name); } sock_info->socket = -1; } + if (sock_info->notify_socket != -1) { + ret = ustcomm_close_unix_sock(sock_info->notify_socket); + if (ret) { + ERR("Error closing %s ust notify socket", + sock_info->name); + } + sock_info->notify_socket = -1; + } /* Register */ - ret = ustcomm_connect_unix_sock(sock_info->sock_path); - if (ret < 0) { - DBG("Info: sessiond not accepting connections to %s apps socket", sock_info->name); - prev_connect_failed = 1; - /* - * If we cannot find the sessiond daemon, don't delay - * constructor execution. - */ - ret = handle_register_done(sock_info); - assert(!ret); - ust_unlock(); - goto restart; + for (i = 0; i < 2; i++) { + ret = ustcomm_connect_unix_sock(sock_info->sock_path); + if (ret < 0) { + DBG("Info: sessiond not accepting connections to %s apps socket", sock_info->name); + prev_connect_failed = 1; + /* + * If we cannot find the sessiond daemon, don't delay + * constructor execution. + */ + ret = handle_register_done(sock_info); + assert(!ret); + ust_unlock(); + goto restart; + } + open_sock[i] = ret; } - sock_info->socket = sock = ret; + sock_info->socket = open_sock[0]; + sock_info->notify_socket = open_sock[1]; /* * Create only one root handle per listener thread for the whole @@ -878,9 +896,10 @@ restart: sock_info->root_handle = ret; } - ret = register_app_to_sessiond(sock); + ret = register_to_sessiond(sock_info->socket, USTCTL_SOCKET_CMD); if (ret < 0) { - ERR("Error registering to %s apps socket", sock_info->name); + ERR("Error registering to %s ust cmd socket", + sock_info->name); prev_connect_failed = 1; /* * If we cannot register to the sessiond daemon, don't @@ -891,6 +910,23 @@ restart: ust_unlock(); goto restart; } + ret = register_to_sessiond(sock_info->notify_socket, + USTCTL_SOCKET_NOTIFY); + if (ret < 0) { + ERR("Error registering to %s ust notify socket", + sock_info->name); + prev_connect_failed = 1; + /* + * If we cannot register to the sessiond daemon, don't + * delay constructor execution. + */ + ret = handle_register_done(sock_info); + assert(!ret); + ust_unlock(); + goto restart; + } + sock = sock_info->socket; + ust_unlock(); for (;;) { -- 2.34.1