Add wildcard support
[lttng-ust.git] / liblttng-ust / ltt-probes.c
1 /*
2 * ltt-probes.c
3 *
4 * Copyright 2010 (c) - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
5 *
6 * Holds LTTng probes registry.
7 *
8 * Dual LGPL v2.1/GPL v2 license.
9 */
10
11 #include <string.h>
12 #include <errno.h>
13 #include <urcu/list.h>
14 #include <urcu/hlist.h>
15 #include <lttng/ust-events.h>
16 #include <assert.h>
17 #include <helper.h>
18 #include <ctype.h>
19
20 #include "ltt-tracer-core.h"
21 #include "jhash.h"
22 #include "error.h"
23
24 /*
25 * probe list is protected by ust_lock()/ust_unlock().
26 */
27 static CDS_LIST_HEAD(probe_list);
28
29 /*
30 * Loglevel hash table, containing the active loglevels.
31 * Protected by ust lock.
32 */
33 #define LOGLEVEL_HASH_BITS 6
34 #define LOGLEVEL_TABLE_SIZE (1 << LOGLEVEL_HASH_BITS)
35 static struct cds_hlist_head loglevel_table[LOGLEVEL_TABLE_SIZE];
36
37 /*
38 * Wildcard list, containing the active wildcards.
39 * Protected by ust lock.
40 */
41 static CDS_LIST_HEAD(wildcard_list);
42
43 static
44 const struct lttng_probe_desc *find_provider(const char *provider)
45 {
46 struct lttng_probe_desc *iter;
47
48 cds_list_for_each_entry(iter, &probe_list, head) {
49 if (!strcmp(iter->provider, provider))
50 return iter;
51 }
52 return NULL;
53 }
54
55 static
56 const struct lttng_event_desc *find_event(const char *name)
57 {
58 struct lttng_probe_desc *probe_desc;
59 int i;
60
61 cds_list_for_each_entry(probe_desc, &probe_list, head) {
62 for (i = 0; i < probe_desc->nr_events; i++) {
63 if (!strcmp(probe_desc->event_desc[i]->name, name))
64 return probe_desc->event_desc[i];
65 }
66 }
67 return NULL;
68 }
69
70 int ltt_probe_register(struct lttng_probe_desc *desc)
71 {
72 struct lttng_probe_desc *iter;
73 int ret = 0;
74 int i;
75
76 ust_lock();
77 if (find_provider(desc->provider)) {
78 ret = -EEXIST;
79 goto end;
80 }
81 /*
82 * TODO: This is O(N^2). Turn into a hash table when probe registration
83 * overhead becomes an issue.
84 */
85 for (i = 0; i < desc->nr_events; i++) {
86 if (find_event(desc->event_desc[i]->name)) {
87 ret = -EEXIST;
88 goto end;
89 }
90 }
91
92 /*
93 * We sort the providers by struct lttng_probe_desc pointer
94 * address.
95 */
96 cds_list_for_each_entry_reverse(iter, &probe_list, head) {
97 BUG_ON(iter == desc); /* Should never be in the list twice */
98 if (iter < desc) {
99 /* We belong to the location right after iter. */
100 cds_list_add(&desc->head, &iter->head);
101 goto desc_added;
102 }
103 }
104 /* We should be added at the head of the list */
105 cds_list_add(&desc->head, &probe_list);
106 desc_added:
107
108 /*
109 * fix the events awaiting probe load.
110 */
111 for (i = 0; i < desc->nr_events; i++) {
112 ret = pending_probe_fix_events(desc->event_desc[i]);
113 assert(!ret);
114 }
115 end:
116 ust_unlock();
117 return ret;
118 }
119
120 void ltt_probe_unregister(struct lttng_probe_desc *desc)
121 {
122 ust_lock();
123 cds_list_del(&desc->head);
124 ust_unlock();
125 }
126
127 /*
128 * called with UST lock held.
129 */
130 const struct lttng_event_desc *ltt_event_get(const char *name)
131 {
132 const struct lttng_event_desc *event;
133
134 event = find_event(name);
135 if (!event)
136 return NULL;
137 return event;
138 }
139
140 void ltt_event_put(const struct lttng_event_desc *event)
141 {
142 }
143
144 void ltt_probes_prune_event_list(struct lttng_ust_tracepoint_list *list)
145 {
146 struct tp_list_entry *list_entry, *tmp;
147
148 cds_list_for_each_entry_safe(list_entry, tmp, &list->head, head) {
149 cds_list_del(&list_entry->head);
150 free(list_entry);
151 }
152 }
153
154 /*
155 * called with UST lock held.
156 */
157 int ltt_probes_get_event_list(struct lttng_ust_tracepoint_list *list)
158 {
159 struct lttng_probe_desc *probe_desc;
160 int i;
161
162 CDS_INIT_LIST_HEAD(&list->head);
163 cds_list_for_each_entry(probe_desc, &probe_list, head) {
164 for (i = 0; i < probe_desc->nr_events; i++) {
165 struct tp_list_entry *list_entry;
166
167 list_entry = zmalloc(sizeof(*list_entry));
168 if (!list_entry)
169 goto err_nomem;
170 cds_list_add(&list_entry->head, &list->head);
171 strncpy(list_entry->tp.name,
172 probe_desc->event_desc[i]->name,
173 LTTNG_UST_SYM_NAME_LEN);
174 list_entry->tp.name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
175 if (!probe_desc->event_desc[i]->loglevel) {
176 list_entry->tp.loglevel[0] = '\0';
177 list_entry->tp.loglevel_value = 0;
178 } else {
179 strncpy(list_entry->tp.loglevel,
180 (*probe_desc->event_desc[i]->loglevel)->identifier,
181 LTTNG_UST_SYM_NAME_LEN);
182 list_entry->tp.loglevel[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
183 list_entry->tp.loglevel_value =
184 (*probe_desc->event_desc[i]->loglevel)->value;
185 }
186 }
187 }
188 if (cds_list_empty(&list->head))
189 list->iter = NULL;
190 else
191 list->iter =
192 cds_list_first_entry(&list->head, struct tp_list_entry, head);
193 return 0;
194
195 err_nomem:
196 ltt_probes_prune_event_list(list);
197 return -ENOMEM;
198 }
199
200 /*
201 * Return current iteration position, advance internal iterator to next.
202 * Return NULL if end of list.
203 */
204 struct lttng_ust_tracepoint_iter *
205 lttng_ust_tracepoint_list_get_iter_next(struct lttng_ust_tracepoint_list *list)
206 {
207 struct tp_list_entry *entry;
208
209 if (!list->iter)
210 return NULL;
211 entry = list->iter;
212 if (entry->head.next == &list->head)
213 list->iter = NULL;
214 else
215 list->iter = cds_list_entry(entry->head.next,
216 struct tp_list_entry, head);
217 return &entry->tp;
218 }
219
220 /*
221 * Get loglevel if the loglevel is present in the loglevel hash table.
222 * Must be called with ust lock held.
223 * Returns NULL if not present.
224 */
225 struct loglevel_entry *get_loglevel(const char *name)
226 {
227 struct cds_hlist_head *head;
228 struct cds_hlist_node *node;
229 struct loglevel_entry *e;
230 uint32_t hash = jhash(name, strlen(name), 0);
231
232 head = &loglevel_table[hash & (LOGLEVEL_TABLE_SIZE - 1)];
233 cds_hlist_for_each_entry(e, node, head, hlist) {
234 if (!strcmp(name, e->name))
235 return e;
236 }
237 return NULL;
238 }
239
240 struct loglevel_entry *get_loglevel_value(int64_t value)
241 {
242 char name[LTTNG_UST_SYM_NAME_LEN];
243 int ret;
244
245 ret = snprintf(name, LTTNG_UST_SYM_NAME_LEN, "%lld", (long long) value);
246 if (ret < 0)
247 return NULL;
248 return get_loglevel(name);
249 }
250
251 /*
252 * marshall all probes/all events and create those that fit the
253 * loglevel. Add them to the events list as created.
254 */
255 static
256 void _probes_create_loglevel_events(struct loglevel_entry *entry,
257 struct session_loglevel *loglevel)
258 {
259 struct lttng_probe_desc *probe_desc;
260 struct lttng_ust_event event_param;
261 int i;
262
263 cds_list_for_each_entry(probe_desc, &probe_list, head) {
264 for (i = 0; i < probe_desc->nr_events; i++) {
265 const struct tracepoint_loglevel_entry *ev_ll;
266 const struct lttng_event_desc *event_desc;
267 int match = 0;
268
269 event_desc = probe_desc->event_desc[i];
270 if (!(event_desc->loglevel))
271 continue;
272 ev_ll = *event_desc->loglevel;
273 if (isdigit(entry->name[0])) {
274 if (atoll(entry->name) == ev_ll->value) {
275 match = 1;
276 }
277 } else if (!strcmp(ev_ll->identifier, entry->name)) {
278 match = 1;
279 }
280
281 if (match) {
282 struct ltt_event *ev;
283 int ret;
284
285 memcpy(&event_param, &loglevel->event_param,
286 sizeof(event_param));
287 memcpy(event_param.name,
288 event_desc->name,
289 sizeof(event_param.name));
290 /* create event */
291 ret = ltt_event_create(loglevel->chan,
292 &event_param, NULL,
293 &ev);
294 if (ret) {
295 DBG("Error creating event");
296 continue;
297 }
298 cds_list_add(&ev->loglevel_list,
299 &loglevel->events);
300 }
301 }
302 }
303 }
304
305 /*
306 * Add the loglevel to the loglevel hash table. Must be called with
307 * ust lock held.
308 */
309 struct session_loglevel *add_loglevel(const char *name,
310 struct ltt_channel *chan,
311 struct lttng_ust_event *event_param)
312 {
313 struct cds_hlist_head *head;
314 struct cds_hlist_node *node;
315 struct loglevel_entry *e;
316 struct session_loglevel *sl;
317 size_t name_len = strlen(name) + 1;
318 uint32_t hash = jhash(name, name_len-1, 0);
319 int found = 0;
320
321 /* loglevel entry */
322 head = &loglevel_table[hash & (LOGLEVEL_TABLE_SIZE - 1)];
323 cds_hlist_for_each_entry(e, node, head, hlist) {
324 if (!strcmp(name, e->name)) {
325 found = 1;
326 break;
327 }
328 }
329
330 if (!found) {
331 /*
332 * Using zmalloc here to allocate a variable length element. Could
333 * cause some memory fragmentation if overused.
334 */
335 e = zmalloc(sizeof(struct loglevel_entry) + name_len);
336 if (!e)
337 return ERR_PTR(-ENOMEM);
338 memcpy(&e->name[0], name, name_len);
339 cds_hlist_add_head(&e->hlist, head);
340 CDS_INIT_LIST_HEAD(&e->session_list);
341 }
342
343 /* session loglevel */
344 cds_list_for_each_entry(sl, &e->session_list, session_list) {
345 if (chan == sl->chan) {
346 DBG("loglevel %s busy for this channel", name);
347 return ERR_PTR(-EEXIST); /* Already there */
348 }
349 }
350 sl = zmalloc(sizeof(struct session_loglevel));
351 if (!sl)
352 return ERR_PTR(-ENOMEM);
353 sl->chan = chan;
354 sl->enabled = 1;
355 memcpy(&sl->event_param, event_param, sizeof(sl->event_param));
356 sl->event_param.instrumentation = LTTNG_UST_TRACEPOINT;
357 CDS_INIT_LIST_HEAD(&sl->events);
358 cds_list_add(&sl->list, &chan->session->loglevels);
359 cds_list_add(&sl->session_list, &e->session_list);
360 sl->entry = e;
361 _probes_create_loglevel_events(e, sl);
362 return sl;
363 }
364
365 /*
366 * Remove the loglevel from the loglevel hash table. Must be called with
367 * ust_lock held. Only called at session teardown.
368 */
369 void _remove_loglevel(struct session_loglevel *loglevel)
370 {
371 struct ltt_event *ev, *tmp;
372
373 /*
374 * Just remove the events owned (for enable/disable) by this
375 * loglevel from the list. The session teardown will take care
376 * of freeing the event memory.
377 */
378 cds_list_for_each_entry_safe(ev, tmp, &loglevel->events, list) {
379 cds_list_del(&ev->list);
380 }
381 cds_list_del(&loglevel->session_list);
382 cds_list_del(&loglevel->list);
383 if (cds_list_empty(&loglevel->entry->session_list)) {
384 cds_hlist_del(&loglevel->entry->hlist);
385 free(loglevel->entry);
386 }
387 free(loglevel);
388 }
389
390 int ltt_loglevel_enable(struct session_loglevel *loglevel)
391 {
392 struct ltt_event *ev;
393 int ret;
394
395 if (loglevel->enabled)
396 return -EEXIST;
397 cds_list_for_each_entry(ev, &loglevel->events, list) {
398 ret = ltt_event_enable(ev);
399 if (ret) {
400 DBG("Error: enable error.\n");
401 return ret;
402 }
403 }
404 loglevel->enabled = 1;
405 return 0;
406 }
407
408 int ltt_loglevel_disable(struct session_loglevel *loglevel)
409 {
410 struct ltt_event *ev;
411 int ret;
412
413 if (!loglevel->enabled)
414 return -EEXIST;
415 cds_list_for_each_entry(ev, &loglevel->events, list) {
416 ret = ltt_event_disable(ev);
417 if (ret) {
418 DBG("Error: disable error.\n");
419 return ret;
420 }
421 }
422 loglevel->enabled = 0;
423 return 0;
424 }
425
426 /* WILDCARDS */
427
428 /*
429 * Return wildcard for a given event name if the event name match the
430 * one of the wildcards.
431 * Must be called with ust lock held.
432 * Returns NULL if not present.
433 */
434 struct wildcard_entry *match_wildcard(const char *name)
435 {
436 struct wildcard_entry *e;
437
438 cds_list_for_each_entry(e, &wildcard_list, list) {
439 /* If only contain '*' */
440 if (strlen(e->name) == 1)
441 return e;
442 /* Compare excluding final '*' */
443 if (!strncmp(name, e->name, strlen(e->name) - 1))
444 return e;
445 }
446 return NULL;
447 }
448
449 /*
450 * marshall all probes/all events and create those that fit the
451 * wildcard. Add them to the events list as created.
452 */
453 static
454 void _probes_create_wildcard_events(struct wildcard_entry *entry,
455 struct session_wildcard *wildcard)
456 {
457 struct lttng_probe_desc *probe_desc;
458 struct lttng_ust_event event_param;
459 int i;
460
461 cds_list_for_each_entry(probe_desc, &probe_list, head) {
462 for (i = 0; i < probe_desc->nr_events; i++) {
463 const struct lttng_event_desc *event_desc;
464 int match = 0;
465
466 event_desc = probe_desc->event_desc[i];
467 /* compare excluding final '*' */
468 assert(strlen(entry->name) > 0);
469 if (strcmp(event_desc->name, "lttng_ust:metadata")
470 && (strlen(entry->name) == 1
471 || !strncmp(event_desc->name, entry->name,
472 strlen(entry->name) - 1))) {
473 match = 1;
474 }
475 if (match) {
476 struct ltt_event *ev;
477 int ret;
478
479 memcpy(&event_param, &wildcard->event_param,
480 sizeof(event_param));
481 memcpy(event_param.name,
482 event_desc->name,
483 sizeof(event_param.name));
484 /* create event */
485 ret = ltt_event_create(wildcard->chan,
486 &event_param, NULL,
487 &ev);
488 if (ret) {
489 DBG("Error creating event");
490 continue;
491 }
492 cds_list_add(&ev->wildcard_list,
493 &wildcard->events);
494 }
495 }
496 }
497 }
498
499 /*
500 * Add the wildcard to the wildcard hash table. Must be called with
501 * ust lock held.
502 */
503 struct session_wildcard *add_wildcard(const char *name,
504 struct ltt_channel *chan,
505 struct lttng_ust_event *event_param)
506 {
507 struct wildcard_entry *e;
508 struct session_wildcard *sw;
509 size_t name_len = strlen(name) + 1;
510 int found = 0;
511
512 /* wildcard entry */
513 cds_list_for_each_entry(e, &wildcard_list, list) {
514 if (!strcmp(name, e->name)) {
515 found = 1;
516 break;
517 }
518 }
519
520 if (!found) {
521 /*
522 * Using zmalloc here to allocate a variable length element. Could
523 * cause some memory fragmentation if overused.
524 */
525 e = zmalloc(sizeof(struct wildcard_entry) + name_len);
526 if (!e)
527 return ERR_PTR(-ENOMEM);
528 memcpy(&e->name[0], name, name_len);
529 cds_list_add(&e->list, &wildcard_list);
530 CDS_INIT_LIST_HEAD(&e->session_list);
531 }
532
533 /* session wildcard */
534 cds_list_for_each_entry(sw, &e->session_list, session_list) {
535 if (chan == sw->chan) {
536 DBG("wildcard %s busy for this channel", name);
537 return ERR_PTR(-EEXIST); /* Already there */
538 }
539 }
540 sw = zmalloc(sizeof(struct session_wildcard));
541 if (!sw)
542 return ERR_PTR(-ENOMEM);
543 sw->chan = chan;
544 sw->enabled = 1;
545 memcpy(&sw->event_param, event_param, sizeof(sw->event_param));
546 sw->event_param.instrumentation = LTTNG_UST_TRACEPOINT;
547 CDS_INIT_LIST_HEAD(&sw->events);
548 cds_list_add(&sw->list, &chan->session->wildcards);
549 cds_list_add(&sw->session_list, &e->session_list);
550 sw->entry = e;
551 _probes_create_wildcard_events(e, sw);
552 return sw;
553 }
554
555 /*
556 * Remove the wildcard from the wildcard hash table. Must be called with
557 * ust_lock held. Only called at session teardown.
558 */
559 void _remove_wildcard(struct session_wildcard *wildcard)
560 {
561 struct ltt_event *ev, *tmp;
562
563 /*
564 * Just remove the events owned (for enable/disable) by this
565 * wildcard from the list. The session teardown will take care
566 * of freeing the event memory.
567 */
568 cds_list_for_each_entry_safe(ev, tmp, &wildcard->events, list) {
569 cds_list_del(&ev->list);
570 }
571 cds_list_del(&wildcard->session_list);
572 cds_list_del(&wildcard->list);
573 if (cds_list_empty(&wildcard->entry->session_list)) {
574 cds_list_del(&wildcard->entry->list);
575 free(wildcard->entry);
576 }
577 free(wildcard);
578 }
579
580 int ltt_wildcard_enable(struct session_wildcard *wildcard)
581 {
582 struct ltt_event *ev;
583 int ret;
584
585 if (wildcard->enabled)
586 return -EEXIST;
587 cds_list_for_each_entry(ev, &wildcard->events, list) {
588 ret = ltt_event_enable(ev);
589 if (ret) {
590 DBG("Error: enable error.\n");
591 return ret;
592 }
593 }
594 wildcard->enabled = 1;
595 return 0;
596 }
597
598 int ltt_wildcard_disable(struct session_wildcard *wildcard)
599 {
600 struct ltt_event *ev;
601 int ret;
602
603 if (!wildcard->enabled)
604 return -EEXIST;
605 cds_list_for_each_entry(ev, &wildcard->events, list) {
606 ret = ltt_event_disable(ev);
607 if (ret) {
608 DBG("Error: disable error.\n");
609 return ret;
610 }
611 }
612 wildcard->enabled = 0;
613 return 0;
614 }
This page took 0.0416 seconds and 4 git commands to generate.