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 const struct lttng_probe_desc
*find_provider(const char *provider
)
40 struct lttng_probe_desc
*iter
;
42 cds_list_for_each_entry(iter
, &probe_list
, head
) {
43 if (!strcmp(iter
->provider
, provider
))
50 const struct lttng_event_desc
*find_event(const char *name
)
52 struct lttng_probe_desc
*probe_desc
;
55 cds_list_for_each_entry(probe_desc
, &probe_list
, head
) {
56 for (i
= 0; i
< probe_desc
->nr_events
; i
++) {
57 if (!strcmp(probe_desc
->event_desc
[i
]->name
, name
))
58 return probe_desc
->event_desc
[i
];
64 int ltt_probe_register(struct lttng_probe_desc
*desc
)
66 struct lttng_probe_desc
*iter
;
71 if (find_provider(desc
->provider
)) {
76 * TODO: This is O(N^2). Turn into a hash table when probe registration
77 * overhead becomes an issue.
79 for (i
= 0; i
< desc
->nr_events
; i
++) {
80 if (find_event(desc
->event_desc
[i
]->name
)) {
87 * We sort the providers by struct lttng_probe_desc pointer
90 cds_list_for_each_entry_reverse(iter
, &probe_list
, head
) {
91 BUG_ON(iter
== desc
); /* Should never be in the list twice */
93 /* We belong to the location right after iter. */
94 cds_list_add(&desc
->head
, &iter
->head
);
98 /* We should be added at the head of the list */
99 cds_list_add(&desc
->head
, &probe_list
);
103 * fix the events awaiting probe load.
105 for (i
= 0; i
< desc
->nr_events
; i
++) {
106 ret
= pending_probe_fix_events(desc
->event_desc
[i
]);
114 void ltt_probe_unregister(struct lttng_probe_desc
*desc
)
117 cds_list_del(&desc
->head
);
122 * called with UST lock held.
124 const struct lttng_event_desc
*ltt_event_get(const char *name
)
126 const struct lttng_event_desc
*event
;
128 event
= find_event(name
);
134 void ltt_event_put(const struct lttng_event_desc
*event
)
138 void ltt_probes_prune_event_list(struct lttng_ust_tracepoint_list
*list
)
140 struct tp_list_entry
*list_entry
, *tmp
;
142 cds_list_for_each_entry_safe(list_entry
, tmp
, &list
->head
, head
) {
143 cds_list_del(&list_entry
->head
);
149 * called with UST lock held.
151 int ltt_probes_get_event_list(struct lttng_ust_tracepoint_list
*list
)
153 struct lttng_probe_desc
*probe_desc
;
156 CDS_INIT_LIST_HEAD(&list
->head
);
157 cds_list_for_each_entry(probe_desc
, &probe_list
, head
) {
158 for (i
= 0; i
< probe_desc
->nr_events
; i
++) {
159 struct tp_list_entry
*list_entry
;
161 list_entry
= zmalloc(sizeof(*list_entry
));
164 cds_list_add(&list_entry
->head
, &list
->head
);
165 strncpy(list_entry
->tp
.name
,
166 probe_desc
->event_desc
[i
]->name
,
167 LTTNG_UST_SYM_NAME_LEN
);
168 list_entry
->tp
.name
[LTTNG_UST_SYM_NAME_LEN
- 1] = '\0';
169 if (!probe_desc
->event_desc
[i
]->loglevel
) {
170 list_entry
->tp
.loglevel
[0] = '\0';
171 list_entry
->tp
.loglevel_value
= 0;
173 strncpy(list_entry
->tp
.loglevel
,
174 (*probe_desc
->event_desc
[i
]->loglevel
)->identifier
,
175 LTTNG_UST_SYM_NAME_LEN
);
176 list_entry
->tp
.loglevel
[LTTNG_UST_SYM_NAME_LEN
- 1] = '\0';
177 list_entry
->tp
.loglevel_value
=
178 (*probe_desc
->event_desc
[i
]->loglevel
)->value
;
182 if (cds_list_empty(&list
->head
))
186 cds_list_first_entry(&list
->head
, struct tp_list_entry
, head
);
190 ltt_probes_prune_event_list(list
);
195 * Return current iteration position, advance internal iterator to next.
196 * Return NULL if end of list.
198 struct lttng_ust_tracepoint_iter
*
199 lttng_ust_tracepoint_list_get_iter_next(struct lttng_ust_tracepoint_list
*list
)
201 struct tp_list_entry
*entry
;
206 if (entry
->head
.next
== &list
->head
)
209 list
->iter
= cds_list_entry(entry
->head
.next
,
210 struct tp_list_entry
, head
);
215 * Get loglevel if the loglevel is present in the loglevel hash table.
216 * Must be called with ust lock held.
217 * Returns NULL if not present.
219 struct loglevel_entry
*get_loglevel(const char *name
)
221 struct cds_hlist_head
*head
;
222 struct cds_hlist_node
*node
;
223 struct loglevel_entry
*e
;
224 uint32_t hash
= jhash(name
, strlen(name
), 0);
226 head
= &loglevel_table
[hash
& (LOGLEVEL_TABLE_SIZE
- 1)];
227 cds_hlist_for_each_entry(e
, node
, head
, hlist
) {
228 if (!strcmp(name
, e
->name
))
234 struct loglevel_entry
*get_loglevel_value(int64_t value
)
236 char name
[LTTNG_UST_SYM_NAME_LEN
];
239 ret
= snprintf(name
, LTTNG_UST_SYM_NAME_LEN
, "%lld", (long long) value
);
242 return get_loglevel(name
);
246 * marshall all probes/all events and create those that fit the
247 * loglevel. Add them to the events list as created.
250 void _probes_create_loglevel_events(struct loglevel_entry
*entry
,
251 struct session_loglevel
*loglevel
)
253 struct lttng_probe_desc
*probe_desc
;
254 struct lttng_ust_event event_param
;
257 cds_list_for_each_entry(probe_desc
, &probe_list
, head
) {
258 for (i
= 0; i
< probe_desc
->nr_events
; i
++) {
259 const struct tracepoint_loglevel_entry
*ev_ll
;
260 const struct lttng_event_desc
*event_desc
;
263 event_desc
= probe_desc
->event_desc
[i
];
264 if (!(event_desc
->loglevel
))
266 ev_ll
= *event_desc
->loglevel
;
267 if (isalpha(entry
->name
[0])) {
268 if (atoll(entry
->name
) == ev_ll
->value
) {
271 } else if (!strcmp(ev_ll
->identifier
, entry
->name
)) {
276 struct ltt_event
*ev
;
279 memcpy(&event_param
, &loglevel
->event_param
,
280 sizeof(event_param
));
281 memcpy(event_param
.name
,
283 sizeof(event_param
.name
));
285 ret
= ltt_event_create(loglevel
->chan
,
289 DBG("Error creating event");
292 cds_list_add(&ev
->loglevel_list
,
300 * Add the loglevel to the loglevel hash table. Must be called with
303 struct session_loglevel
*add_loglevel(const char *name
,
304 struct ltt_channel
*chan
,
305 struct lttng_ust_event
*event_param
)
307 struct cds_hlist_head
*head
;
308 struct cds_hlist_node
*node
;
309 struct loglevel_entry
*e
;
310 struct session_loglevel
*sl
;
311 size_t name_len
= strlen(name
) + 1;
312 uint32_t hash
= jhash(name
, name_len
-1, 0);
316 head
= &loglevel_table
[hash
& (LOGLEVEL_TABLE_SIZE
- 1)];
317 cds_hlist_for_each_entry(e
, node
, head
, hlist
) {
318 if (!strcmp(name
, e
->name
)) {
326 * Using zmalloc here to allocate a variable length element. Could
327 * cause some memory fragmentation if overused.
329 e
= zmalloc(sizeof(struct loglevel_entry
) + name_len
);
331 return ERR_PTR(-ENOMEM
);
332 memcpy(&e
->name
[0], name
, name_len
);
333 cds_hlist_add_head(&e
->hlist
, head
);
334 CDS_INIT_LIST_HEAD(&e
->session_list
);
337 /* session loglevel */
338 cds_list_for_each_entry(sl
, &e
->session_list
, session_list
) {
339 if (chan
== sl
->chan
) {
340 DBG("loglevel %s busy for this channel", name
);
341 return ERR_PTR(-EEXIST
); /* Already there */
344 sl
= zmalloc(sizeof(struct session_loglevel
));
346 return ERR_PTR(-ENOMEM
);
349 memcpy(&sl
->event_param
, event_param
, sizeof(sl
->event_param
));
350 sl
->event_param
.instrumentation
= LTTNG_UST_TRACEPOINT
;
351 CDS_INIT_LIST_HEAD(&sl
->events
);
352 cds_list_add(&sl
->list
, &chan
->session
->loglevels
);
353 cds_list_add(&sl
->session_list
, &e
->session_list
);
355 _probes_create_loglevel_events(e
, sl
);
360 * Remove the loglevel from the loglevel hash table. Must be called with
361 * ust_lock held. Only called at session teardown.
363 void _remove_loglevel(struct session_loglevel
*loglevel
)
365 struct ltt_event
*ev
, *tmp
;
368 * Just remove the events owned (for enable/disable) by this
369 * loglevel from the list. The session teardown will take care
370 * of freeing the event memory.
372 cds_list_for_each_entry_safe(ev
, tmp
, &loglevel
->events
, list
) {
373 cds_list_del(&ev
->list
);
375 cds_list_del(&loglevel
->session_list
);
376 cds_list_del(&loglevel
->list
);
377 if (cds_list_empty(&loglevel
->entry
->session_list
)) {
378 cds_hlist_del(&loglevel
->entry
->hlist
);
379 free(loglevel
->entry
);
384 int ltt_loglevel_enable(struct session_loglevel
*loglevel
)
386 struct ltt_event
*ev
;
389 if (loglevel
->enabled
)
391 cds_list_for_each_entry(ev
, &loglevel
->events
, list
) {
392 ret
= ltt_event_enable(ev
);
394 DBG("Error: enable error.\n");
398 loglevel
->enabled
= 1;
402 int ltt_loglevel_disable(struct session_loglevel
*loglevel
)
404 struct ltt_event
*ev
;
407 if (!loglevel
->enabled
)
409 cds_list_for_each_entry(ev
, &loglevel
->events
, list
) {
410 ret
= ltt_event_disable(ev
);
412 DBG("Error: disable error.\n");
416 loglevel
->enabled
= 0;