Fix: big relayd cleanup and refactor
[lttng-tools.git] / src / bin / lttng-relayd / session.c
CommitLineData
2f8f53af
DG
1/*
2 * Copyright (C) 2013 - Julien Desfossez <jdesfossez@efficios.com>
3 * David Goulet <dgoulet@efficios.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License, version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 51
16 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
2a174661
DG
19#define _GNU_SOURCE
20#include <common/common.h>
21
22#include "ctf-trace.h"
2f8f53af 23#include "session.h"
2a174661
DG
24#include "stream.h"
25
26/* Global session id used in the session creation. */
27static uint64_t last_relay_session_id;
28
29static void rcu_destroy_session(struct rcu_head *head)
30{
31 struct relay_session *session =
32 caa_container_of(head, struct relay_session, rcu_node);
33
34 free(session);
35}
36
37/*
38 * Create a new session by assigning a new session ID.
39 *
40 * Return allocated session or else NULL.
41 */
42struct relay_session *session_create(void)
43{
44 struct relay_session *session;
45
46 session = zmalloc(sizeof(*session));
47 if (!session) {
48 PERROR("relay session zmalloc");
49 goto error;
50 }
51
52 session->ctf_traces_ht = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
53 if (!session->ctf_traces_ht) {
54 free(session);
55 goto error;
56 }
57
58 pthread_mutex_init(&session->viewer_ready_lock, NULL);
59 session->id = ++last_relay_session_id;
60 lttng_ht_node_init_u64(&session->session_n, session->id);
61
62error:
63 return session;
64}
2f8f53af
DG
65
66/*
67 * Lookup a session within the given hash table and session id. RCU read side
68 * lock MUST be acquired before calling this and as long as the caller has a
69 * reference to the object.
70 *
71 * Return session or NULL if not found.
72 */
73struct relay_session *session_find_by_id(struct lttng_ht *ht, uint64_t id)
74{
75 struct relay_session *session = NULL;
2a174661 76 struct lttng_ht_node_u64 *node;
2f8f53af
DG
77 struct lttng_ht_iter iter;
78
79 assert(ht);
80
2a174661
DG
81 lttng_ht_lookup(ht, &id, &iter);
82 node = lttng_ht_iter_get_node_u64(&iter);
2f8f53af 83 if (!node) {
2a174661 84 DBG("Session find by ID %" PRIu64 " id NOT found", id);
2f8f53af
DG
85 goto end;
86 }
87 session = caa_container_of(node, struct relay_session, session_n);
2a174661 88 DBG("Session find by ID %" PRIu64 " id found", id);
2f8f53af
DG
89
90end:
91 return session;
92}
2a174661
DG
93
94/*
95 * Delete session from the given hash table.
96 *
97 * Return lttng ht del error code being 0 on success and 1 on failure.
98 */
99int session_delete(struct lttng_ht *ht, struct relay_session *session)
100{
101 struct lttng_ht_iter iter;
102
103 assert(ht);
104 assert(session);
105
106 iter.iter.node = &session->session_n.node;
107 return lttng_ht_del(ht, &iter);
108}
109
110/*
111 * The caller MUST be from the viewer thread since the viewer refcount is
112 * decremented. With this calue down to 0, it will try to destroy the session.
113 */
114void session_viewer_try_destroy(struct lttng_ht *ht,
115 struct relay_session *session)
116{
117 unsigned long ret_ref;
118
119 assert(session);
120
121 ret_ref = uatomic_add_return(&session->viewer_refcount, -1);
122 if (ret_ref == 0) {
123 session_try_destroy(ht, session);
124 }
125}
126
127/*
128 * Should only be called from the main streaming thread since it does not touch
129 * the viewer refcount. If this refcount is down to 0, destroy the session only
130 * and only if the session deletion succeeds. This is done because the viewer
131 * *and* the streaming thread can both concurently try to destroy the session
132 * thus the first come first serve.
133 */
134void session_try_destroy(struct lttng_ht *ht, struct relay_session *session)
135{
136 int ret = 0;
137 unsigned long ret_ref;
138
139 assert(session);
140
141 ret_ref = uatomic_read(&session->viewer_refcount);
142 if (ret_ref == 0 && session->close_flag) {
143 if (ht) {
144 ret = session_delete(ht, session);
145 }
146 if (!ret) {
147 /* Only destroy the session if the deletion was successful. */
148 session_destroy(session);
149 }
150 }
151}
152
153/*
154 * Destroy a session object.
155 */
156void session_destroy(struct relay_session *session)
157{
158 struct ctf_trace *ctf_trace;
159 struct lttng_ht_iter iter;
160
161 assert(session);
162
163 DBG("Relay destroying session %" PRIu64, session->id);
164
165 /*
166 * Empty the ctf trace hash table which will destroy the stream contained
167 * in that table.
168 */
169 rcu_read_lock();
170 cds_lfht_for_each_entry(session->ctf_traces_ht->ht, &iter.iter, ctf_trace,
171 node.node) {
172 ctf_trace_delete(session->ctf_traces_ht, ctf_trace);
173 ctf_trace_destroy(ctf_trace);
174 }
175 lttng_ht_destroy(session->ctf_traces_ht);
176 rcu_read_unlock();
177
178 call_rcu(&session->rcu_node, rcu_destroy_session);
179}
This page took 0.031785 seconds and 5 git commands to generate.