216ed17cc2cc5d03bb24583ab4371004c02d7090
[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,
379 loglevel_list) {
380 cds_list_del(&ev->loglevel_list);
381 }
382 cds_list_del(&loglevel->session_list);
383 cds_list_del(&loglevel->list);
384 if (cds_list_empty(&loglevel->entry->session_list)) {
385 cds_hlist_del(&loglevel->entry->hlist);
386 free(loglevel->entry);
387 }
388 free(loglevel);
389 }
390
391 int ltt_loglevel_enable(struct session_loglevel *loglevel)
392 {
393 struct ltt_event *ev;
394 int ret;
395
396 if (loglevel->enabled)
397 return -EEXIST;
398 cds_list_for_each_entry(ev, &loglevel->events, loglevel_list) {
399 ret = ltt_event_enable(ev);
400 if (ret) {
401 DBG("Error: enable error.\n");
402 return ret;
403 }
404 }
405 loglevel->enabled = 1;
406 return 0;
407 }
408
409 int ltt_loglevel_disable(struct session_loglevel *loglevel)
410 {
411 struct ltt_event *ev;
412 int ret;
413
414 if (!loglevel->enabled)
415 return -EEXIST;
416 cds_list_for_each_entry(ev, &loglevel->events, loglevel_list) {
417 ret = ltt_event_disable(ev);
418 if (ret) {
419 DBG("Error: disable error.\n");
420 return ret;
421 }
422 }
423 loglevel->enabled = 0;
424 return 0;
425 }
426
427 /* WILDCARDS */
428
429 /*
430 * Return wildcard for a given event name if the event name match the
431 * one of the wildcards.
432 * Must be called with ust lock held.
433 * Returns NULL if not present.
434 */
435 struct wildcard_entry *match_wildcard(const char *name)
436 {
437 struct wildcard_entry *e;
438
439 cds_list_for_each_entry(e, &wildcard_list, list) {
440 /* If only contain '*' */
441 if (strlen(e->name) == 1)
442 return e;
443 /* Compare excluding final '*' */
444 if (!strncmp(name, e->name, strlen(e->name) - 1))
445 return e;
446 }
447 return NULL;
448 }
449
450 /*
451 * marshall all probes/all events and create those that fit the
452 * wildcard. Add them to the events list as created.
453 */
454 static
455 void _probes_create_wildcard_events(struct wildcard_entry *entry,
456 struct session_wildcard *wildcard)
457 {
458 struct lttng_probe_desc *probe_desc;
459 struct lttng_ust_event event_param;
460 int i;
461
462 cds_list_for_each_entry(probe_desc, &probe_list, head) {
463 for (i = 0; i < probe_desc->nr_events; i++) {
464 const struct lttng_event_desc *event_desc;
465 int match = 0;
466
467 event_desc = probe_desc->event_desc[i];
468 /* compare excluding final '*' */
469 assert(strlen(entry->name) > 0);
470 if (strcmp(event_desc->name, "lttng_ust:metadata")
471 && (strlen(entry->name) == 1
472 || !strncmp(event_desc->name, entry->name,
473 strlen(entry->name) - 1))) {
474 match = 1;
475 }
476 if (match) {
477 struct ltt_event *ev;
478 int ret;
479
480 memcpy(&event_param, &wildcard->event_param,
481 sizeof(event_param));
482 memcpy(event_param.name,
483 event_desc->name,
484 sizeof(event_param.name));
485 /* create event */
486 ret = ltt_event_create(wildcard->chan,
487 &event_param, NULL,
488 &ev);
489 if (ret) {
490 DBG("Error creating event");
491 continue;
492 }
493 cds_list_add(&ev->wildcard_list,
494 &wildcard->events);
495 }
496 }
497 }
498 }
499
500 /*
501 * Add the wildcard to the wildcard hash table. Must be called with
502 * ust lock held.
503 */
504 struct session_wildcard *add_wildcard(const char *name,
505 struct ltt_channel *chan,
506 struct lttng_ust_event *event_param)
507 {
508 struct wildcard_entry *e;
509 struct session_wildcard *sw;
510 size_t name_len = strlen(name) + 1;
511 int found = 0;
512
513 /* wildcard entry */
514 cds_list_for_each_entry(e, &wildcard_list, list) {
515 if (!strcmp(name, e->name)) {
516 found = 1;
517 break;
518 }
519 }
520
521 if (!found) {
522 /*
523 * Using zmalloc here to allocate a variable length element. Could
524 * cause some memory fragmentation if overused.
525 */
526 e = zmalloc(sizeof(struct wildcard_entry) + name_len);
527 if (!e)
528 return ERR_PTR(-ENOMEM);
529 memcpy(&e->name[0], name, name_len);
530 cds_list_add(&e->list, &wildcard_list);
531 CDS_INIT_LIST_HEAD(&e->session_list);
532 }
533
534 /* session wildcard */
535 cds_list_for_each_entry(sw, &e->session_list, session_list) {
536 if (chan == sw->chan) {
537 DBG("wildcard %s busy for this channel", name);
538 return ERR_PTR(-EEXIST); /* Already there */
539 }
540 }
541 sw = zmalloc(sizeof(struct session_wildcard));
542 if (!sw)
543 return ERR_PTR(-ENOMEM);
544 sw->chan = chan;
545 sw->enabled = 1;
546 memcpy(&sw->event_param, event_param, sizeof(sw->event_param));
547 sw->event_param.instrumentation = LTTNG_UST_TRACEPOINT;
548 CDS_INIT_LIST_HEAD(&sw->events);
549 cds_list_add(&sw->list, &chan->session->wildcards);
550 cds_list_add(&sw->session_list, &e->session_list);
551 sw->entry = e;
552 _probes_create_wildcard_events(e, sw);
553 return sw;
554 }
555
556 /*
557 * Remove the wildcard from the wildcard hash table. Must be called with
558 * ust_lock held. Only called at session teardown.
559 */
560 void _remove_wildcard(struct session_wildcard *wildcard)
561 {
562 struct ltt_event *ev, *tmp;
563
564 /*
565 * Just remove the events owned (for enable/disable) by this
566 * wildcard from the list. The session teardown will take care
567 * of freeing the event memory.
568 */
569 cds_list_for_each_entry_safe(ev, tmp, &wildcard->events,
570 wildcard_list) {
571 cds_list_del(&ev->wildcard_list);
572 }
573 cds_list_del(&wildcard->session_list);
574 cds_list_del(&wildcard->list);
575 if (cds_list_empty(&wildcard->entry->session_list)) {
576 cds_list_del(&wildcard->entry->list);
577 free(wildcard->entry);
578 }
579 free(wildcard);
580 }
581
582 int ltt_wildcard_enable(struct session_wildcard *wildcard)
583 {
584 struct ltt_event *ev;
585 int ret;
586
587 if (wildcard->enabled)
588 return -EEXIST;
589 cds_list_for_each_entry(ev, &wildcard->events, wildcard_list) {
590 ret = ltt_event_enable(ev);
591 if (ret) {
592 DBG("Error: enable error.\n");
593 return ret;
594 }
595 }
596 wildcard->enabled = 1;
597 return 0;
598 }
599
600 int ltt_wildcard_disable(struct session_wildcard *wildcard)
601 {
602 struct ltt_event *ev;
603 int ret;
604
605 if (!wildcard->enabled)
606 return -EEXIST;
607 cds_list_for_each_entry(ev, &wildcard->events, wildcard_list) {
608 ret = ltt_event_disable(ev);
609 if (ret) {
610 DBG("Error: disable error.\n");
611 return ret;
612 }
613 }
614 wildcard->enabled = 0;
615 return 0;
616 }
This page took 0.041069 seconds and 3 git commands to generate.