void delete_ust_app(struct ust_app *app)
{
int ret, sock;
- struct lttng_ht_iter iter;
- struct ust_app_session *ua_sess;
+ struct ust_app_session *ua_sess, *tmp_ua_sess;
rcu_read_lock();
sock = app->sock;
app->sock = -1;
+ lttng_ht_destroy(app->sessions);
+
/* Wipe sessions */
- cds_lfht_for_each_entry(app->sessions->ht, &iter.iter, ua_sess,
- node.node) {
- ret = lttng_ht_del(app->sessions, &iter);
- if (ret) {
- /* The session is already scheduled for teardown. */
- continue;
- }
- delete_ust_app_session(app->sock, ua_sess);
+ cds_list_for_each_entry_safe(ua_sess, tmp_ua_sess, &app->teardown_head,
+ teardown_node) {
+ /* Free every object in the session and the session. */
+ delete_ust_app_session(sock, ua_sess);
}
- lttng_ht_destroy(app->sessions);
/*
* Wait until we have deleted the application from the sock hash table
}
/*
- * Create UST app channel and create it on the tracer.
+ * Create UST app channel and create it on the tracer. Set ua_chanp of the
+ * newly created channel if not NULL.
*/
-static struct ust_app_channel *create_ust_app_channel(
- struct ust_app_session *ua_sess, struct ltt_ust_channel *uchan,
- struct ust_app *app)
+static int create_ust_app_channel(struct ust_app_session *ua_sess,
+ struct ltt_ust_channel *uchan, struct ust_app *app,
+ struct ust_app_channel **ua_chanp)
{
int ret = 0;
struct lttng_ht_iter iter;
ua_chan = alloc_ust_app_channel(uchan->name, &uchan->attr);
if (ua_chan == NULL) {
/* Only malloc can fail here */
+ ret = -ENOMEM;
goto error;
}
shadow_copy_channel(ua_chan, uchan);
goto error;
}
+ /* Only add the channel if successful on the tracer side. */
lttng_ht_add_unique_str(ua_sess->channels, &ua_chan->node);
DBG2("UST app create channel %s for PID %d completed", ua_chan->name,
app->pid);
end:
- return ua_chan;
+ if (ua_chanp) {
+ *ua_chanp = ua_chan;
+ }
+
+ /* Everything went well. */
+ return 0;
error:
delete_ust_app_channel(-1, ua_chan);
- return NULL;
+ return ret;
}
/*
lta->sock = sock;
lttng_ht_node_init_ulong(<a->sock_n, (unsigned long)lta->sock);
+ CDS_INIT_LIST_HEAD(<a->teardown_head);
+
rcu_read_lock();
/*
struct ust_app *lta;
struct lttng_ht_node_ulong *node;
struct lttng_ht_iter iter;
+ struct ust_app_session *ua_sess;
int ret;
rcu_read_lock();
lta->pid);
}
+ /* Remove sessions so they are not visible during deletion.*/
+ cds_lfht_for_each_entry(lta->sessions->ht, &iter.iter, ua_sess,
+ node.node) {
+ ret = lttng_ht_del(lta->sessions, &iter);
+ if (ret) {
+ /* The session was already removed so scheduled for teardown. */
+ continue;
+ }
+
+ /*
+ * Add session to list for teardown. This is safe since at this point we
+ * are the only one using this list.
+ */
+ cds_list_add(&ua_sess->teardown_node, <a->teardown_head);
+ }
+
/* Free memory */
call_rcu(<a->pid_n.head, delete_ust_app_rcu);
struct lttng_ht_iter iter;
struct ust_app *app;
struct ust_app_session *ua_sess;
- struct ust_app_channel *ua_chan;
/* Very wrong code flow */
assert(usess);
ua_sess = create_ust_app_session(usess, app);
if (ua_sess == NULL) {
/* The malloc() failed. */
- ret = -1;
- goto error;
+ ret = -ENOMEM;
+ goto error_rcu_unlock;
} else if (ua_sess == (void *) -1UL) {
- /* The application's socket is not valid. Contiuing */
- ret = -1;
+ /*
+ * The application's socket is not valid. Either a bad socket or a
+ * timeout on it. We can't inform yet the caller that for a
+ * specific app, the session failed so we continue here.
+ */
continue;
}
- /* Create channel onto application */
- ua_chan = create_ust_app_channel(ua_sess, uchan, app);
- if (ua_chan == NULL) {
- /* Major problem here and it's maybe the tracer or malloc() */
- ret = -1;
- goto error;
+ /* Create channel onto application. We don't need the chan ref. */
+ ret = create_ust_app_channel(ua_sess, uchan, app, NULL);
+ if (ret < 0 && ret == -ENOMEM) {
+ /* No more memory is a fatal error. Stop right now. */
+ goto error_rcu_unlock;
}
}
+error_rcu_unlock:
rcu_read_unlock();
-
-error:
return ret;
}
ua_sess = lookup_session_by_app(usess, app);
if (ua_sess == NULL) {
- goto error_rcu_unlock;
+ /* The session is in teardown process. Ignore and continue. */
+ goto end;
}
/* Upon restart, we skip the setup, already done */
}
}
- /* Indicate that the session has been started once */
- ua_sess->started = 1;
-
ret = create_ust_app_metadata(ua_sess, usess->pathname, app);
if (ret < 0) {
ret = LTTNG_ERR_UST_META_FAIL;
goto error_rcu_unlock;
}
+ /* Indicate that the session has been started once */
+ ua_sess->started = 1;
+
health_code_update(&health_thread_cmd);
/* Quiescent wait after starting trace */
ua_sess = lookup_session_by_app(usess, app);
if (ua_sess == NULL) {
- /* Only malloc can failed so something is really wrong */
- goto error_rcu_unlock;
+ goto end;
}
/*
* If started = 0, it means that stop trace has been called for a session
- * that was never started. This is a code flow error and should never
- * happen.
+ * that was never started. It's possible since we can have a fail start
+ * from either the application manager thread or the command thread. Simply
+ * indicate that this is a stop error.
*/
- assert(ua_sess->started == 1);
+ if (ua_sess->started == 1) {
+ goto error_rcu_unlock;
+ }
health_code_update(&health_thread_cmd);
/*
* Destroy a specific UST session in apps.
*/
-int ust_app_destroy_trace(struct ltt_ust_session *usess, struct ust_app *app)
+static int destroy_trace(struct ltt_ust_session *usess, struct ust_app *app)
{
struct ust_app_session *ua_sess;
struct lttng_ust_object_data obj;
__lookup_session_by_app(usess, app, &iter);
node = lttng_ht_iter_get_node_ulong(&iter);
if (node == NULL) {
- /* Only malloc can failed so something is really wrong */
- goto error_rcu_unlock;
+ /* Session is being or is deleted. */
+ goto end;
}
ua_sess = caa_container_of(node, struct ust_app_session, node);
ret = lttng_ht_del(app->sessions, &iter);
rcu_read_unlock();
health_code_update(&health_thread_cmd);
return 0;
-
-error_rcu_unlock:
- rcu_read_unlock();
- health_code_update(&health_thread_cmd);
- return -1;
}
/*
rcu_read_lock();
cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) {
- ret = ust_app_destroy_trace(usess, app);
+ ret = destroy_trace(usess, app);
if (ret < 0) {
/* Continue to next apps even on error */
continue;
struct ust_app_event *ua_event;
struct ust_app_ctx *ua_ctx;
- if (usess == NULL) {
- ERR("No UST session on global update. Returning");
- goto error;
- }
+ assert(usess);
DBG2("UST app global update for app sock %d for session id %d", sock,
usess->id);