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>
19 #include "ltt-tracer-core.h"
24 * probe list is protected by ust_lock()/ust_unlock().
26 static CDS_LIST_HEAD(probe_list
);
29 * Loglevel hash table, containing the active loglevels.
30 * Protected by ust lock.
32 #define LOGLEVEL_HASH_BITS 6
33 #define LOGLEVEL_TABLE_SIZE (1 << LOGLEVEL_HASH_BITS)
34 static struct cds_hlist_head loglevel_table
[LOGLEVEL_TABLE_SIZE
];
37 const struct lttng_probe_desc
*find_provider(const char *provider
)
39 struct lttng_probe_desc
*iter
;
41 cds_list_for_each_entry(iter
, &probe_list
, head
) {
42 if (!strcmp(iter
->provider
, provider
))
49 const struct lttng_event_desc
*find_event(const char *name
)
51 struct lttng_probe_desc
*probe_desc
;
54 cds_list_for_each_entry(probe_desc
, &probe_list
, head
) {
55 for (i
= 0; i
< probe_desc
->nr_events
; i
++) {
56 if (!strcmp(probe_desc
->event_desc
[i
]->name
, name
))
57 return probe_desc
->event_desc
[i
];
63 int ltt_probe_register(struct lttng_probe_desc
*desc
)
65 struct lttng_probe_desc
*iter
;
70 if (find_provider(desc
->provider
)) {
75 * TODO: This is O(N^2). Turn into a hash table when probe registration
76 * overhead becomes an issue.
78 for (i
= 0; i
< desc
->nr_events
; i
++) {
79 if (find_event(desc
->event_desc
[i
]->name
)) {
86 * We sort the providers by struct lttng_probe_desc pointer
89 cds_list_for_each_entry_reverse(iter
, &probe_list
, head
) {
90 BUG_ON(iter
== desc
); /* Should never be in the list twice */
92 /* We belong to the location right after iter. */
93 cds_list_add(&desc
->head
, &iter
->head
);
97 /* We should be added at the head of the list */
98 cds_list_add(&desc
->head
, &probe_list
);
102 * fix the events awaiting probe load.
104 for (i
= 0; i
< desc
->nr_events
; i
++) {
105 ret
= pending_probe_fix_events(desc
->event_desc
[i
]);
113 void ltt_probe_unregister(struct lttng_probe_desc
*desc
)
116 cds_list_del(&desc
->head
);
121 * called with UST lock held.
123 const struct lttng_event_desc
*ltt_event_get(const char *name
)
125 const struct lttng_event_desc
*event
;
127 event
= find_event(name
);
133 void ltt_event_put(const struct lttng_event_desc
*event
)
137 void ltt_probes_prune_event_list(struct lttng_ust_tracepoint_list
*list
)
139 struct tp_list_entry
*list_entry
, *tmp
;
141 cds_list_for_each_entry_safe(list_entry
, tmp
, &list
->head
, head
) {
142 cds_list_del(&list_entry
->head
);
148 * called with UST lock held.
150 int ltt_probes_get_event_list(struct lttng_ust_tracepoint_list
*list
)
152 struct lttng_probe_desc
*probe_desc
;
155 CDS_INIT_LIST_HEAD(&list
->head
);
156 cds_list_for_each_entry(probe_desc
, &probe_list
, head
) {
157 for (i
= 0; i
< probe_desc
->nr_events
; i
++) {
158 struct tp_list_entry
*list_entry
;
160 list_entry
= zmalloc(sizeof(*list_entry
));
163 cds_list_add(&list_entry
->head
, &list
->head
);
164 strncpy(list_entry
->tp
.name
,
165 probe_desc
->event_desc
[i
]->name
,
166 LTTNG_UST_SYM_NAME_LEN
);
167 list_entry
->tp
.name
[LTTNG_UST_SYM_NAME_LEN
- 1] = '\0';
168 if (!probe_desc
->event_desc
[i
]->loglevel
) {
169 list_entry
->tp
.loglevel
[0] = '\0';
170 list_entry
->tp
.loglevel_value
= 0;
172 strncpy(list_entry
->tp
.loglevel
,
173 (*probe_desc
->event_desc
[i
]->loglevel
)->identifier
,
174 LTTNG_UST_SYM_NAME_LEN
);
175 list_entry
->tp
.loglevel
[LTTNG_UST_SYM_NAME_LEN
- 1] = '\0';
176 list_entry
->tp
.loglevel_value
=
177 (*probe_desc
->event_desc
[i
]->loglevel
)->value
;
181 if (cds_list_empty(&list
->head
))
185 cds_list_first_entry(&list
->head
, struct tp_list_entry
, head
);
189 ltt_probes_prune_event_list(list
);
194 * Return current iteration position, advance internal iterator to next.
195 * Return NULL if end of list.
197 struct lttng_ust_tracepoint_iter
*
198 lttng_ust_tracepoint_list_get_iter_next(struct lttng_ust_tracepoint_list
*list
)
200 struct tp_list_entry
*entry
;
205 if (entry
->head
.next
== &list
->head
)
208 list
->iter
= cds_list_entry(entry
->head
.next
,
209 struct tp_list_entry
, head
);
214 * Get loglevel if the loglevel is present in the loglevel hash table.
215 * Must be called with ust lock held.
216 * Returns NULL if not present.
218 struct loglevel_entry
*get_loglevel(const char *name
)
220 struct cds_hlist_head
*head
;
221 struct cds_hlist_node
*node
;
222 struct loglevel_entry
*e
;
223 uint32_t hash
= jhash(name
, strlen(name
), 0);
225 head
= &loglevel_table
[hash
& (LOGLEVEL_TABLE_SIZE
- 1)];
226 cds_hlist_for_each_entry(e
, node
, head
, hlist
) {
227 if (!strcmp(name
, e
->name
))
234 * marshall all probes/all events and create those that fit the
235 * loglevel. Add them to the events list as created.
238 void _probes_create_loglevel_events(struct loglevel_entry
*entry
,
239 struct session_loglevel
*loglevel
)
241 struct lttng_probe_desc
*probe_desc
;
244 cds_list_for_each_entry(probe_desc
, &probe_list
, head
) {
245 for (i
= 0; i
< probe_desc
->nr_events
; i
++) {
246 const struct tracepoint_loglevel_entry
*ev_ll
;
248 if (!(probe_desc
->event_desc
[i
]->loglevel
))
250 ev_ll
= *probe_desc
->event_desc
[i
]->loglevel
;
251 if (!strcmp(ev_ll
->identifier
, entry
->name
)) {
252 struct ltt_event
*ev
;
256 ret
= ltt_event_create(loglevel
->chan
,
257 &loglevel
->event_param
, NULL
,
260 * TODO: report error.
264 cds_list_add(&ev
->loglevel_list
,
272 * Add the loglevel to the loglevel hash table. Must be called with
275 struct session_loglevel
*add_loglevel(const char *name
,
276 struct ltt_channel
*chan
,
277 struct lttng_ust_event
*event_param
)
279 struct cds_hlist_head
*head
;
280 struct cds_hlist_node
*node
;
281 struct loglevel_entry
*e
;
282 struct session_loglevel
*sl
;
283 size_t name_len
= strlen(name
) + 1;
284 uint32_t hash
= jhash(name
, name_len
-1, 0);
288 head
= &loglevel_table
[hash
& (LOGLEVEL_TABLE_SIZE
- 1)];
289 cds_hlist_for_each_entry(e
, node
, head
, hlist
) {
290 if (!strcmp(name
, e
->name
)) {
298 * Using zmalloc here to allocate a variable length element. Could
299 * cause some memory fragmentation if overused.
301 e
= zmalloc(sizeof(struct loglevel_entry
) + name_len
);
303 return ERR_PTR(-ENOMEM
);
304 memcpy(&e
->name
[0], name
, name_len
);
305 cds_hlist_add_head(&e
->hlist
, head
);
308 /* session loglevel */
309 cds_list_for_each_entry(sl
, &e
->session_list
, session_list
) {
310 if (chan
== sl
->chan
) {
311 DBG("loglevel %s busy for this channel", name
);
312 return ERR_PTR(-EEXIST
); /* Already there */
315 sl
= zmalloc(sizeof(struct session_loglevel
));
317 return ERR_PTR(-ENOMEM
);
320 memcpy(&sl
->event_param
, event_param
, sizeof(sl
->event_param
));
321 CDS_INIT_LIST_HEAD(&sl
->events
);
322 cds_list_add(&sl
->list
, &chan
->session
->loglevels
);
323 cds_list_add(&sl
->session_list
, &e
->session_list
);
324 _probes_create_loglevel_events(e
, sl
);
329 * Remove the loglevel from the loglevel hash table. Must be called with
330 * ust_lock held. Only called at session teardown.
332 void _remove_loglevel(struct session_loglevel
*loglevel
)
334 struct ltt_event
*ev
, *tmp
;
337 * Just remove the events owned (for enable/disable) by this
338 * loglevel from the list. The session teardown will take care
339 * of freeing the event memory.
341 cds_list_for_each_entry_safe(ev
, tmp
, &loglevel
->events
, list
) {
342 cds_list_del(&ev
->list
);
344 cds_list_del(&loglevel
->session_list
);
345 cds_list_del(&loglevel
->list
);
346 if (cds_list_empty(&loglevel
->entry
->session_list
)) {
347 cds_hlist_del(&loglevel
->entry
->hlist
);
348 free(loglevel
->entry
);
353 int ltt_loglevel_enable(struct session_loglevel
*loglevel
)
355 struct ltt_event
*ev
;
358 if (loglevel
->enabled
)
360 cds_list_for_each_entry(ev
, &loglevel
->events
, list
) {
361 ret
= ltt_event_enable(ev
);
363 DBG("Error: enable error.\n");
367 loglevel
->enabled
= 1;
371 int ltt_loglevel_disable(struct session_loglevel
*loglevel
)
373 struct ltt_event
*ev
;
376 if (!loglevel
->enabled
)
378 cds_list_for_each_entry(ev
, &loglevel
->events
, list
) {
379 ret
= ltt_event_disable(ev
);
381 DBG("Error: disable error.\n");
385 loglevel
->enabled
= 0;