loglevel enable fix: enable event names, not loglevel
[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>
ce5aef0b 18
8165c8da 19#include "ltt-tracer-core.h"
1f18504e
MD
20#include "jhash.h"
21#include "error.h"
8165c8da
MD
22
23/*
17dfb34b 24 * probe list is protected by ust_lock()/ust_unlock().
8165c8da 25 */
8d8a24c8 26static CDS_LIST_HEAD(probe_list);
ce5aef0b 27
1f18504e
MD
28/*
29 * Loglevel hash table, containing the active loglevels.
30 * Protected by ust lock.
31 */
32#define LOGLEVEL_HASH_BITS 6
33#define LOGLEVEL_TABLE_SIZE (1 << LOGLEVEL_HASH_BITS)
34static struct cds_hlist_head loglevel_table[LOGLEVEL_TABLE_SIZE];
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++) {
df854e41
MD
56 if (!strcmp(probe_desc->event_desc[i]->name, name))
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:
8165c8da
MD
100
101 /*
102 * fix the events awaiting probe load.
103 */
104 for (i = 0; i < desc->nr_events; i++) {
df854e41 105 ret = pending_probe_fix_events(desc->event_desc[i]);
8165c8da
MD
106 assert(!ret);
107 }
ce5aef0b 108end:
17dfb34b 109 ust_unlock();
ce5aef0b
MD
110 return ret;
111}
ce5aef0b
MD
112
113void ltt_probe_unregister(struct lttng_probe_desc *desc)
114{
17dfb34b 115 ust_lock();
8d8a24c8 116 cds_list_del(&desc->head);
17dfb34b 117 ust_unlock();
ce5aef0b 118}
ce5aef0b 119
8165c8da
MD
120/*
121 * called with UST lock held.
122 */
ce5aef0b
MD
123const struct lttng_event_desc *ltt_event_get(const char *name)
124{
125 const struct lttng_event_desc *event;
ce5aef0b 126
ce5aef0b 127 event = find_event(name);
ce5aef0b
MD
128 if (!event)
129 return NULL;
ce5aef0b
MD
130 return event;
131}
ce5aef0b
MD
132
133void ltt_event_put(const struct lttng_event_desc *event)
134{
ce5aef0b 135}
c8fcf224
MD
136
137void ltt_probes_prune_event_list(struct lttng_ust_tracepoint_list *list)
138{
139 struct tp_list_entry *list_entry, *tmp;
140
141 cds_list_for_each_entry_safe(list_entry, tmp, &list->head, head) {
142 cds_list_del(&list_entry->head);
143 free(list_entry);
144 }
145}
146
147/*
148 * called with UST lock held.
149 */
150int ltt_probes_get_event_list(struct lttng_ust_tracepoint_list *list)
151{
152 struct lttng_probe_desc *probe_desc;
153 int i;
154
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;
159
160 list_entry = zmalloc(sizeof(*list_entry));
161 if (!list_entry)
162 goto err_nomem;
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;
171 } else {
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;
178 }
179 }
180 }
181 if (cds_list_empty(&list->head))
182 list->iter = NULL;
183 else
184 list->iter =
185 cds_list_first_entry(&list->head, struct tp_list_entry, head);
186 return 0;
187
188err_nomem:
189 ltt_probes_prune_event_list(list);
190 return -ENOMEM;
191}
192
193/*
194 * Return current iteration position, advance internal iterator to next.
195 * Return NULL if end of list.
196 */
197struct lttng_ust_tracepoint_iter *
198 lttng_ust_tracepoint_list_get_iter_next(struct lttng_ust_tracepoint_list *list)
199{
200 struct tp_list_entry *entry;
201
202 if (!list->iter)
203 return NULL;
204 entry = list->iter;
205 if (entry->head.next == &list->head)
206 list->iter = NULL;
207 else
208 list->iter = cds_list_entry(entry->head.next,
209 struct tp_list_entry, head);
210 return &entry->tp;
211}
1f18504e
MD
212
213/*
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.
217 */
218struct loglevel_entry *get_loglevel(const char *name)
219{
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);
224
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))
228 return e;
229 }
230 return NULL;
231}
232
233/*
234 * marshall all probes/all events and create those that fit the
235 * loglevel. Add them to the events list as created.
236 */
237static
574a6217
MD
238void _probes_create_loglevel_events(struct loglevel_entry *entry,
239 struct session_loglevel *loglevel)
1f18504e
MD
240{
241 struct lttng_probe_desc *probe_desc;
7ee3cc56 242 struct lttng_ust_event event_param;
1f18504e
MD
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 tracepoint_loglevel_entry *ev_ll;
7ee3cc56 248 const struct lttng_event_desc *event_desc;
1f18504e 249
7ee3cc56
MD
250 event_desc = probe_desc->event_desc[i];
251 if (!(event_desc->loglevel))
1f18504e 252 continue;
7ee3cc56 253 ev_ll = *event_desc->loglevel;
574a6217 254 if (!strcmp(ev_ll->identifier, entry->name)) {
1f18504e
MD
255 struct ltt_event *ev;
256 int ret;
257
7ee3cc56
MD
258 memcpy(&event_param, &loglevel->event_param,
259 sizeof(event_param));
260 memcpy(event_param.name,
261 event_desc->name,
262 sizeof(event_param.name));
1f18504e
MD
263 /* create event */
264 ret = ltt_event_create(loglevel->chan,
7ee3cc56 265 &event_param, NULL,
1f18504e 266 &ev);
7ee3cc56
MD
267 if (ret) {
268 DBG("Error creating event");
1f18504e 269 continue;
7ee3cc56 270 }
1f18504e
MD
271 cds_list_add(&ev->loglevel_list,
272 &loglevel->events);
273 }
1f18504e
MD
274 }
275 }
276}
277
278/*
279 * Add the loglevel to the loglevel hash table. Must be called with
280 * ust lock held.
281 */
574a6217 282struct session_loglevel *add_loglevel(const char *name,
1f18504e
MD
283 struct ltt_channel *chan,
284 struct lttng_ust_event *event_param)
285{
286 struct cds_hlist_head *head;
287 struct cds_hlist_node *node;
288 struct loglevel_entry *e;
574a6217 289 struct session_loglevel *sl;
1f18504e
MD
290 size_t name_len = strlen(name) + 1;
291 uint32_t hash = jhash(name, name_len-1, 0);
574a6217 292 int found = 0;
1f18504e 293
574a6217 294 /* loglevel entry */
1f18504e
MD
295 head = &loglevel_table[hash & (LOGLEVEL_TABLE_SIZE - 1)];
296 cds_hlist_for_each_entry(e, node, head, hlist) {
297 if (!strcmp(name, e->name)) {
574a6217
MD
298 found = 1;
299 break;
300 }
301 }
302
303 if (!found) {
304 /*
305 * Using zmalloc here to allocate a variable length element. Could
306 * cause some memory fragmentation if overused.
307 */
308 e = zmalloc(sizeof(struct loglevel_entry) + name_len);
309 if (!e)
310 return ERR_PTR(-ENOMEM);
311 memcpy(&e->name[0], name, name_len);
312 cds_hlist_add_head(&e->hlist, head);
d5201d38 313 CDS_INIT_LIST_HEAD(&e->session_list);
574a6217
MD
314 }
315
316 /* session loglevel */
317 cds_list_for_each_entry(sl, &e->session_list, session_list) {
318 if (chan == sl->chan) {
319 DBG("loglevel %s busy for this channel", name);
1f18504e
MD
320 return ERR_PTR(-EEXIST); /* Already there */
321 }
322 }
574a6217
MD
323 sl = zmalloc(sizeof(struct session_loglevel));
324 if (!sl)
1f18504e 325 return ERR_PTR(-ENOMEM);
574a6217
MD
326 sl->chan = chan;
327 sl->enabled = 1;
328 memcpy(&sl->event_param, event_param, sizeof(sl->event_param));
d5201d38 329 sl->event_param.instrumentation = LTTNG_UST_TRACEPOINT;
574a6217
MD
330 CDS_INIT_LIST_HEAD(&sl->events);
331 cds_list_add(&sl->list, &chan->session->loglevels);
332 cds_list_add(&sl->session_list, &e->session_list);
2981744d 333 sl->entry = e;
574a6217
MD
334 _probes_create_loglevel_events(e, sl);
335 return sl;
1f18504e
MD
336}
337
338/*
339 * Remove the loglevel from the loglevel hash table. Must be called with
340 * ust_lock held. Only called at session teardown.
341 */
574a6217 342void _remove_loglevel(struct session_loglevel *loglevel)
1f18504e
MD
343{
344 struct ltt_event *ev, *tmp;
345
346 /*
347 * Just remove the events owned (for enable/disable) by this
348 * loglevel from the list. The session teardown will take care
349 * of freeing the event memory.
350 */
351 cds_list_for_each_entry_safe(ev, tmp, &loglevel->events, list) {
352 cds_list_del(&ev->list);
353 }
574a6217 354 cds_list_del(&loglevel->session_list);
1f18504e 355 cds_list_del(&loglevel->list);
574a6217
MD
356 if (cds_list_empty(&loglevel->entry->session_list)) {
357 cds_hlist_del(&loglevel->entry->hlist);
358 free(loglevel->entry);
359 }
1f18504e
MD
360 free(loglevel);
361}
362
574a6217 363int ltt_loglevel_enable(struct session_loglevel *loglevel)
1f18504e
MD
364{
365 struct ltt_event *ev;
366 int ret;
367
368 if (loglevel->enabled)
369 return -EEXIST;
370 cds_list_for_each_entry(ev, &loglevel->events, list) {
371 ret = ltt_event_enable(ev);
372 if (ret) {
373 DBG("Error: enable error.\n");
374 return ret;
375 }
376 }
377 loglevel->enabled = 1;
378 return 0;
379}
380
574a6217 381int ltt_loglevel_disable(struct session_loglevel *loglevel)
1f18504e
MD
382{
383 struct ltt_event *ev;
384 int ret;
385
386 if (!loglevel->enabled)
387 return -EEXIST;
388 cds_list_for_each_entry(ev, &loglevel->events, list) {
389 ret = ltt_event_disable(ev);
390 if (ret) {
391 DBG("Error: disable error.\n");
392 return ret;
393 }
394 }
395 loglevel->enabled = 0;
396 return 0;
397}
This page took 0.040302 seconds and 4 git commands to generate.