X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fust-app.c;h=e496a5f5548f78975fba58d773da3c8aa45d8d58;hp=285467fbbacac990864a0871d18f200a0eb7f67b;hb=3a6922c6ab7b4d9455f517ac0bf86dfcede0ef3d;hpb=ee02239944bbb8b019bf5505bfc849fb0936e2f6 diff --git a/src/bin/lttng-sessiond/ust-app.c b/src/bin/lttng-sessiond/ust-app.c index 285467fbb..e496a5f55 100644 --- a/src/bin/lttng-sessiond/ust-app.c +++ b/src/bin/lttng-sessiond/ust-app.c @@ -376,6 +376,8 @@ void delete_ust_app_channel_rcu(struct rcu_head *head) * Extract the lost packet or discarded events counter when the channel is * being deleted and store the value in the parent channel so we can * access it from lttng list and at stop/destroy. + * + * The session list lock must be held by the caller. */ static void save_per_pid_lost_discarded_counters(struct ust_app_channel *ua_chan) @@ -390,12 +392,22 @@ void save_per_pid_lost_discarded_counters(struct ust_app_channel *ua_chan) rcu_read_lock(); session = session_find_by_id(ua_chan->session->tracing_id); - if (!session) { - ERR("Missing LTT session to get discarded events"); - goto end; - } - if (!session->ust_session) { - ERR("Missing UST session to get discarded events"); + if (!session || !session->ust_session) { + /* + * Not finding the session is not an error because there are + * multiple ways the channels can be torn down. + * + * 1) The session daemon can initiate the destruction of the + * ust app session after receiving a destroy command or + * during its shutdown/teardown. + * 2) The application, since we are in per-pid tracing, is + * unregistering and tearing down its ust app session. + * + * Both paths are protected by the session list lock which + * ensures that the accounting of lost packets and discarded + * events is done exactly once. The session is then unpublished + * from the session list, resulting in this condition. + */ goto end; } @@ -426,6 +438,8 @@ end: /* * Delete ust app channel safely. RCU read lock must be held before calling * this function. + * + * The session list lock must be held by the caller. */ static void delete_ust_app_channel(int sock, struct ust_app_channel *ua_chan, @@ -537,7 +551,7 @@ ssize_t ust_app_push_metadata(struct ust_registry_session *registry, char *metadata_str = NULL; size_t len, offset, new_metadata_len_sent; ssize_t ret_val; - uint64_t metadata_key; + uint64_t metadata_key, metadata_version; assert(registry); assert(socket); @@ -567,6 +581,7 @@ ssize_t ust_app_push_metadata(struct ust_registry_session *registry, offset = registry->metadata_len_sent; len = registry->metadata_len - registry->metadata_len_sent; new_metadata_len_sent = registry->metadata_len; + metadata_version = registry->metadata_version; if (len == 0) { DBG3("No metadata to push for metadata key %" PRIu64, registry->metadata_key); @@ -603,7 +618,7 @@ push_data: * different bidirectionnal communication sockets. */ ret = consumer_push_metadata(socket, metadata_key, - metadata_str, len, offset); + metadata_str, len, offset, metadata_version); pthread_mutex_lock(®istry->lock); if (ret < 0) { /* @@ -787,6 +802,8 @@ void delete_ust_app_session_rcu(struct rcu_head *head) /* * Delete ust app session safely. RCU read lock must be held before calling * this function. + * + * The session list lock must be held by the caller. */ static void delete_ust_app_session(int sock, struct ust_app_session *ua_sess, @@ -870,6 +887,11 @@ void delete_ust_app(struct ust_app *app) int ret, sock; struct ust_app_session *ua_sess, *tmp_ua_sess; + /* + * The session list lock must be held during this function to guarantee + * the existence of ua_sess. + */ + session_lock_list(); /* Delete ust app sessions info */ sock = app->sock; app->sock = -1; @@ -908,6 +930,7 @@ void delete_ust_app(struct ust_app *app) DBG2("UST app pid %d deleted", app->pid); free(app); + session_unlock_list(); } /* @@ -928,6 +951,8 @@ void delete_ust_app_rcu(struct rcu_head *head) /* * Delete the session from the application ht and delete the data structure by * freeing every object inside and releasing them. + * + * The session list lock must be held by the caller. */ static void destroy_app_session(struct ust_app *app, struct ust_app_session *ua_sess) @@ -2796,9 +2821,6 @@ static int send_channel_uid_to_ust(struct buffer_reg_channel *reg_chan, (void) release_ust_app_stream(-1, &stream, app); if (ret == -EPIPE || ret == -LTTNG_UST_ERR_EXITING) { ret = -ENOTCONN; /* Caused by app exiting. */ - goto error_stream_unlock; - } else if (ret < 0) { - goto error_stream_unlock; } goto error_stream_unlock; } @@ -4625,6 +4647,155 @@ int ust_app_flush_session(struct ltt_ust_session *usess) return ret; } +static +int ust_app_clear_quiescent_app_session(struct ust_app *app, + struct ust_app_session *ua_sess) +{ + int ret = 0; + struct lttng_ht_iter iter; + struct ust_app_channel *ua_chan; + struct consumer_socket *socket; + + DBG("Clearing stream quiescent state for ust app pid %d", app->pid); + + rcu_read_lock(); + + if (!app->compatible) { + goto end_not_compatible; + } + + pthread_mutex_lock(&ua_sess->lock); + + if (ua_sess->deleted) { + goto end_unlock; + } + + health_code_update(); + + socket = consumer_find_socket_by_bitness(app->bits_per_long, + ua_sess->consumer); + if (!socket) { + ERR("Failed to find consumer (%" PRIu32 ") socket", + app->bits_per_long); + ret = -1; + goto end_unlock; + } + + /* Clear quiescent state. */ + switch (ua_sess->buffer_type) { + case LTTNG_BUFFER_PER_PID: + cds_lfht_for_each_entry(ua_sess->channels->ht, &iter.iter, + ua_chan, node.node) { + health_code_update(); + ret = consumer_clear_quiescent_channel(socket, + ua_chan->key); + if (ret) { + ERR("Error clearing quiescent state for consumer channel"); + ret = -1; + continue; + } + } + break; + case LTTNG_BUFFER_PER_UID: + default: + assert(0); + ret = -1; + break; + } + + health_code_update(); + +end_unlock: + pthread_mutex_unlock(&ua_sess->lock); + +end_not_compatible: + rcu_read_unlock(); + health_code_update(); + return ret; +} + +/* + * Clear quiescent state in each stream for all applications for a + * specific UST session. + * Called with UST session lock held. + */ +static +int ust_app_clear_quiescent_session(struct ltt_ust_session *usess) + +{ + int ret = 0; + + DBG("Clearing stream quiescent state for all ust apps"); + + rcu_read_lock(); + + switch (usess->buffer_type) { + case LTTNG_BUFFER_PER_UID: + { + struct lttng_ht_iter iter; + struct buffer_reg_uid *reg; + + /* + * Clear quiescent for all per UID buffers associated to + * that session. + */ + cds_list_for_each_entry(reg, &usess->buffer_reg_uid_list, lnode) { + struct consumer_socket *socket; + struct buffer_reg_channel *reg_chan; + + /* Get associated consumer socket.*/ + socket = consumer_find_socket_by_bitness( + reg->bits_per_long, usess->consumer); + if (!socket) { + /* + * Ignore request if no consumer is found for + * the session. + */ + continue; + } + + cds_lfht_for_each_entry(reg->registry->channels->ht, + &iter.iter, reg_chan, node.node) { + /* + * The following call will print error values so + * the return code is of little importance + * because whatever happens, we have to try them + * all. + */ + (void) consumer_clear_quiescent_channel(socket, + reg_chan->consumer_key); + } + } + break; + } + case LTTNG_BUFFER_PER_PID: + { + struct ust_app_session *ua_sess; + struct lttng_ht_iter iter; + struct ust_app *app; + + cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, + pid_n.node) { + ua_sess = lookup_session_by_app(usess, app); + if (ua_sess == NULL) { + continue; + } + (void) ust_app_clear_quiescent_app_session(app, + ua_sess); + } + break; + } + default: + ret = -1; + assert(0); + break; + } + + rcu_read_unlock(); + health_code_update(); + return ret; +} + /* * Destroy a specific UST session in apps. */ @@ -4683,6 +4854,14 @@ int ust_app_start_trace_all(struct ltt_ust_session *usess) rcu_read_lock(); + /* + * In a start-stop-start use-case, we need to clear the quiescent state + * of each channel set by the prior stop command, thus ensuring that a + * following stop or destroy is sure to grab a timestamp_end near those + * operations, even if the packet is empty. + */ + (void) ust_app_clear_quiescent_session(usess); + cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) { ret = ust_app_start_trace(usess, app); if (ret < 0) { @@ -5024,54 +5203,6 @@ end: return ret; } -/* - * Calibrate registered applications. - */ -int ust_app_calibrate_glb(struct lttng_ust_calibrate *calibrate) -{ - int ret = 0; - struct lttng_ht_iter iter; - struct ust_app *app; - - rcu_read_lock(); - - cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) { - if (!app->compatible) { - /* - * TODO: In time, we should notice the caller of this error by - * telling him that this is a version error. - */ - continue; - } - - health_code_update(); - - pthread_mutex_lock(&app->sock_lock); - ret = ustctl_calibrate(app->sock, calibrate); - pthread_mutex_unlock(&app->sock_lock); - if (ret < 0) { - switch (ret) { - case -ENOSYS: - /* Means that it's not implemented on the tracer side. */ - ret = 0; - break; - default: - DBG2("Calibrate app PID %d returned with error %d", - app->pid, ret); - break; - } - } - } - - DBG("UST app global domain calibration finished"); - - rcu_read_unlock(); - - health_code_update(); - - return ret; -} - /* * Receive registration and populate the given msg structure. * @@ -5701,7 +5832,6 @@ int ust_app_snapshot_record(struct ltt_ust_session *usess, uint64_t nb_packets_per_stream) { int ret = 0; - unsigned int snapshot_done = 0; struct lttng_ht_iter iter; struct ust_app *app; char pathname[PATH_MAX]; @@ -5753,7 +5883,6 @@ int ust_app_snapshot_record(struct ltt_ust_session *usess, if (ret < 0) { goto error; } - snapshot_done = 1; } break; } @@ -5806,7 +5935,6 @@ int ust_app_snapshot_record(struct ltt_ust_session *usess, if (ret < 0) { goto error; } - snapshot_done = 1; } break; } @@ -5815,15 +5943,6 @@ int ust_app_snapshot_record(struct ltt_ust_session *usess, break; } - if (!snapshot_done) { - /* - * If no snapshot was made and we are not in the error path, this means - * that there are no buffers thus no (prior) application to snapshot - * data from so we have simply NO data. - */ - ret = -ENODATA; - } - error: rcu_read_unlock(); return ret; @@ -5920,9 +6039,11 @@ int ust_app_uid_get_channel_runtime_stats(uint64_t ust_session_id, if (overwrite) { ret = consumer_get_lost_packets(ust_session_id, consumer_chan_key, consumer, lost); + *discarded = 0; } else { ret = consumer_get_discarded_events(ust_session_id, consumer_chan_key, consumer, discarded); + *lost = 0; } end: @@ -5965,16 +6086,83 @@ int ust_app_pid_get_channel_runtime_stats(struct ltt_ust_session *usess, if (overwrite) { ret = consumer_get_lost_packets(usess->id, ua_chan->key, consumer, lost); + *discarded = 0; goto end; } else { ret = consumer_get_discarded_events(usess->id, ua_chan->key, consumer, discarded); + *lost = 0; goto end; } + } + +end: + rcu_read_unlock(); + return ret; +} + +static +int ust_app_regenerate_statedump(struct ltt_ust_session *usess, + struct ust_app *app) +{ + int ret = 0; + struct ust_app_session *ua_sess; + + DBG("Regenerating the metadata for ust app pid %d", app->pid); + + rcu_read_lock(); + + ua_sess = lookup_session_by_app(usess, app); + if (ua_sess == NULL) { + /* The session is in teardown process. Ignore and continue. */ goto end; } + pthread_mutex_lock(&ua_sess->lock); + + if (ua_sess->deleted) { + goto end_unlock; + } + + pthread_mutex_lock(&app->sock_lock); + ret = ustctl_regenerate_statedump(app->sock, ua_sess->handle); + pthread_mutex_unlock(&app->sock_lock); + +end_unlock: + pthread_mutex_unlock(&ua_sess->lock); + end: rcu_read_unlock(); + health_code_update(); return ret; } + +/* + * Regenerate the statedump for each app in the session. + */ +int ust_app_regenerate_statedump_all(struct ltt_ust_session *usess) +{ + int ret = 0; + struct lttng_ht_iter iter; + struct ust_app *app; + + DBG("Regenerating the metadata for all UST apps"); + + rcu_read_lock(); + + cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) { + if (!app->compatible) { + continue; + } + + ret = ust_app_regenerate_statedump(usess, app); + if (ret < 0) { + /* Continue to the next app even on error */ + continue; + } + } + + rcu_read_unlock(); + + return 0; +}