Update loglevel ABI: only loglevel value/enum is known by UST
[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 "tracepoint-internal.h"
21 #include "ltt-tracer-core.h"
22 #include "jhash.h"
23 #include "error.h"
24
25 /*
26 * probe list is protected by ust_lock()/ust_unlock().
27 */
28 static CDS_LIST_HEAD(probe_list);
29
30 /*
31 * Wildcard list, containing the active wildcards.
32 * Protected by ust lock.
33 */
34 static CDS_LIST_HEAD(wildcard_list);
35
36 static
37 const struct lttng_probe_desc *find_provider(const char *provider)
38 {
39 struct lttng_probe_desc *iter;
40
41 cds_list_for_each_entry(iter, &probe_list, head) {
42 if (!strcmp(iter->provider, provider))
43 return iter;
44 }
45 return NULL;
46 }
47
48 static
49 const struct lttng_event_desc *find_event(const char *name)
50 {
51 struct lttng_probe_desc *probe_desc;
52 int i;
53
54 cds_list_for_each_entry(probe_desc, &probe_list, head) {
55 for (i = 0; i < probe_desc->nr_events; i++) {
56 if (!strncmp(probe_desc->event_desc[i]->name, name,
57 LTTNG_UST_SYM_NAME_LEN - 1))
58 return probe_desc->event_desc[i];
59 }
60 }
61 return NULL;
62 }
63
64 int ltt_probe_register(struct lttng_probe_desc *desc)
65 {
66 struct lttng_probe_desc *iter;
67 int ret = 0;
68 int i;
69
70 ust_lock();
71 if (find_provider(desc->provider)) {
72 ret = -EEXIST;
73 goto end;
74 }
75 /*
76 * TODO: This is O(N^2). Turn into a hash table when probe registration
77 * overhead becomes an issue.
78 */
79 for (i = 0; i < desc->nr_events; i++) {
80 if (find_event(desc->event_desc[i]->name)) {
81 ret = -EEXIST;
82 goto end;
83 }
84 }
85
86 /*
87 * We sort the providers by struct lttng_probe_desc pointer
88 * address.
89 */
90 cds_list_for_each_entry_reverse(iter, &probe_list, head) {
91 BUG_ON(iter == desc); /* Should never be in the list twice */
92 if (iter < desc) {
93 /* We belong to the location right after iter. */
94 cds_list_add(&desc->head, &iter->head);
95 goto desc_added;
96 }
97 }
98 /* We should be added at the head of the list */
99 cds_list_add(&desc->head, &probe_list);
100 desc_added:
101 DBG("just registered probe %s containing %u events",
102 desc->provider, desc->nr_events);
103 /*
104 * fix the events awaiting probe load.
105 */
106 for (i = 0; i < desc->nr_events; i++) {
107 ret = pending_probe_fix_events(desc->event_desc[i]);
108 assert(!ret);
109 }
110 end:
111 ust_unlock();
112 return ret;
113 }
114
115 void ltt_probe_unregister(struct lttng_probe_desc *desc)
116 {
117 ust_lock();
118 cds_list_del(&desc->head);
119 DBG("just unregistered probe %s", desc->provider);
120 ust_unlock();
121 }
122
123 /*
124 * called with UST lock held.
125 */
126 const struct lttng_event_desc *ltt_event_get(const char *name)
127 {
128 const struct lttng_event_desc *event;
129
130 event = find_event(name);
131 if (!event)
132 return NULL;
133 return event;
134 }
135
136 void ltt_event_put(const struct lttng_event_desc *event)
137 {
138 }
139
140 void ltt_probes_prune_event_list(struct lttng_ust_tracepoint_list *list)
141 {
142 struct tp_list_entry *list_entry, *tmp;
143
144 cds_list_for_each_entry_safe(list_entry, tmp, &list->head, head) {
145 cds_list_del(&list_entry->head);
146 free(list_entry);
147 }
148 }
149
150 /*
151 * called with UST lock held.
152 */
153 int ltt_probes_get_event_list(struct lttng_ust_tracepoint_list *list)
154 {
155 struct lttng_probe_desc *probe_desc;
156 int i;
157
158 CDS_INIT_LIST_HEAD(&list->head);
159 cds_list_for_each_entry(probe_desc, &probe_list, head) {
160 for (i = 0; i < probe_desc->nr_events; i++) {
161 struct tp_list_entry *list_entry;
162
163 list_entry = zmalloc(sizeof(*list_entry));
164 if (!list_entry)
165 goto err_nomem;
166 cds_list_add(&list_entry->head, &list->head);
167 strncpy(list_entry->tp.name,
168 probe_desc->event_desc[i]->name,
169 LTTNG_UST_SYM_NAME_LEN);
170 list_entry->tp.name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
171 if (!probe_desc->event_desc[i]->loglevel) {
172 list_entry->tp.loglevel = TRACE_DEFAULT;
173 } else {
174 list_entry->tp.loglevel = *(*probe_desc->event_desc[i]->loglevel);
175 }
176 }
177 }
178 if (cds_list_empty(&list->head))
179 list->iter = NULL;
180 else
181 list->iter =
182 cds_list_first_entry(&list->head, struct tp_list_entry, head);
183 return 0;
184
185 err_nomem:
186 ltt_probes_prune_event_list(list);
187 return -ENOMEM;
188 }
189
190 /*
191 * Return current iteration position, advance internal iterator to next.
192 * Return NULL if end of list.
193 */
194 struct lttng_ust_tracepoint_iter *
195 lttng_ust_tracepoint_list_get_iter_next(struct lttng_ust_tracepoint_list *list)
196 {
197 struct tp_list_entry *entry;
198
199 if (!list->iter)
200 return NULL;
201 entry = list->iter;
202 if (entry->head.next == &list->head)
203 list->iter = NULL;
204 else
205 list->iter = cds_list_entry(entry->head.next,
206 struct tp_list_entry, head);
207 return &entry->tp;
208 }
209
210 /* WILDCARDS */
211
212 /*
213 * Return wildcard for a given event name if the event name match the
214 * one of the wildcards.
215 * Must be called with ust lock held.
216 * Returns NULL if not present.
217 */
218 struct wildcard_entry *match_wildcard(const char *name)
219 {
220 struct wildcard_entry *e;
221
222 cds_list_for_each_entry(e, &wildcard_list, list) {
223 /* If only contain '*' */
224 if (strlen(e->name) == 1)
225 return e;
226 /* Compare excluding final '*' */
227 if (!strncmp(name, e->name, strlen(e->name) - 1))
228 return e;
229 }
230 return NULL;
231 }
232
233 /*
234 * marshall all probes/all events and create those that fit the
235 * wildcard. Add them to the events list as created.
236 */
237 static
238 void _probes_create_wildcard_events(struct wildcard_entry *entry,
239 struct session_wildcard *wildcard)
240 {
241 struct lttng_probe_desc *probe_desc;
242 struct lttng_ust_event event_param;
243 int i;
244
245 cds_list_for_each_entry(probe_desc, &probe_list, head) {
246 for (i = 0; i < probe_desc->nr_events; i++) {
247 const struct lttng_event_desc *event_desc;
248 int match = 0;
249
250 event_desc = probe_desc->event_desc[i];
251 /* compare excluding final '*' */
252 assert(strlen(entry->name) > 0);
253 if (strcmp(event_desc->name, "lttng_ust:metadata")
254 && (strlen(entry->name) == 1
255 || !strncmp(event_desc->name, entry->name,
256 strlen(entry->name) - 1))) {
257 /* TODO: check if loglevel match */
258 //if (event_desc->loglevel
259 // && (*event_desc->loglevel) ...)
260 match = 1;
261 }
262 if (match) {
263 struct ltt_event *ev;
264 int ret;
265
266 memcpy(&event_param, &wildcard->event_param,
267 sizeof(event_param));
268 memcpy(event_param.name,
269 event_desc->name,
270 sizeof(event_param.name));
271 /* create event */
272 ret = ltt_event_create(wildcard->chan,
273 &event_param, NULL,
274 &ev);
275 if (ret) {
276 DBG("Error creating event");
277 continue;
278 }
279 cds_list_add(&ev->wildcard_list,
280 &wildcard->events);
281 }
282 }
283 }
284 }
285
286 /*
287 * Add the wildcard to the wildcard list. Must be called with
288 * ust lock held.
289 */
290 struct session_wildcard *add_wildcard(const char *name,
291 struct ltt_channel *chan,
292 struct lttng_ust_event *event_param)
293 {
294 struct wildcard_entry *e;
295 struct session_wildcard *sw;
296 size_t name_len = strlen(name) + 1;
297 int found = 0;
298
299 /* try to find global wildcard entry */
300 cds_list_for_each_entry(e, &wildcard_list, list) {
301 if (!strncmp(name, e->name, LTTNG_UST_SYM_NAME_LEN - 1)) {
302 found = 1;
303 break;
304 }
305 }
306
307 if (!found) {
308 /*
309 * Create global wildcard entry if not found. Using
310 * zmalloc here to allocate a variable length element.
311 * Could cause some memory fragmentation if overused.
312 */
313 e = zmalloc(sizeof(struct wildcard_entry) + name_len);
314 if (!e)
315 return ERR_PTR(-ENOMEM);
316 memcpy(&e->name[0], name, name_len);
317 cds_list_add(&e->list, &wildcard_list);
318 CDS_INIT_LIST_HEAD(&e->session_list);
319 }
320
321 /* session wildcard */
322 cds_list_for_each_entry(sw, &e->session_list, session_list) {
323 if (chan == sw->chan) {
324 DBG("wildcard %s busy for this channel", name);
325 return ERR_PTR(-EEXIST); /* Already there */
326 }
327 }
328 sw = zmalloc(sizeof(struct session_wildcard));
329 if (!sw)
330 return ERR_PTR(-ENOMEM);
331 sw->chan = chan;
332 sw->enabled = 1;
333 memcpy(&sw->event_param, event_param, sizeof(sw->event_param));
334 sw->event_param.instrumentation = LTTNG_UST_TRACEPOINT;
335 CDS_INIT_LIST_HEAD(&sw->events);
336 cds_list_add(&sw->list, &chan->session->wildcards);
337 cds_list_add(&sw->session_list, &e->session_list);
338 sw->entry = e;
339 _probes_create_wildcard_events(e, sw);
340 return sw;
341 }
342
343 /*
344 * Remove the wildcard from the wildcard list. Must be called with
345 * ust_lock held. Only called at session teardown.
346 */
347 void _remove_wildcard(struct session_wildcard *wildcard)
348 {
349 struct ltt_event *ev, *tmp;
350
351 /*
352 * Just remove the events owned (for enable/disable) by this
353 * wildcard from the list. The session teardown will take care
354 * of freeing the event memory.
355 */
356 cds_list_for_each_entry_safe(ev, tmp, &wildcard->events,
357 wildcard_list) {
358 cds_list_del(&ev->wildcard_list);
359 }
360 cds_list_del(&wildcard->session_list);
361 cds_list_del(&wildcard->list);
362 if (cds_list_empty(&wildcard->entry->session_list)) {
363 cds_list_del(&wildcard->entry->list);
364 free(wildcard->entry);
365 }
366 free(wildcard);
367 }
368
369 int ltt_wildcard_enable(struct session_wildcard *wildcard)
370 {
371 struct ltt_event *ev;
372 int ret;
373
374 if (wildcard->enabled)
375 return -EEXIST;
376 cds_list_for_each_entry(ev, &wildcard->events, wildcard_list) {
377 ret = ltt_event_enable(ev);
378 if (ret) {
379 DBG("Error: enable error.\n");
380 return ret;
381 }
382 }
383 wildcard->enabled = 1;
384 return 0;
385 }
386
387 int ltt_wildcard_disable(struct session_wildcard *wildcard)
388 {
389 struct ltt_event *ev;
390 int ret;
391
392 if (!wildcard->enabled)
393 return -EEXIST;
394 cds_list_for_each_entry(ev, &wildcard->events, wildcard_list) {
395 ret = ltt_event_disable(ev);
396 if (ret) {
397 DBG("Error: disable error.\n");
398 return ret;
399 }
400 }
401 wildcard->enabled = 0;
402 return 0;
403 }
This page took 0.038133 seconds and 5 git commands to generate.