Update loglevel ABI: only loglevel value/enum is known by UST
[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
882a56d7 20#include "tracepoint-internal.h"
8165c8da 21#include "ltt-tracer-core.h"
1f18504e
MD
22#include "jhash.h"
23#include "error.h"
8165c8da
MD
24
25/*
17dfb34b 26 * probe list is protected by ust_lock()/ust_unlock().
8165c8da 27 */
8d8a24c8 28static CDS_LIST_HEAD(probe_list);
ce5aef0b 29
e6c12e3d
MD
30/*
31 * Wildcard list, containing the active wildcards.
32 * Protected by ust lock.
33 */
34static CDS_LIST_HEAD(wildcard_list);
35
df854e41
MD
36static
37const 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
ce5aef0b
MD
48static
49const struct lttng_event_desc *find_event(const char *name)
50{
51 struct lttng_probe_desc *probe_desc;
52 int i;
53
8d8a24c8 54 cds_list_for_each_entry(probe_desc, &probe_list, head) {
ce5aef0b 55 for (i = 0; i < probe_desc->nr_events; i++) {
ff412fb5
MD
56 if (!strncmp(probe_desc->event_desc[i]->name, name,
57 LTTNG_UST_SYM_NAME_LEN - 1))
df854e41 58 return probe_desc->event_desc[i];
ce5aef0b
MD
59 }
60 }
61 return NULL;
62}
63
64int ltt_probe_register(struct lttng_probe_desc *desc)
65{
df854e41 66 struct lttng_probe_desc *iter;
ce5aef0b
MD
67 int ret = 0;
68 int i;
69
17dfb34b 70 ust_lock();
df854e41
MD
71 if (find_provider(desc->provider)) {
72 ret = -EEXIST;
73 goto end;
74 }
ce5aef0b
MD
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++) {
df854e41 80 if (find_event(desc->event_desc[i]->name)) {
ce5aef0b
MD
81 ret = -EEXIST;
82 goto end;
83 }
84 }
df854e41
MD
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 */
8d8a24c8 99 cds_list_add(&desc->head, &probe_list);
df854e41 100desc_added:
e81a53af
MD
101 DBG("just registered probe %s containing %u events",
102 desc->provider, desc->nr_events);
8165c8da
MD
103 /*
104 * fix the events awaiting probe load.
105 */
106 for (i = 0; i < desc->nr_events; i++) {
df854e41 107 ret = pending_probe_fix_events(desc->event_desc[i]);
8165c8da
MD
108 assert(!ret);
109 }
ce5aef0b 110end:
17dfb34b 111 ust_unlock();
ce5aef0b
MD
112 return ret;
113}
ce5aef0b
MD
114
115void ltt_probe_unregister(struct lttng_probe_desc *desc)
116{
17dfb34b 117 ust_lock();
8d8a24c8 118 cds_list_del(&desc->head);
e81a53af 119 DBG("just unregistered probe %s", desc->provider);
17dfb34b 120 ust_unlock();
ce5aef0b 121}
ce5aef0b 122
8165c8da
MD
123/*
124 * called with UST lock held.
125 */
ce5aef0b
MD
126const struct lttng_event_desc *ltt_event_get(const char *name)
127{
128 const struct lttng_event_desc *event;
ce5aef0b 129
ce5aef0b 130 event = find_event(name);
ce5aef0b
MD
131 if (!event)
132 return NULL;
ce5aef0b
MD
133 return event;
134}
ce5aef0b
MD
135
136void ltt_event_put(const struct lttng_event_desc *event)
137{
ce5aef0b 138}
c8fcf224
MD
139
140void 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 */
153int 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) {
882a56d7 172 list_entry->tp.loglevel = TRACE_DEFAULT;
c8fcf224 173 } else {
882a56d7 174 list_entry->tp.loglevel = *(*probe_desc->event_desc[i]->loglevel);
c8fcf224
MD
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
185err_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 */
194struct 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}
1f18504e 209
e6c12e3d
MD
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 */
218struct 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 */
237static
238void _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))) {
51c5df09
MD
257 /* TODO: check if loglevel match */
258 //if (event_desc->loglevel
882a56d7 259 // && (*event_desc->loglevel) ...)
e6c12e3d
MD
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/*
51c5df09 287 * Add the wildcard to the wildcard list. Must be called with
e6c12e3d
MD
288 * ust lock held.
289 */
290struct 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
51c5df09 299 /* try to find global wildcard entry */
e6c12e3d 300 cds_list_for_each_entry(e, &wildcard_list, list) {
ff412fb5 301 if (!strncmp(name, e->name, LTTNG_UST_SYM_NAME_LEN - 1)) {
e6c12e3d
MD
302 found = 1;
303 break;
304 }
305 }
306
307 if (!found) {
308 /*
51c5df09
MD
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.
e6c12e3d
MD
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/*
51c5df09 344 * Remove the wildcard from the wildcard list. Must be called with
e6c12e3d
MD
345 * ust_lock held. Only called at session teardown.
346 */
347void _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 */
66221151
MD
356 cds_list_for_each_entry_safe(ev, tmp, &wildcard->events,
357 wildcard_list) {
358 cds_list_del(&ev->wildcard_list);
e6c12e3d
MD
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
369int ltt_wildcard_enable(struct session_wildcard *wildcard)
370{
371 struct ltt_event *ev;
372 int ret;
373
374 if (wildcard->enabled)
375 return -EEXIST;
66221151 376 cds_list_for_each_entry(ev, &wildcard->events, wildcard_list) {
e6c12e3d
MD
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
387int ltt_wildcard_disable(struct session_wildcard *wildcard)
388{
389 struct ltt_event *ev;
390 int ret;
391
392 if (!wildcard->enabled)
393 return -EEXIST;
66221151 394 cds_list_for_each_entry(ev, &wildcard->events, wildcard_list) {
e6c12e3d
MD
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.040385 seconds and 4 git commands to generate.