Add sock flush buffer ctl API
[lttng-ust.git] / liblttng-ust / ltt-probes.c
CommitLineData
ce5aef0b
MD
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
8d8a24c8
MD
11#include <string.h>
12#include <errno.h>
13#include <urcu/list.h>
1f18504e 14#include <urcu/hlist.h>
4318ae1b 15#include <lttng/ust-events.h>
a3bb4b27 16#include <assert.h>
c8fcf224 17#include <helper.h>
48740cab 18#include <ctype.h>
ce5aef0b 19
8165c8da 20#include "ltt-tracer-core.h"
1f18504e
MD
21#include "jhash.h"
22#include "error.h"
8165c8da
MD
23
24/*
17dfb34b 25 * probe list is protected by ust_lock()/ust_unlock().
8165c8da 26 */
8d8a24c8 27static CDS_LIST_HEAD(probe_list);
ce5aef0b 28
1f18504e
MD
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)
35static struct cds_hlist_head loglevel_table[LOGLEVEL_TABLE_SIZE];
36
e6c12e3d
MD
37/*
38 * Wildcard list, containing the active wildcards.
39 * Protected by ust lock.
40 */
41static CDS_LIST_HEAD(wildcard_list);
42
df854e41
MD
43static
44const 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
ce5aef0b
MD
55static
56const struct lttng_event_desc *find_event(const char *name)
57{
58 struct lttng_probe_desc *probe_desc;
59 int i;
60
8d8a24c8 61 cds_list_for_each_entry(probe_desc, &probe_list, head) {
ce5aef0b 62 for (i = 0; i < probe_desc->nr_events; i++) {
df854e41
MD
63 if (!strcmp(probe_desc->event_desc[i]->name, name))
64 return probe_desc->event_desc[i];
ce5aef0b
MD
65 }
66 }
67 return NULL;
68}
69
70int ltt_probe_register(struct lttng_probe_desc *desc)
71{
df854e41 72 struct lttng_probe_desc *iter;
ce5aef0b
MD
73 int ret = 0;
74 int i;
75
17dfb34b 76 ust_lock();
df854e41
MD
77 if (find_provider(desc->provider)) {
78 ret = -EEXIST;
79 goto end;
80 }
ce5aef0b
MD
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++) {
df854e41 86 if (find_event(desc->event_desc[i]->name)) {
ce5aef0b
MD
87 ret = -EEXIST;
88 goto end;
89 }
90 }
df854e41
MD
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 */
8d8a24c8 105 cds_list_add(&desc->head, &probe_list);
df854e41 106desc_added:
8165c8da
MD
107
108 /*
109 * fix the events awaiting probe load.
110 */
111 for (i = 0; i < desc->nr_events; i++) {
df854e41 112 ret = pending_probe_fix_events(desc->event_desc[i]);
8165c8da
MD
113 assert(!ret);
114 }
ce5aef0b 115end:
17dfb34b 116 ust_unlock();
ce5aef0b
MD
117 return ret;
118}
ce5aef0b
MD
119
120void ltt_probe_unregister(struct lttng_probe_desc *desc)
121{
17dfb34b 122 ust_lock();
8d8a24c8 123 cds_list_del(&desc->head);
17dfb34b 124 ust_unlock();
ce5aef0b 125}
ce5aef0b 126
8165c8da
MD
127/*
128 * called with UST lock held.
129 */
ce5aef0b
MD
130const struct lttng_event_desc *ltt_event_get(const char *name)
131{
132 const struct lttng_event_desc *event;
ce5aef0b 133
ce5aef0b 134 event = find_event(name);
ce5aef0b
MD
135 if (!event)
136 return NULL;
ce5aef0b
MD
137 return event;
138}
ce5aef0b
MD
139
140void ltt_event_put(const struct lttng_event_desc *event)
141{
ce5aef0b 142}
c8fcf224
MD
143
144void 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 */
157int 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
195err_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 */
204struct 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}
1f18504e
MD
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 */
225struct 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
48740cab
MD
240struct 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
1f18504e
MD
251/*
252 * marshall all probes/all events and create those that fit the
253 * loglevel. Add them to the events list as created.
254 */
255static
574a6217
MD
256void _probes_create_loglevel_events(struct loglevel_entry *entry,
257 struct session_loglevel *loglevel)
1f18504e
MD
258{
259 struct lttng_probe_desc *probe_desc;
7ee3cc56 260 struct lttng_ust_event event_param;
1f18504e
MD
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;
7ee3cc56 266 const struct lttng_event_desc *event_desc;
5e87eb4a 267 int match = 0;
1f18504e 268
7ee3cc56
MD
269 event_desc = probe_desc->event_desc[i];
270 if (!(event_desc->loglevel))
1f18504e 271 continue;
7ee3cc56 272 ev_ll = *event_desc->loglevel;
3431ca3e 273 if (isdigit(entry->name[0])) {
48740cab
MD
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) {
1f18504e
MD
282 struct ltt_event *ev;
283 int ret;
284
7ee3cc56
MD
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));
1f18504e
MD
290 /* create event */
291 ret = ltt_event_create(loglevel->chan,
7ee3cc56 292 &event_param, NULL,
1f18504e 293 &ev);
7ee3cc56
MD
294 if (ret) {
295 DBG("Error creating event");
1f18504e 296 continue;
7ee3cc56 297 }
1f18504e
MD
298 cds_list_add(&ev->loglevel_list,
299 &loglevel->events);
300 }
1f18504e
MD
301 }
302 }
303}
304
305/*
306 * Add the loglevel to the loglevel hash table. Must be called with
307 * ust lock held.
308 */
574a6217 309struct session_loglevel *add_loglevel(const char *name,
1f18504e
MD
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;
574a6217 316 struct session_loglevel *sl;
1f18504e
MD
317 size_t name_len = strlen(name) + 1;
318 uint32_t hash = jhash(name, name_len-1, 0);
574a6217 319 int found = 0;
1f18504e 320
574a6217 321 /* loglevel entry */
1f18504e
MD
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)) {
574a6217
MD
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);
d5201d38 340 CDS_INIT_LIST_HEAD(&e->session_list);
574a6217
MD
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);
1f18504e
MD
347 return ERR_PTR(-EEXIST); /* Already there */
348 }
349 }
574a6217
MD
350 sl = zmalloc(sizeof(struct session_loglevel));
351 if (!sl)
1f18504e 352 return ERR_PTR(-ENOMEM);
574a6217
MD
353 sl->chan = chan;
354 sl->enabled = 1;
355 memcpy(&sl->event_param, event_param, sizeof(sl->event_param));
d5201d38 356 sl->event_param.instrumentation = LTTNG_UST_TRACEPOINT;
574a6217
MD
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);
2981744d 360 sl->entry = e;
574a6217
MD
361 _probes_create_loglevel_events(e, sl);
362 return sl;
1f18504e
MD
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 */
574a6217 369void _remove_loglevel(struct session_loglevel *loglevel)
1f18504e
MD
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 */
66221151
MD
378 cds_list_for_each_entry_safe(ev, tmp, &loglevel->events,
379 loglevel_list) {
380 cds_list_del(&ev->loglevel_list);
1f18504e 381 }
574a6217 382 cds_list_del(&loglevel->session_list);
1f18504e 383 cds_list_del(&loglevel->list);
574a6217
MD
384 if (cds_list_empty(&loglevel->entry->session_list)) {
385 cds_hlist_del(&loglevel->entry->hlist);
386 free(loglevel->entry);
387 }
1f18504e
MD
388 free(loglevel);
389}
390
574a6217 391int ltt_loglevel_enable(struct session_loglevel *loglevel)
1f18504e
MD
392{
393 struct ltt_event *ev;
394 int ret;
395
396 if (loglevel->enabled)
397 return -EEXIST;
66221151 398 cds_list_for_each_entry(ev, &loglevel->events, loglevel_list) {
1f18504e
MD
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
574a6217 409int ltt_loglevel_disable(struct session_loglevel *loglevel)
1f18504e
MD
410{
411 struct ltt_event *ev;
412 int ret;
413
414 if (!loglevel->enabled)
415 return -EEXIST;
66221151 416 cds_list_for_each_entry(ev, &loglevel->events, loglevel_list) {
1f18504e
MD
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}
e6c12e3d
MD
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 */
435struct 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 */
454static
455void _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 */
504struct 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 */
560void _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 */
66221151
MD
569 cds_list_for_each_entry_safe(ev, tmp, &wildcard->events,
570 wildcard_list) {
571 cds_list_del(&ev->wildcard_list);
e6c12e3d
MD
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
582int ltt_wildcard_enable(struct session_wildcard *wildcard)
583{
584 struct ltt_event *ev;
585 int ret;
586
587 if (wildcard->enabled)
588 return -EEXIST;
66221151 589 cds_list_for_each_entry(ev, &wildcard->events, wildcard_list) {
e6c12e3d
MD
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
600int ltt_wildcard_disable(struct session_wildcard *wildcard)
601{
602 struct ltt_event *ev;
603 int ret;
604
605 if (!wildcard->enabled)
606 return -EEXIST;
66221151 607 cds_list_for_each_entry(ev, &wildcard->events, wildcard_list) {
e6c12e3d
MD
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.050924 seconds and 4 git commands to generate.