Move health into its own common/ static library
[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>
7972aab2 19#include <inttypes.h>
d0b96690
DG
20
21#include <common/common.h>
7972aab2
DG
22#include <common/hashtable/utils.h>
23#include <lttng/lttng.h>
24
d0b96690 25#include "ust-registry.h"
8494bda5 26#include "ust-app.h"
0b2dc8df 27#include "utils.h"
d0b96690
DG
28
29/*
30 * Hash table match function for event in the registry.
31 */
32static int ht_match_event(struct cds_lfht_node *node, const void *_key)
33{
34 struct ust_registry_event *event;
35 const struct ust_registry_event *key;
36
37 assert(node);
38 assert(_key);
39
40 event = caa_container_of(node, struct ust_registry_event, node.node);
41 assert(event);
42 key = _key;
43
44 /* It has to be a perfect match. */
45 if (strncmp(event->name, key->name, sizeof(event->name)) != 0) {
46 goto no_match;
47 }
48
49 /* It has to be a perfect match. */
50 if (strncmp(event->signature, key->signature,
51 strlen(event->signature) != 0)) {
52 goto no_match;
53 }
54
55 /* Match */
56 return 1;
57
58no_match:
59 return 0;
60}
61
7972aab2
DG
62static unsigned long ht_hash_event(void *_key, unsigned long seed)
63{
64 uint64_t xored_key;
65 struct ust_registry_event *key = _key;
66
67 assert(key);
68
69 xored_key = (uint64_t) (hash_key_str(key->name, seed) ^
70 hash_key_str(key->signature, seed));
71
72 return hash_key_u64(&xored_key, seed);
73}
74
8494bda5
MD
75/*
76 * Return negative value on error, 0 if OK.
77 *
78 * TODO: we could add stricter verification of more types to catch
79 * errors in liblttng-ust implementation earlier than consumption by the
80 * trace reader.
81 */
82static
83int validate_event_field(struct ustctl_field *field,
84 const char *event_name,
85 struct ust_app *app)
86{
87 switch(field->type.atype) {
88 case ustctl_atype_integer:
89 case ustctl_atype_enum:
90 case ustctl_atype_array:
91 case ustctl_atype_sequence:
92 case ustctl_atype_string:
93 break;
94
95 case ustctl_atype_float:
96 switch (field->type.u.basic._float.mant_dig) {
97 case 0:
98 WARN("UST application '%s' (pid: %d) has unknown float mantissa '%u' "
99 "in field '%s', rejecting event '%s'",
100 app->name, app->pid,
101 field->type.u.basic._float.mant_dig,
102 field->name,
103 event_name);
104 return -EINVAL;
105 default:
106 break;
107 }
108 break;
109
110 default:
111 return -ENOENT;
112 }
113 return 0;
114}
115
116static
117int validate_event_fields(size_t nr_fields, struct ustctl_field *fields,
118 const char *event_name, struct ust_app *app)
119{
120 unsigned int i;
121
122 for (i = 0; i < nr_fields; i++) {
123 if (validate_event_field(&fields[i], event_name, app) < 0)
124 return -EINVAL;
125 }
126 return 0;
127}
128
d0b96690
DG
129/*
130 * Allocate event and initialize it. This does NOT set a valid event id from a
131 * registry.
132 */
133static struct ust_registry_event *alloc_event(int session_objd,
134 int channel_objd, char *name, char *sig, size_t nr_fields,
8494bda5
MD
135 struct ustctl_field *fields, int loglevel, char *model_emf_uri,
136 struct ust_app *app)
d0b96690
DG
137{
138 struct ust_registry_event *event = NULL;
139
8494bda5
MD
140 /*
141 * Ensure that the field content is valid.
142 */
143 if (validate_event_fields(nr_fields, fields, name, app) < 0) {
144 return NULL;
145 }
146
d0b96690
DG
147 event = zmalloc(sizeof(*event));
148 if (!event) {
149 PERROR("zmalloc ust registry event");
150 goto error;
151 }
152
153 event->session_objd = session_objd;
154 event->channel_objd = channel_objd;
155 /* Allocated by ustctl. */
156 event->signature = sig;
157 event->nr_fields = nr_fields;
158 event->fields = fields;
159 event->loglevel = loglevel;
160 event->model_emf_uri = model_emf_uri;
161 if (name) {
162 /* Copy event name and force NULL byte. */
163 strncpy(event->name, name, sizeof(event->name));
164 event->name[sizeof(event->name) - 1] = '\0';
165 }
7972aab2 166 cds_lfht_node_init(&event->node.node);
d0b96690
DG
167
168error:
169 return event;
170}
171
172/*
173 * Free event data structure. This does NOT delete it from any hash table. It's
174 * safe to pass a NULL pointer. This shoudl be called inside a call RCU if the
175 * event is previously deleted from a rcu hash table.
176 */
177static void destroy_event(struct ust_registry_event *event)
178{
179 if (!event) {
180 return;
181 }
182
183 free(event->fields);
184 free(event->model_emf_uri);
185 free(event->signature);
186 free(event);
187}
188
189/*
190 * Destroy event function call of the call RCU.
191 */
192static void destroy_event_rcu(struct rcu_head *head)
193{
7972aab2
DG
194 struct lttng_ht_node_u64 *node =
195 caa_container_of(head, struct lttng_ht_node_u64, head);
d0b96690
DG
196 struct ust_registry_event *event =
197 caa_container_of(node, struct ust_registry_event, node);
198
199 destroy_event(event);
200}
201
202/*
203 * Find an event using the name and signature in the given registry. RCU read
204 * side lock MUST be acquired before calling this function and as long as the
205 * event reference is kept by the caller.
206 *
207 * On success, the event pointer is returned else NULL.
208 */
209struct ust_registry_event *ust_registry_find_event(
210 struct ust_registry_channel *chan, char *name, char *sig)
211{
7972aab2 212 struct lttng_ht_node_u64 *node;
d0b96690
DG
213 struct lttng_ht_iter iter;
214 struct ust_registry_event *event = NULL;
215 struct ust_registry_event key;
216
217 assert(chan);
218 assert(name);
219 assert(sig);
220
221 /* Setup key for the match function. */
222 strncpy(key.name, name, sizeof(key.name));
223 key.name[sizeof(key.name) - 1] = '\0';
224 key.signature = sig;
225
7972aab2 226 cds_lfht_lookup(chan->ht->ht, chan->ht->hash_fct(&key, lttng_ht_seed),
d0b96690 227 chan->ht->match_fct, &key, &iter.iter);
7972aab2 228 node = lttng_ht_iter_get_node_u64(&iter);
d0b96690
DG
229 if (!node) {
230 goto end;
231 }
232 event = caa_container_of(node, struct ust_registry_event, node);
233
234end:
235 return event;
236}
237
238/*
239 * Create a ust_registry_event from the given parameters and add it to the
240 * registry hash table. If event_id is valid, it is set with the newly created
241 * event id.
242 *
243 * On success, return 0 else a negative value. The created event MUST be unique
244 * so on duplicate entry -EINVAL is returned. On error, event_id is untouched.
245 *
246 * Should be called with session registry mutex held.
247 */
248int ust_registry_create_event(struct ust_registry_session *session,
45893984
DG
249 uint64_t chan_key, int session_objd, int channel_objd, char *name,
250 char *sig, size_t nr_fields, struct ustctl_field *fields, int loglevel,
8494bda5
MD
251 char *model_emf_uri, int buffer_type, uint32_t *event_id_p,
252 struct ust_app *app)
d0b96690
DG
253{
254 int ret;
7972aab2 255 uint32_t event_id;
d0b96690
DG
256 struct cds_lfht_node *nptr;
257 struct ust_registry_event *event = NULL;
45893984 258 struct ust_registry_channel *chan;
d0b96690
DG
259
260 assert(session);
d0b96690
DG
261 assert(name);
262 assert(sig);
7972aab2 263 assert(event_id_p);
d0b96690 264
d5d629b5
DG
265 rcu_read_lock();
266
d0b96690
DG
267 /*
268 * This should not happen but since it comes from the UST tracer, an
269 * external party, don't assert and simply validate values.
270 */
271 if (session_objd < 0 || channel_objd < 0) {
272 ret = -EINVAL;
d5d629b5 273 goto error_free;
d0b96690
DG
274 }
275
45893984
DG
276 chan = ust_registry_channel_find(session, chan_key);
277 if (!chan) {
278 ret = -EINVAL;
d5d629b5 279 goto error_free;
45893984
DG
280 }
281
d0b96690
DG
282 /* Check if we've reached the maximum possible id. */
283 if (ust_registry_is_max_id(chan->used_event_id)) {
284 ret = -ENOENT;
d5d629b5 285 goto error_free;
d0b96690
DG
286 }
287
288 event = alloc_event(session_objd, channel_objd, name, sig, nr_fields,
8494bda5 289 fields, loglevel, model_emf_uri, app);
d0b96690
DG
290 if (!event) {
291 ret = -ENOMEM;
d5d629b5 292 goto error_free;
d0b96690
DG
293 }
294
d0b96690 295 DBG3("UST registry creating event with event: %s, sig: %s, id: %u, "
7972aab2
DG
296 "chan_objd: %u, sess_objd: %u, chan_id: %u", event->name,
297 event->signature, event->id, event->channel_objd,
298 event->session_objd, chan->chan_id);
d0b96690 299
d0b96690
DG
300 /*
301 * This is an add unique with a custom match function for event. The node
302 * are matched using the event name and signature.
303 */
7972aab2 304 nptr = cds_lfht_add_unique(chan->ht->ht, chan->ht->hash_fct(event,
d0b96690
DG
305 lttng_ht_seed), chan->ht->match_fct, event, &event->node.node);
306 if (nptr != &event->node.node) {
7972aab2
DG
307 if (buffer_type == LTTNG_BUFFER_PER_UID) {
308 /*
309 * This is normal, we just have to send the event id of the
310 * returned node and make sure we destroy the previously allocated
311 * event object.
312 */
313 destroy_event(event);
314 event = caa_container_of(nptr, struct ust_registry_event,
315 node.node);
316 assert(event);
317 event_id = event->id;
318 } else {
319 ERR("UST registry create event add unique failed for event: %s, "
320 "sig: %s, id: %u, chan_objd: %u, sess_objd: %u",
321 event->name, event->signature, event->id,
322 event->channel_objd, event->session_objd);
323 ret = -EINVAL;
324 goto error_unlock;
325 }
326 } else {
327 /* Request next event id if the node was successfully added. */
328 event_id = event->id = ust_registry_get_next_event_id(chan);
d0b96690
DG
329 }
330
7972aab2 331 *event_id_p = event_id;
d0b96690 332
7972aab2
DG
333 if (!event->metadata_dumped) {
334 /* Append to metadata */
335 ret = ust_metadata_event_statedump(session, chan, event);
336 if (ret) {
337 ERR("Error appending event metadata (errno = %d)", ret);
338 rcu_read_unlock();
339 return ret;
340 }
d0b96690
DG
341 }
342
45893984 343 rcu_read_unlock();
d0b96690
DG
344 return 0;
345
d5d629b5
DG
346error_free:
347 free(sig);
348 free(fields);
349 free(model_emf_uri);
d0b96690
DG
350error_unlock:
351 rcu_read_unlock();
d0b96690
DG
352 destroy_event(event);
353 return ret;
354}
355
356/*
357 * For a given event in a registry, delete the entry and destroy the event.
358 * This MUST be called within a RCU read side lock section.
359 */
360void ust_registry_destroy_event(struct ust_registry_channel *chan,
361 struct ust_registry_event *event)
362{
363 int ret;
364 struct lttng_ht_iter iter;
365
366 assert(chan);
367 assert(event);
368
369 /* Delete the node first. */
370 iter.iter.node = &event->node.node;
371 ret = lttng_ht_del(chan->ht, &iter);
372 assert(!ret);
373
374 call_rcu(&event->node.head, destroy_event_rcu);
375
376 return;
377}
378
36b588ed
MD
379/*
380 * We need to execute ht_destroy outside of RCU read-side critical
0b2dc8df
MD
381 * section and outside of call_rcu thread, so we postpone its execution
382 * using ht_cleanup_push. It is simpler than to change the semantic of
383 * the many callers of delete_ust_app_session().
36b588ed
MD
384 */
385static
386void destroy_channel_rcu(struct rcu_head *head)
387{
388 struct ust_registry_channel *chan =
389 caa_container_of(head, struct ust_registry_channel, rcu_head);
390
9dbcf332 391 if (chan->ht) {
0b2dc8df 392 ht_cleanup_push(chan->ht);
9dbcf332 393 }
3295105b 394 free(chan->ctx_fields);
36b588ed
MD
395 free(chan);
396}
397
d0b96690
DG
398/*
399 * Destroy every element of the registry and free the memory. This does NOT
400 * free the registry pointer since it might not have been allocated before so
401 * it's the caller responsability.
d0b96690 402 */
45893984 403static void destroy_channel(struct ust_registry_channel *chan)
d0b96690
DG
404{
405 struct lttng_ht_iter iter;
406 struct ust_registry_event *event;
407
408 assert(chan);
409
9209cee7 410 rcu_read_lock();
d0b96690
DG
411 /* Destroy all event associated with this registry. */
412 cds_lfht_for_each_entry(chan->ht->ht, &iter.iter, event, node.node) {
413 /* Delete the node from the ht and free it. */
414 ust_registry_destroy_event(chan, event);
415 }
9209cee7 416 rcu_read_unlock();
36b588ed 417 call_rcu(&chan->rcu_head, destroy_channel_rcu);
d0b96690
DG
418}
419
420/*
421 * Initialize registry with default values.
422 */
45893984
DG
423int ust_registry_channel_add(struct ust_registry_session *session,
424 uint64_t key)
425{
426 int ret = 0;
427 struct ust_registry_channel *chan;
428
429 assert(session);
430
431 chan = zmalloc(sizeof(*chan));
432 if (!chan) {
433 PERROR("zmalloc ust registry channel");
434 ret = -ENOMEM;
9dbcf332 435 goto error_alloc;
45893984
DG
436 }
437
438 chan->ht = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
439 if (!chan->ht) {
440 ret = -ENOMEM;
441 goto error;
442 }
443
444 /* Set custom match function. */
445 chan->ht->match_fct = ht_match_event;
7972aab2
DG
446 chan->ht->hash_fct = ht_hash_event;
447
448 /*
449 * Assign a channel ID right now since the event notification comes
450 * *before* the channel notify so the ID needs to be set at this point so
451 * the metadata can be dumped for that event.
452 */
453 if (ust_registry_is_max_id(session->used_channel_id)) {
454 ret = -1;
455 goto error;
456 }
457 chan->chan_id = ust_registry_get_next_chan_id(session);
45893984
DG
458
459 rcu_read_lock();
460 lttng_ht_node_init_u64(&chan->node, key);
461 lttng_ht_add_unique_u64(session->channels, &chan->node);
462 rcu_read_unlock();
463
9dbcf332
DG
464 return 0;
465
45893984 466error:
9dbcf332
DG
467 destroy_channel(chan);
468error_alloc:
45893984
DG
469 return ret;
470}
471
472/*
473 * Find a channel in the given registry. RCU read side lock MUST be acquired
474 * before calling this function and as long as the event reference is kept by
475 * the caller.
476 *
477 * On success, the pointer is returned else NULL.
478 */
479struct ust_registry_channel *ust_registry_channel_find(
480 struct ust_registry_session *session, uint64_t key)
481{
482 struct lttng_ht_node_u64 *node;
483 struct lttng_ht_iter iter;
484 struct ust_registry_channel *chan = NULL;
485
486 assert(session);
487 assert(session->channels);
488
7972aab2
DG
489 DBG3("UST registry channel finding key %" PRIu64, key);
490
45893984
DG
491 lttng_ht_lookup(session->channels, &key, &iter);
492 node = lttng_ht_iter_get_node_u64(&iter);
493 if (!node) {
494 goto end;
495 }
496 chan = caa_container_of(node, struct ust_registry_channel, node);
497
498end:
499 return chan;
500}
501
502/*
503 * Remove channel using key from registry and free memory.
504 */
505void ust_registry_channel_del_free(struct ust_registry_session *session,
506 uint64_t key)
507{
508 struct lttng_ht_iter iter;
509 struct ust_registry_channel *chan;
9209cee7 510 int ret;
45893984
DG
511
512 assert(session);
513
514 rcu_read_lock();
515 chan = ust_registry_channel_find(session, key);
516 if (!chan) {
9209cee7 517 rcu_read_unlock();
45893984
DG
518 goto end;
519 }
520
521 iter.iter.node = &chan->node.node;
9209cee7
MD
522 ret = lttng_ht_del(session->channels, &iter);
523 assert(!ret);
524 rcu_read_unlock();
45893984
DG
525 destroy_channel(chan);
526
527end:
45893984
DG
528 return;
529}
530
531/*
532 * Initialize registry with default values and set the newly allocated session
533 * pointer to sessionp.
534 *
535 * Return 0 on success and sessionp is set or else return -1 and sessionp is
536 * kept untouched.
537 */
538int ust_registry_session_init(struct ust_registry_session **sessionp,
d0b96690
DG
539 struct ust_app *app,
540 uint32_t bits_per_long,
541 uint32_t uint8_t_alignment,
542 uint32_t uint16_t_alignment,
543 uint32_t uint32_t_alignment,
544 uint32_t uint64_t_alignment,
545 uint32_t long_alignment,
af6142cf
MD
546 int byte_order,
547 uint32_t major,
548 uint32_t minor)
d0b96690
DG
549{
550 int ret;
45893984 551 struct ust_registry_session *session;
d0b96690 552
45893984 553 assert(sessionp);
d0b96690 554
45893984
DG
555 session = zmalloc(sizeof(*session));
556 if (!session) {
557 PERROR("zmalloc ust registry session");
9dbcf332 558 goto error_alloc;
45893984 559 }
d0b96690
DG
560
561 pthread_mutex_init(&session->lock, NULL);
562 session->bits_per_long = bits_per_long;
563 session->uint8_t_alignment = uint8_t_alignment;
564 session->uint16_t_alignment = uint16_t_alignment;
565 session->uint32_t_alignment = uint32_t_alignment;
566 session->uint64_t_alignment = uint64_t_alignment;
567 session->long_alignment = long_alignment;
568 session->byte_order = byte_order;
569
45893984
DG
570 session->channels = lttng_ht_new(0, LTTNG_HT_TYPE_U64);
571 if (!session->channels) {
572 goto error;
573 }
574
d0b96690
DG
575 ret = lttng_uuid_generate(session->uuid);
576 if (ret) {
577 ERR("Failed to generate UST uuid (errno = %d)", ret);
578 goto error;
579 }
580
581 pthread_mutex_lock(&session->lock);
af6142cf 582 ret = ust_metadata_session_statedump(session, app, major, minor);
d0b96690
DG
583 pthread_mutex_unlock(&session->lock);
584 if (ret) {
585 ERR("Failed to generate session metadata (errno = %d)", ret);
586 goto error;
587 }
588
45893984
DG
589 *sessionp = session;
590
d0b96690
DG
591 return 0;
592
593error:
9dbcf332
DG
594 ust_registry_session_destroy(session);
595error_alloc:
d0b96690
DG
596 return -1;
597}
598
599/*
600 * Destroy session registry. This does NOT free the given pointer since it
601 * might get passed as a reference. The registry lock should NOT be acquired.
602 */
603void ust_registry_session_destroy(struct ust_registry_session *reg)
604{
605 int ret;
45893984
DG
606 struct lttng_ht_iter iter;
607 struct ust_registry_channel *chan;
d0b96690
DG
608
609 /* On error, EBUSY can be returned if lock. Code flow error. */
610 ret = pthread_mutex_destroy(&reg->lock);
611 assert(!ret);
612
45893984
DG
613 rcu_read_lock();
614 /* Destroy all event associated with this registry. */
615 cds_lfht_for_each_entry(reg->channels->ht, &iter.iter, chan, node.node) {
616 /* Delete the node from the ht and free it. */
617 ret = lttng_ht_del(reg->channels, &iter);
618 assert(!ret);
619 destroy_channel(chan);
620 }
45893984
DG
621 rcu_read_unlock();
622
52d8ccce 623 ht_cleanup_push(reg->channels);
d0b96690
DG
624 free(reg->metadata);
625}
This page took 0.054832 seconds and 5 git commands to generate.