4 * Copyright 2010 (c) - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
6 * Holds LTTng probes registry.
8 * Dual LGPL v2.1/GPL v2 license.
13 #include <urcu/list.h>
14 #include <urcu/hlist.h>
15 #include <lttng/ust-events.h>
20 #include "ltt-tracer-core.h"
25 * probe list is protected by ust_lock()/ust_unlock().
27 static CDS_LIST_HEAD(probe_list
);
30 * Loglevel hash table, containing the active loglevels.
31 * Protected by ust lock.
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
];
38 * Wildcard list, containing the active wildcards.
39 * Protected by ust lock.
41 static CDS_LIST_HEAD(wildcard_list
);
44 const struct lttng_probe_desc
*find_provider(const char *provider
)
46 struct lttng_probe_desc
*iter
;
48 cds_list_for_each_entry(iter
, &probe_list
, head
) {
49 if (!strcmp(iter
->provider
, provider
))
56 const struct lttng_event_desc
*find_event(const char *name
)
58 struct lttng_probe_desc
*probe_desc
;
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
];
70 int ltt_probe_register(struct lttng_probe_desc
*desc
)
72 struct lttng_probe_desc
*iter
;
77 if (find_provider(desc
->provider
)) {
82 * TODO: This is O(N^2). Turn into a hash table when probe registration
83 * overhead becomes an issue.
85 for (i
= 0; i
< desc
->nr_events
; i
++) {
86 if (find_event(desc
->event_desc
[i
]->name
)) {
93 * We sort the providers by struct lttng_probe_desc pointer
96 cds_list_for_each_entry_reverse(iter
, &probe_list
, head
) {
97 BUG_ON(iter
== desc
); /* Should never be in the list twice */
99 /* We belong to the location right after iter. */
100 cds_list_add(&desc
->head
, &iter
->head
);
104 /* We should be added at the head of the list */
105 cds_list_add(&desc
->head
, &probe_list
);
109 * fix the events awaiting probe load.
111 for (i
= 0; i
< desc
->nr_events
; i
++) {
112 ret
= pending_probe_fix_events(desc
->event_desc
[i
]);
120 void ltt_probe_unregister(struct lttng_probe_desc
*desc
)
123 cds_list_del(&desc
->head
);
128 * called with UST lock held.
130 const struct lttng_event_desc
*ltt_event_get(const char *name
)
132 const struct lttng_event_desc
*event
;
134 event
= find_event(name
);
140 void ltt_event_put(const struct lttng_event_desc
*event
)
144 void ltt_probes_prune_event_list(struct lttng_ust_tracepoint_list
*list
)
146 struct tp_list_entry
*list_entry
, *tmp
;
148 cds_list_for_each_entry_safe(list_entry
, tmp
, &list
->head
, head
) {
149 cds_list_del(&list_entry
->head
);
155 * called with UST lock held.
157 int ltt_probes_get_event_list(struct lttng_ust_tracepoint_list
*list
)
159 struct lttng_probe_desc
*probe_desc
;
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
;
167 list_entry
= zmalloc(sizeof(*list_entry
));
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;
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
;
188 if (cds_list_empty(&list
->head
))
192 cds_list_first_entry(&list
->head
, struct tp_list_entry
, head
);
196 ltt_probes_prune_event_list(list
);
201 * Return current iteration position, advance internal iterator to next.
202 * Return NULL if end of list.
204 struct lttng_ust_tracepoint_iter
*
205 lttng_ust_tracepoint_list_get_iter_next(struct lttng_ust_tracepoint_list
*list
)
207 struct tp_list_entry
*entry
;
212 if (entry
->head
.next
== &list
->head
)
215 list
->iter
= cds_list_entry(entry
->head
.next
,
216 struct tp_list_entry
, head
);
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.
225 struct loglevel_entry
*get_loglevel(const char *name
)
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);
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
))
240 struct loglevel_entry
*get_loglevel_value(int64_t value
)
242 char name
[LTTNG_UST_SYM_NAME_LEN
];
245 ret
= snprintf(name
, LTTNG_UST_SYM_NAME_LEN
, "%lld", (long long) value
);
248 return get_loglevel(name
);
252 * marshall all probes/all events and create those that fit the
253 * loglevel. Add them to the events list as created.
256 void _probes_create_loglevel_events(struct loglevel_entry
*entry
,
257 struct session_loglevel
*loglevel
)
259 struct lttng_probe_desc
*probe_desc
;
260 struct lttng_ust_event event_param
;
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
;
269 event_desc
= probe_desc
->event_desc
[i
];
270 if (!(event_desc
->loglevel
))
272 ev_ll
= *event_desc
->loglevel
;
273 if (isdigit(entry
->name
[0])) {
274 if (atoll(entry
->name
) == ev_ll
->value
) {
277 } else if (!strcmp(ev_ll
->identifier
, entry
->name
)) {
282 struct ltt_event
*ev
;
285 memcpy(&event_param
, &loglevel
->event_param
,
286 sizeof(event_param
));
287 memcpy(event_param
.name
,
289 sizeof(event_param
.name
));
291 ret
= ltt_event_create(loglevel
->chan
,
295 DBG("Error creating event");
298 cds_list_add(&ev
->loglevel_list
,
306 * Add the loglevel to the loglevel hash table. Must be called with
309 struct session_loglevel
*add_loglevel(const char *name
,
310 struct ltt_channel
*chan
,
311 struct lttng_ust_event
*event_param
)
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);
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
)) {
332 * Using zmalloc here to allocate a variable length element. Could
333 * cause some memory fragmentation if overused.
335 e
= zmalloc(sizeof(struct loglevel_entry
) + name_len
);
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
);
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 */
350 sl
= zmalloc(sizeof(struct session_loglevel
));
352 return ERR_PTR(-ENOMEM
);
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
);
361 _probes_create_loglevel_events(e
, sl
);
366 * Remove the loglevel from the loglevel hash table. Must be called with
367 * ust_lock held. Only called at session teardown.
369 void _remove_loglevel(struct session_loglevel
*loglevel
)
371 struct ltt_event
*ev
, *tmp
;
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.
378 cds_list_for_each_entry_safe(ev
, tmp
, &loglevel
->events
,
380 cds_list_del(&ev
->loglevel_list
);
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
);
391 int ltt_loglevel_enable(struct session_loglevel
*loglevel
)
393 struct ltt_event
*ev
;
396 if (loglevel
->enabled
)
398 cds_list_for_each_entry(ev
, &loglevel
->events
, loglevel_list
) {
399 ret
= ltt_event_enable(ev
);
401 DBG("Error: enable error.\n");
405 loglevel
->enabled
= 1;
409 int ltt_loglevel_disable(struct session_loglevel
*loglevel
)
411 struct ltt_event
*ev
;
414 if (!loglevel
->enabled
)
416 cds_list_for_each_entry(ev
, &loglevel
->events
, loglevel_list
) {
417 ret
= ltt_event_disable(ev
);
419 DBG("Error: disable error.\n");
423 loglevel
->enabled
= 0;
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.
435 struct wildcard_entry
*match_wildcard(const char *name
)
437 struct wildcard_entry
*e
;
439 cds_list_for_each_entry(e
, &wildcard_list
, list
) {
440 /* If only contain '*' */
441 if (strlen(e
->name
) == 1)
443 /* Compare excluding final '*' */
444 if (!strncmp(name
, e
->name
, strlen(e
->name
) - 1))
451 * marshall all probes/all events and create those that fit the
452 * wildcard. Add them to the events list as created.
455 void _probes_create_wildcard_events(struct wildcard_entry
*entry
,
456 struct session_wildcard
*wildcard
)
458 struct lttng_probe_desc
*probe_desc
;
459 struct lttng_ust_event event_param
;
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
;
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))) {
477 struct ltt_event
*ev
;
480 memcpy(&event_param
, &wildcard
->event_param
,
481 sizeof(event_param
));
482 memcpy(event_param
.name
,
484 sizeof(event_param
.name
));
486 ret
= ltt_event_create(wildcard
->chan
,
490 DBG("Error creating event");
493 cds_list_add(&ev
->wildcard_list
,
501 * Add the wildcard to the wildcard hash table. Must be called with
504 struct session_wildcard
*add_wildcard(const char *name
,
505 struct ltt_channel
*chan
,
506 struct lttng_ust_event
*event_param
)
508 struct wildcard_entry
*e
;
509 struct session_wildcard
*sw
;
510 size_t name_len
= strlen(name
) + 1;
514 cds_list_for_each_entry(e
, &wildcard_list
, list
) {
515 if (!strcmp(name
, e
->name
)) {
523 * Using zmalloc here to allocate a variable length element. Could
524 * cause some memory fragmentation if overused.
526 e
= zmalloc(sizeof(struct wildcard_entry
) + name_len
);
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
);
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 */
541 sw
= zmalloc(sizeof(struct session_wildcard
));
543 return ERR_PTR(-ENOMEM
);
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
);
552 _probes_create_wildcard_events(e
, sw
);
557 * Remove the wildcard from the wildcard hash table. Must be called with
558 * ust_lock held. Only called at session teardown.
560 void _remove_wildcard(struct session_wildcard
*wildcard
)
562 struct ltt_event
*ev
, *tmp
;
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.
569 cds_list_for_each_entry_safe(ev
, tmp
, &wildcard
->events
,
571 cds_list_del(&ev
->wildcard_list
);
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
);
582 int ltt_wildcard_enable(struct session_wildcard
*wildcard
)
584 struct ltt_event
*ev
;
587 if (wildcard
->enabled
)
589 cds_list_for_each_entry(ev
, &wildcard
->events
, wildcard_list
) {
590 ret
= ltt_event_enable(ev
);
592 DBG("Error: enable error.\n");
596 wildcard
->enabled
= 1;
600 int ltt_wildcard_disable(struct session_wildcard
*wildcard
)
602 struct ltt_event
*ev
;
605 if (!wildcard
->enabled
)
607 cds_list_for_each_entry(ev
, &wildcard
->events
, wildcard_list
) {
608 ret
= ltt_event_disable(ev
);
610 DBG("Error: disable error.\n");
614 wildcard
->enabled
= 0;