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