Fix uninitialized match variable
[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 "ltt-tracer-core.h"
21 #include "jhash.h"
22 #include "error.h"
23
24 /*
25 * probe list is protected by ust_lock()/ust_unlock().
26 */
27 static CDS_LIST_HEAD(probe_list);
28
29 /*
30 * Loglevel hash table, containing the active loglevels.
31 * Protected by ust lock.
32 */
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];
36
37 static
38 const struct lttng_probe_desc *find_provider(const char *provider)
39 {
40 struct lttng_probe_desc *iter;
41
42 cds_list_for_each_entry(iter, &probe_list, head) {
43 if (!strcmp(iter->provider, provider))
44 return iter;
45 }
46 return NULL;
47 }
48
49 static
50 const struct lttng_event_desc *find_event(const char *name)
51 {
52 struct lttng_probe_desc *probe_desc;
53 int i;
54
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];
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
102 /*
103 * fix the events awaiting probe load.
104 */
105 for (i = 0; i < desc->nr_events; i++) {
106 ret = pending_probe_fix_events(desc->event_desc[i]);
107 assert(!ret);
108 }
109 end:
110 ust_unlock();
111 return ret;
112 }
113
114 void ltt_probe_unregister(struct lttng_probe_desc *desc)
115 {
116 ust_lock();
117 cds_list_del(&desc->head);
118 ust_unlock();
119 }
120
121 /*
122 * called with UST lock held.
123 */
124 const struct lttng_event_desc *ltt_event_get(const char *name)
125 {
126 const struct lttng_event_desc *event;
127
128 event = find_event(name);
129 if (!event)
130 return NULL;
131 return event;
132 }
133
134 void ltt_event_put(const struct lttng_event_desc *event)
135 {
136 }
137
138 void ltt_probes_prune_event_list(struct lttng_ust_tracepoint_list *list)
139 {
140 struct tp_list_entry *list_entry, *tmp;
141
142 cds_list_for_each_entry_safe(list_entry, tmp, &list->head, head) {
143 cds_list_del(&list_entry->head);
144 free(list_entry);
145 }
146 }
147
148 /*
149 * called with UST lock held.
150 */
151 int ltt_probes_get_event_list(struct lttng_ust_tracepoint_list *list)
152 {
153 struct lttng_probe_desc *probe_desc;
154 int i;
155
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;
160
161 list_entry = zmalloc(sizeof(*list_entry));
162 if (!list_entry)
163 goto err_nomem;
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;
172 } else {
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;
179 }
180 }
181 }
182 if (cds_list_empty(&list->head))
183 list->iter = NULL;
184 else
185 list->iter =
186 cds_list_first_entry(&list->head, struct tp_list_entry, head);
187 return 0;
188
189 err_nomem:
190 ltt_probes_prune_event_list(list);
191 return -ENOMEM;
192 }
193
194 /*
195 * Return current iteration position, advance internal iterator to next.
196 * Return NULL if end of list.
197 */
198 struct lttng_ust_tracepoint_iter *
199 lttng_ust_tracepoint_list_get_iter_next(struct lttng_ust_tracepoint_list *list)
200 {
201 struct tp_list_entry *entry;
202
203 if (!list->iter)
204 return NULL;
205 entry = list->iter;
206 if (entry->head.next == &list->head)
207 list->iter = NULL;
208 else
209 list->iter = cds_list_entry(entry->head.next,
210 struct tp_list_entry, head);
211 return &entry->tp;
212 }
213
214 /*
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.
218 */
219 struct loglevel_entry *get_loglevel(const char *name)
220 {
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);
225
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))
229 return e;
230 }
231 return NULL;
232 }
233
234 struct loglevel_entry *get_loglevel_value(int64_t value)
235 {
236 char name[LTTNG_UST_SYM_NAME_LEN];
237 int ret;
238
239 ret = snprintf(name, LTTNG_UST_SYM_NAME_LEN, "%lld", (long long) value);
240 if (ret < 0)
241 return NULL;
242 return get_loglevel(name);
243 }
244
245 /*
246 * marshall all probes/all events and create those that fit the
247 * loglevel. Add them to the events list as created.
248 */
249 static
250 void _probes_create_loglevel_events(struct loglevel_entry *entry,
251 struct session_loglevel *loglevel)
252 {
253 struct lttng_probe_desc *probe_desc;
254 struct lttng_ust_event event_param;
255 int i;
256
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;
261 int match = 0;
262
263 event_desc = probe_desc->event_desc[i];
264 if (!(event_desc->loglevel))
265 continue;
266 ev_ll = *event_desc->loglevel;
267 if (isalpha(entry->name[0])) {
268 if (atoll(entry->name) == ev_ll->value) {
269 match = 1;
270 }
271 } else if (!strcmp(ev_ll->identifier, entry->name)) {
272 match = 1;
273 }
274
275 if (match) {
276 struct ltt_event *ev;
277 int ret;
278
279 memcpy(&event_param, &loglevel->event_param,
280 sizeof(event_param));
281 memcpy(event_param.name,
282 event_desc->name,
283 sizeof(event_param.name));
284 /* create event */
285 ret = ltt_event_create(loglevel->chan,
286 &event_param, NULL,
287 &ev);
288 if (ret) {
289 DBG("Error creating event");
290 continue;
291 }
292 cds_list_add(&ev->loglevel_list,
293 &loglevel->events);
294 }
295 }
296 }
297 }
298
299 /*
300 * Add the loglevel to the loglevel hash table. Must be called with
301 * ust lock held.
302 */
303 struct session_loglevel *add_loglevel(const char *name,
304 struct ltt_channel *chan,
305 struct lttng_ust_event *event_param)
306 {
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);
313 int found = 0;
314
315 /* loglevel entry */
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)) {
319 found = 1;
320 break;
321 }
322 }
323
324 if (!found) {
325 /*
326 * Using zmalloc here to allocate a variable length element. Could
327 * cause some memory fragmentation if overused.
328 */
329 e = zmalloc(sizeof(struct loglevel_entry) + name_len);
330 if (!e)
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);
335 }
336
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 */
342 }
343 }
344 sl = zmalloc(sizeof(struct session_loglevel));
345 if (!sl)
346 return ERR_PTR(-ENOMEM);
347 sl->chan = chan;
348 sl->enabled = 1;
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);
354 sl->entry = e;
355 _probes_create_loglevel_events(e, sl);
356 return sl;
357 }
358
359 /*
360 * Remove the loglevel from the loglevel hash table. Must be called with
361 * ust_lock held. Only called at session teardown.
362 */
363 void _remove_loglevel(struct session_loglevel *loglevel)
364 {
365 struct ltt_event *ev, *tmp;
366
367 /*
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.
371 */
372 cds_list_for_each_entry_safe(ev, tmp, &loglevel->events, list) {
373 cds_list_del(&ev->list);
374 }
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);
380 }
381 free(loglevel);
382 }
383
384 int ltt_loglevel_enable(struct session_loglevel *loglevel)
385 {
386 struct ltt_event *ev;
387 int ret;
388
389 if (loglevel->enabled)
390 return -EEXIST;
391 cds_list_for_each_entry(ev, &loglevel->events, list) {
392 ret = ltt_event_enable(ev);
393 if (ret) {
394 DBG("Error: enable error.\n");
395 return ret;
396 }
397 }
398 loglevel->enabled = 1;
399 return 0;
400 }
401
402 int ltt_loglevel_disable(struct session_loglevel *loglevel)
403 {
404 struct ltt_event *ev;
405 int ret;
406
407 if (!loglevel->enabled)
408 return -EEXIST;
409 cds_list_for_each_entry(ev, &loglevel->events, list) {
410 ret = ltt_event_disable(ev);
411 if (ret) {
412 DBG("Error: disable error.\n");
413 return ret;
414 }
415 }
416 loglevel->enabled = 0;
417 return 0;
418 }
This page took 0.03706 seconds and 4 git commands to generate.