Move ust channel registry inside session registry
[lttng-tools.git] / src / bin / lttng-sessiond / ust-registry.c
CommitLineData
d0b96690
DG
1/*
2 * Copyright (C) 2013 - David Goulet <dgoulet@efficios.com>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License, version 2 only, as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 51
15 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17#define _GNU_SOURCE
18#include <assert.h>
19
20#include <common/common.h>
21#include "ust-registry.h"
22
23/*
24 * Hash table match function for event in the registry.
25 */
26static int ht_match_event(struct cds_lfht_node *node, const void *_key)
27{
28 struct ust_registry_event *event;
29 const struct ust_registry_event *key;
30
31 assert(node);
32 assert(_key);
33
34 event = caa_container_of(node, struct ust_registry_event, node.node);
35 assert(event);
36 key = _key;
37
38 /* It has to be a perfect match. */
39 if (strncmp(event->name, key->name, sizeof(event->name)) != 0) {
40 goto no_match;
41 }
42
43 /* It has to be a perfect match. */
44 if (strncmp(event->signature, key->signature,
45 strlen(event->signature) != 0)) {
46 goto no_match;
47 }
48
49 /* Match */
50 return 1;
51
52no_match:
53 return 0;
54}
55
56/*
57 * Allocate event and initialize it. This does NOT set a valid event id from a
58 * registry.
59 */
60static struct ust_registry_event *alloc_event(int session_objd,
61 int channel_objd, char *name, char *sig, size_t nr_fields,
62 struct ustctl_field *fields, int loglevel, char *model_emf_uri)
63{
64 struct ust_registry_event *event = NULL;
65
66 event = zmalloc(sizeof(*event));
67 if (!event) {
68 PERROR("zmalloc ust registry event");
69 goto error;
70 }
71
72 event->session_objd = session_objd;
73 event->channel_objd = channel_objd;
74 /* Allocated by ustctl. */
75 event->signature = sig;
76 event->nr_fields = nr_fields;
77 event->fields = fields;
78 event->loglevel = loglevel;
79 event->model_emf_uri = model_emf_uri;
80 if (name) {
81 /* Copy event name and force NULL byte. */
82 strncpy(event->name, name, sizeof(event->name));
83 event->name[sizeof(event->name) - 1] = '\0';
84 }
85 lttng_ht_node_init_str(&event->node, event->name);
86
87error:
88 return event;
89}
90
91/*
92 * Free event data structure. This does NOT delete it from any hash table. It's
93 * safe to pass a NULL pointer. This shoudl be called inside a call RCU if the
94 * event is previously deleted from a rcu hash table.
95 */
96static void destroy_event(struct ust_registry_event *event)
97{
98 if (!event) {
99 return;
100 }
101
102 free(event->fields);
103 free(event->model_emf_uri);
104 free(event->signature);
105 free(event);
106}
107
108/*
109 * Destroy event function call of the call RCU.
110 */
111static void destroy_event_rcu(struct rcu_head *head)
112{
113 struct lttng_ht_node_str *node =
114 caa_container_of(head, struct lttng_ht_node_str, head);
115 struct ust_registry_event *event =
116 caa_container_of(node, struct ust_registry_event, node);
117
118 destroy_event(event);
119}
120
121/*
122 * Find an event using the name and signature in the given registry. RCU read
123 * side lock MUST be acquired before calling this function and as long as the
124 * event reference is kept by the caller.
125 *
126 * On success, the event pointer is returned else NULL.
127 */
128struct ust_registry_event *ust_registry_find_event(
129 struct ust_registry_channel *chan, char *name, char *sig)
130{
131 struct lttng_ht_node_str *node;
132 struct lttng_ht_iter iter;
133 struct ust_registry_event *event = NULL;
134 struct ust_registry_event key;
135
136 assert(chan);
137 assert(name);
138 assert(sig);
139
140 /* Setup key for the match function. */
141 strncpy(key.name, name, sizeof(key.name));
142 key.name[sizeof(key.name) - 1] = '\0';
143 key.signature = sig;
144
145 cds_lfht_lookup(chan->ht->ht, chan->ht->hash_fct(name, lttng_ht_seed),
146 chan->ht->match_fct, &key, &iter.iter);
147 node = lttng_ht_iter_get_node_str(&iter);
148 if (!node) {
149 goto end;
150 }
151 event = caa_container_of(node, struct ust_registry_event, node);
152
153end:
154 return event;
155}
156
157/*
158 * Create a ust_registry_event from the given parameters and add it to the
159 * registry hash table. If event_id is valid, it is set with the newly created
160 * event id.
161 *
162 * On success, return 0 else a negative value. The created event MUST be unique
163 * so on duplicate entry -EINVAL is returned. On error, event_id is untouched.
164 *
165 * Should be called with session registry mutex held.
166 */
167int ust_registry_create_event(struct ust_registry_session *session,
45893984
DG
168 uint64_t chan_key, int session_objd, int channel_objd, char *name,
169 char *sig, size_t nr_fields, struct ustctl_field *fields, int loglevel,
d0b96690
DG
170 char *model_emf_uri, uint32_t *event_id)
171{
172 int ret;
173 struct cds_lfht_node *nptr;
174 struct ust_registry_event *event = NULL;
45893984 175 struct ust_registry_channel *chan;
d0b96690
DG
176
177 assert(session);
d0b96690
DG
178 assert(name);
179 assert(sig);
180
181 /*
182 * This should not happen but since it comes from the UST tracer, an
183 * external party, don't assert and simply validate values.
184 */
185 if (session_objd < 0 || channel_objd < 0) {
186 ret = -EINVAL;
187 goto error;
188 }
189
45893984
DG
190 rcu_read_lock();
191
192 chan = ust_registry_channel_find(session, chan_key);
193 if (!chan) {
194 ret = -EINVAL;
195 goto error_unlock;
196 }
197
d0b96690
DG
198 /* Check if we've reached the maximum possible id. */
199 if (ust_registry_is_max_id(chan->used_event_id)) {
200 ret = -ENOENT;
45893984 201 goto error_unlock;
d0b96690
DG
202 }
203
204 event = alloc_event(session_objd, channel_objd, name, sig, nr_fields,
205 fields, loglevel, model_emf_uri);
206 if (!event) {
207 ret = -ENOMEM;
45893984 208 goto error_unlock;
d0b96690
DG
209 }
210
211 event->id = ust_registry_get_next_event_id(chan);
212
213 DBG3("UST registry creating event with event: %s, sig: %s, id: %u, "
214 "chan_objd: %u, sess_objd: %u", event->name, event->signature,
215 event->id, event->channel_objd, event->session_objd);
216
d0b96690
DG
217 /*
218 * This is an add unique with a custom match function for event. The node
219 * are matched using the event name and signature.
220 */
221 nptr = cds_lfht_add_unique(chan->ht->ht, chan->ht->hash_fct(event->node.key,
222 lttng_ht_seed), chan->ht->match_fct, event, &event->node.node);
223 if (nptr != &event->node.node) {
224 ERR("UST registry create event add unique failed for event: %s, "
225 "sig: %s, id: %u, chan_objd: %u, sess_objd: %u", event->name,
226 event->signature, event->id, event->channel_objd,
227 event->session_objd);
228 ret = -EINVAL;
229 goto error_unlock;
230 }
231
232 /* Set event id if user wants it. */
233 if (event_id) {
234 *event_id = event->id;
235 }
d0b96690
DG
236
237 /* Append to metadata */
238 ret = ust_metadata_event_statedump(session, chan, event);
239 if (ret) {
240 ERR("Error appending event metadata (errno = %d)", ret);
45893984 241 rcu_read_unlock();
d0b96690
DG
242 return ret;
243 }
244
45893984 245 rcu_read_unlock();
d0b96690
DG
246 return 0;
247
248error_unlock:
249 rcu_read_unlock();
250error:
251 destroy_event(event);
252 return ret;
253}
254
255/*
256 * For a given event in a registry, delete the entry and destroy the event.
257 * This MUST be called within a RCU read side lock section.
258 */
259void ust_registry_destroy_event(struct ust_registry_channel *chan,
260 struct ust_registry_event *event)
261{
262 int ret;
263 struct lttng_ht_iter iter;
264
265 assert(chan);
266 assert(event);
267
268 /* Delete the node first. */
269 iter.iter.node = &event->node.node;
270 ret = lttng_ht_del(chan->ht, &iter);
271 assert(!ret);
272
273 call_rcu(&event->node.head, destroy_event_rcu);
274
275 return;
276}
277
d0b96690
DG
278/*
279 * Destroy every element of the registry and free the memory. This does NOT
280 * free the registry pointer since it might not have been allocated before so
281 * it's the caller responsability.
282 *
283 * This MUST be called within a RCU read side lock section.
284 */
45893984 285static void destroy_channel(struct ust_registry_channel *chan)
d0b96690
DG
286{
287 struct lttng_ht_iter iter;
288 struct ust_registry_event *event;
289
290 assert(chan);
291
292 /* Destroy all event associated with this registry. */
293 cds_lfht_for_each_entry(chan->ht->ht, &iter.iter, event, node.node) {
294 /* Delete the node from the ht and free it. */
295 ust_registry_destroy_event(chan, event);
296 }
297 lttng_ht_destroy(chan->ht);
45893984
DG
298
299 free(chan);
d0b96690
DG
300}
301
302/*
303 * Initialize registry with default values.
304 */
45893984
DG
305int ust_registry_channel_add(struct ust_registry_session *session,
306 uint64_t key)
307{
308 int ret = 0;
309 struct ust_registry_channel *chan;
310
311 assert(session);
312
313 chan = zmalloc(sizeof(*chan));
314 if (!chan) {
315 PERROR("zmalloc ust registry channel");
316 ret = -ENOMEM;
317 goto error;
318 }
319
320 chan->ht = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
321 if (!chan->ht) {
322 ret = -ENOMEM;
323 goto error;
324 }
325
326 /* Set custom match function. */
327 chan->ht->match_fct = ht_match_event;
328
329 rcu_read_lock();
330 lttng_ht_node_init_u64(&chan->node, key);
331 lttng_ht_add_unique_u64(session->channels, &chan->node);
332 rcu_read_unlock();
333
334error:
335 return ret;
336}
337
338/*
339 * Find a channel in the given registry. RCU read side lock MUST be acquired
340 * before calling this function and as long as the event reference is kept by
341 * the caller.
342 *
343 * On success, the pointer is returned else NULL.
344 */
345struct ust_registry_channel *ust_registry_channel_find(
346 struct ust_registry_session *session, uint64_t key)
347{
348 struct lttng_ht_node_u64 *node;
349 struct lttng_ht_iter iter;
350 struct ust_registry_channel *chan = NULL;
351
352 assert(session);
353 assert(session->channels);
354
355 lttng_ht_lookup(session->channels, &key, &iter);
356 node = lttng_ht_iter_get_node_u64(&iter);
357 if (!node) {
358 goto end;
359 }
360 chan = caa_container_of(node, struct ust_registry_channel, node);
361
362end:
363 return chan;
364}
365
366/*
367 * Remove channel using key from registry and free memory.
368 */
369void ust_registry_channel_del_free(struct ust_registry_session *session,
370 uint64_t key)
371{
372 struct lttng_ht_iter iter;
373 struct ust_registry_channel *chan;
374
375 assert(session);
376
377 rcu_read_lock();
378 chan = ust_registry_channel_find(session, key);
379 if (!chan) {
380 goto end;
381 }
382
383 iter.iter.node = &chan->node.node;
384 lttng_ht_del(session->channels, &iter);
385
386 destroy_channel(chan);
387
388end:
389 rcu_read_unlock();
390 return;
391}
392
393/*
394 * Initialize registry with default values and set the newly allocated session
395 * pointer to sessionp.
396 *
397 * Return 0 on success and sessionp is set or else return -1 and sessionp is
398 * kept untouched.
399 */
400int ust_registry_session_init(struct ust_registry_session **sessionp,
d0b96690
DG
401 struct ust_app *app,
402 uint32_t bits_per_long,
403 uint32_t uint8_t_alignment,
404 uint32_t uint16_t_alignment,
405 uint32_t uint32_t_alignment,
406 uint32_t uint64_t_alignment,
407 uint32_t long_alignment,
408 int byte_order)
409{
410 int ret;
45893984 411 struct ust_registry_session *session;
d0b96690 412
45893984
DG
413 assert(sessionp);
414 assert(app);
d0b96690 415
45893984
DG
416 session = zmalloc(sizeof(*session));
417 if (!session) {
418 PERROR("zmalloc ust registry session");
419 goto error;
420 }
d0b96690
DG
421
422 pthread_mutex_init(&session->lock, NULL);
423 session->bits_per_long = bits_per_long;
424 session->uint8_t_alignment = uint8_t_alignment;
425 session->uint16_t_alignment = uint16_t_alignment;
426 session->uint32_t_alignment = uint32_t_alignment;
427 session->uint64_t_alignment = uint64_t_alignment;
428 session->long_alignment = long_alignment;
429 session->byte_order = byte_order;
430
45893984
DG
431 session->channels = lttng_ht_new(0, LTTNG_HT_TYPE_U64);
432 if (!session->channels) {
433 goto error;
434 }
435
d0b96690
DG
436 ret = lttng_uuid_generate(session->uuid);
437 if (ret) {
438 ERR("Failed to generate UST uuid (errno = %d)", ret);
439 goto error;
440 }
441
442 pthread_mutex_lock(&session->lock);
443 ret = ust_metadata_session_statedump(session, app);
444 pthread_mutex_unlock(&session->lock);
445 if (ret) {
446 ERR("Failed to generate session metadata (errno = %d)", ret);
447 goto error;
448 }
449
45893984
DG
450 *sessionp = session;
451
d0b96690
DG
452 return 0;
453
454error:
455 return -1;
456}
457
458/*
459 * Destroy session registry. This does NOT free the given pointer since it
460 * might get passed as a reference. The registry lock should NOT be acquired.
461 */
462void ust_registry_session_destroy(struct ust_registry_session *reg)
463{
464 int ret;
45893984
DG
465 struct lttng_ht_iter iter;
466 struct ust_registry_channel *chan;
d0b96690
DG
467
468 /* On error, EBUSY can be returned if lock. Code flow error. */
469 ret = pthread_mutex_destroy(&reg->lock);
470 assert(!ret);
471
45893984
DG
472 rcu_read_lock();
473 /* Destroy all event associated with this registry. */
474 cds_lfht_for_each_entry(reg->channels->ht, &iter.iter, chan, node.node) {
475 /* Delete the node from the ht and free it. */
476 ret = lttng_ht_del(reg->channels, &iter);
477 assert(!ret);
478 destroy_channel(chan);
479 }
480 lttng_ht_destroy(reg->channels);
481 rcu_read_unlock();
482
d0b96690
DG
483 free(reg->metadata);
484}
This page took 0.064345 seconds and 4 git commands to generate.