Commit | Line | Data |
---|---|---|
97ee3a89 DG |
1 | /* |
2 | * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca> | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify it | |
5 | * under the terms of the GNU General Public License as published by the Free | |
6 | * Software Foundation; only version 2 of the License. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
11 | * more details. | |
12 | * | |
13 | * You should have received a copy of the GNU General Public License along with | |
14 | * this program; if not, write to the Free Software Foundation, Inc., 59 Temple | |
15 | * Place - Suite 330, Boston, MA 02111-1307, USA. | |
16 | */ | |
17 | ||
18 | #define _GNU_SOURCE | |
19 | #include <stdio.h> | |
20 | #include <stdlib.h> | |
21 | #include <string.h> | |
22 | #include <unistd.h> | |
23 | ||
24 | #include <lttngerr.h> | |
25 | #include <lttng-share.h> | |
26 | ||
f6a9efaa | 27 | #include "hashtable.h" |
97ee3a89 DG |
28 | #include "trace-ust.h" |
29 | ||
0177d773 | 30 | /* |
f6a9efaa | 31 | * Find the channel in the hashtable. |
0177d773 | 32 | */ |
f6a9efaa DG |
33 | struct ltt_ust_channel *trace_ust_find_channel_by_name(struct cds_lfht *ht, |
34 | char *name) | |
0177d773 | 35 | { |
f6a9efaa DG |
36 | struct cds_lfht_node *node; |
37 | struct cds_lfht_iter iter; | |
0177d773 | 38 | |
f6a9efaa DG |
39 | rcu_read_lock(); |
40 | node = hashtable_lookup(ht, (void *) name, strlen(name), &iter); | |
41 | if (node == NULL) { | |
42 | rcu_read_unlock(); | |
44d3bd01 DG |
43 | goto error; |
44 | } | |
f6a9efaa | 45 | rcu_read_unlock(); |
44d3bd01 | 46 | |
f6a9efaa | 47 | DBG2("Trace UST channel %s found by name", name); |
0177d773 | 48 | |
f6a9efaa | 49 | return caa_container_of(node, struct ltt_ust_channel, node); |
97ee3a89 DG |
50 | |
51 | error: | |
f6a9efaa | 52 | DBG2("Trace UST channel %s not found by name", name); |
97ee3a89 DG |
53 | return NULL; |
54 | } | |
55 | ||
56 | /* | |
f6a9efaa | 57 | * Find the event in the hashtable. |
97ee3a89 | 58 | */ |
f6a9efaa DG |
59 | struct ltt_ust_event *trace_ust_find_event_by_name(struct cds_lfht *ht, |
60 | char *name) | |
97ee3a89 | 61 | { |
f6a9efaa DG |
62 | struct cds_lfht_node *node; |
63 | struct cds_lfht_iter iter; | |
97ee3a89 | 64 | |
f6a9efaa DG |
65 | rcu_read_lock(); |
66 | node = hashtable_lookup(ht, (void *) name, strlen(name), &iter); | |
67 | if (node == NULL) { | |
68 | rcu_read_unlock(); | |
97ee3a89 DG |
69 | goto error; |
70 | } | |
f6a9efaa | 71 | rcu_read_unlock(); |
97ee3a89 | 72 | |
284d8f55 | 73 | DBG2("Trace UST event found by name %s", name); |
f6a9efaa DG |
74 | |
75 | return caa_container_of(node, struct ltt_ust_event, node); | |
97ee3a89 DG |
76 | |
77 | error: | |
284d8f55 | 78 | DBG2("Trace UST event NOT found by name %s", name); |
97ee3a89 DG |
79 | return NULL; |
80 | } | |
81 | ||
82 | /* | |
83 | * Allocate and initialize a ust session data structure. | |
84 | * | |
85 | * Return pointer to structure or NULL. | |
86 | */ | |
48842b30 | 87 | struct ltt_ust_session *trace_ust_create_session(char *path, unsigned int uid, |
44d3bd01 | 88 | struct lttng_domain *domain) |
97ee3a89 | 89 | { |
0177d773 | 90 | int ret; |
97ee3a89 DG |
91 | struct ltt_ust_session *lus; |
92 | ||
93 | /* Allocate a new ltt ust session */ | |
ba7f0ae5 | 94 | lus = zmalloc(sizeof(struct ltt_ust_session)); |
97ee3a89 | 95 | if (lus == NULL) { |
ba7f0ae5 | 96 | PERROR("create ust session zmalloc"); |
97ee3a89 DG |
97 | goto error; |
98 | } | |
99 | ||
100 | /* Init data structure */ | |
48842b30 | 101 | lus->uid = uid; |
36dc12cc | 102 | lus->start_trace = 0; |
97ee3a89 | 103 | |
f6a9efaa DG |
104 | /* Alloc UST domain hash tables */ |
105 | lus->domain_pid = hashtable_new(0); | |
106 | lus->domain_exec = hashtable_new_str(0); | |
107 | ||
108 | /* Alloc UST global domain channels' HT */ | |
109 | lus->domain_global.channels = hashtable_new_str(0); | |
44d3bd01 | 110 | |
0177d773 | 111 | /* Set session path */ |
48842b30 | 112 | ret = snprintf(lus->pathname, PATH_MAX, "%s/ust", path); |
0177d773 | 113 | if (ret < 0) { |
44d3bd01 | 114 | PERROR("snprintf kernel traces path"); |
44844c29 | 115 | goto error_free_session; |
0177d773 DG |
116 | } |
117 | ||
44d3bd01 DG |
118 | DBG2("UST trace session create successful"); |
119 | ||
97ee3a89 DG |
120 | return lus; |
121 | ||
44844c29 MD |
122 | error_free_session: |
123 | free(lus); | |
97ee3a89 DG |
124 | error: |
125 | return NULL; | |
126 | } | |
127 | ||
128 | /* | |
129 | * Allocate and initialize a ust channel data structure. | |
130 | * | |
131 | * Return pointer to structure or NULL. | |
132 | */ | |
44d3bd01 DG |
133 | struct ltt_ust_channel *trace_ust_create_channel(struct lttng_channel *chan, |
134 | char *path) | |
97ee3a89 DG |
135 | { |
136 | int ret; | |
137 | struct ltt_ust_channel *luc; | |
138 | ||
37357452 | 139 | luc = zmalloc(sizeof(struct ltt_ust_channel)); |
97ee3a89 | 140 | if (luc == NULL) { |
ba7f0ae5 | 141 | perror("ltt_ust_channel zmalloc"); |
97ee3a89 DG |
142 | goto error; |
143 | } | |
144 | ||
44d3bd01 | 145 | /* Copy UST channel attributes */ |
48842b30 DG |
146 | luc->attr.overwrite = chan->attr.overwrite; |
147 | luc->attr.subbuf_size = chan->attr.subbuf_size; | |
148 | luc->attr.num_subbuf = chan->attr.num_subbuf; | |
149 | luc->attr.switch_timer_interval = chan->attr.switch_timer_interval; | |
150 | luc->attr.read_timer_interval = chan->attr.read_timer_interval; | |
151 | luc->attr.output = chan->attr.output; | |
44d3bd01 DG |
152 | |
153 | /* Translate to UST output enum */ | |
154 | switch (luc->attr.output) { | |
155 | default: | |
156 | luc->attr.output = LTTNG_UST_MMAP; | |
157 | break; | |
97ee3a89 | 158 | } |
97ee3a89 | 159 | |
97ee3a89 | 160 | /* Copy channel name */ |
44d3bd01 | 161 | strncpy(luc->name, chan->name, sizeof(&luc->name)); |
97ee3a89 DG |
162 | luc->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0'; |
163 | ||
f6a9efaa DG |
164 | /* Init node */ |
165 | hashtable_node_init(&luc->node, (void *) luc->name, strlen(luc->name)); | |
166 | /* Alloc hash tables */ | |
167 | luc->events = hashtable_new_str(0); | |
168 | luc->ctx = hashtable_new_str(0); | |
169 | ||
97ee3a89 | 170 | /* Set trace output path */ |
48842b30 | 171 | ret = snprintf(luc->pathname, PATH_MAX, "%s", path); |
97ee3a89 DG |
172 | if (ret < 0) { |
173 | perror("asprintf ust create channel"); | |
44844c29 | 174 | goto error_free_channel; |
97ee3a89 DG |
175 | } |
176 | ||
f6a9efaa DG |
177 | DBG2("Trace UST channel %s created", luc->name); |
178 | ||
97ee3a89 DG |
179 | return luc; |
180 | ||
44844c29 MD |
181 | error_free_channel: |
182 | free(luc); | |
97ee3a89 DG |
183 | error: |
184 | return NULL; | |
185 | } | |
186 | ||
187 | /* | |
188 | * Allocate and initialize a ust event. Set name and event type. | |
189 | * | |
190 | * Return pointer to structure or NULL. | |
191 | */ | |
192 | struct ltt_ust_event *trace_ust_create_event(struct lttng_event *ev) | |
193 | { | |
194 | struct ltt_ust_event *lue; | |
97ee3a89 | 195 | |
37357452 | 196 | lue = zmalloc(sizeof(struct ltt_ust_event)); |
44d3bd01 | 197 | if (lue == NULL) { |
ba7f0ae5 | 198 | PERROR("ust event zmalloc"); |
97ee3a89 DG |
199 | goto error; |
200 | } | |
201 | ||
202 | switch (ev->type) { | |
203 | case LTTNG_EVENT_PROBE: | |
44d3bd01 | 204 | lue->attr.instrumentation = LTTNG_UST_PROBE; |
97ee3a89 DG |
205 | break; |
206 | case LTTNG_EVENT_FUNCTION: | |
44d3bd01 | 207 | lue->attr.instrumentation = LTTNG_UST_FUNCTION; |
97ee3a89 DG |
208 | break; |
209 | case LTTNG_EVENT_FUNCTION_ENTRY: | |
44d3bd01 | 210 | lue->attr.instrumentation = LTTNG_UST_FUNCTION; |
97ee3a89 DG |
211 | break; |
212 | case LTTNG_EVENT_TRACEPOINT: | |
44d3bd01 | 213 | lue->attr.instrumentation = LTTNG_UST_TRACEPOINT; |
97ee3a89 DG |
214 | break; |
215 | default: | |
216 | ERR("Unknown ust instrumentation type (%d)", ev->type); | |
44844c29 | 217 | goto error_free_event; |
97ee3a89 DG |
218 | } |
219 | ||
220 | /* Copy event name */ | |
44d3bd01 DG |
221 | strncpy(lue->attr.name, ev->name, LTTNG_UST_SYM_NAME_LEN); |
222 | lue->attr.name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0'; | |
97ee3a89 | 223 | |
f6a9efaa DG |
224 | /* Init node */ |
225 | hashtable_node_init(&lue->node, (void *) lue->attr.name, | |
226 | strlen(lue->attr.name)); | |
227 | /* Alloc context hash tables */ | |
e03e3332 | 228 | lue->ctx = hashtable_new_str(0); |
97ee3a89 | 229 | |
284d8f55 DG |
230 | DBG2("Trace UST event %s created", lue->attr.name); |
231 | ||
97ee3a89 DG |
232 | return lue; |
233 | ||
44844c29 MD |
234 | error_free_event: |
235 | free(lue); | |
97ee3a89 DG |
236 | error: |
237 | return NULL; | |
238 | } | |
239 | ||
240 | /* | |
241 | * Allocate and initialize a ust metadata. | |
242 | * | |
243 | * Return pointer to structure or NULL. | |
244 | */ | |
245 | struct ltt_ust_metadata *trace_ust_create_metadata(char *path) | |
246 | { | |
247 | int ret; | |
248 | struct ltt_ust_metadata *lum; | |
97ee3a89 | 249 | |
3a009adb | 250 | lum = zmalloc(sizeof(struct ltt_ust_metadata)); |
44d3bd01 | 251 | if (lum == NULL) { |
ba7f0ae5 | 252 | perror("ust metadata zmalloc"); |
97ee3a89 DG |
253 | goto error; |
254 | } | |
255 | ||
256 | /* Set default attributes */ | |
44d3bd01 DG |
257 | lum->attr.overwrite = DEFAULT_CHANNEL_OVERWRITE; |
258 | lum->attr.subbuf_size = DEFAULT_METADATA_SUBBUF_SIZE; | |
259 | lum->attr.num_subbuf = DEFAULT_METADATA_SUBBUF_NUM; | |
260 | lum->attr.switch_timer_interval = DEFAULT_CHANNEL_SWITCH_TIMER; | |
261 | lum->attr.read_timer_interval = DEFAULT_CHANNEL_READ_TIMER; | |
d41f73b7 | 262 | lum->attr.output = LTTNG_UST_MMAP; |
44d3bd01 | 263 | |
97ee3a89 DG |
264 | lum->handle = -1; |
265 | /* Set metadata trace path */ | |
f6a9efaa | 266 | ret = snprintf(lum->pathname, PATH_MAX, "%s/metadata", path); |
97ee3a89 DG |
267 | if (ret < 0) { |
268 | perror("asprintf ust metadata"); | |
44844c29 | 269 | goto error_free_metadata; |
97ee3a89 DG |
270 | } |
271 | ||
272 | return lum; | |
273 | ||
44844c29 MD |
274 | error_free_metadata: |
275 | free(lum); | |
97ee3a89 DG |
276 | error: |
277 | return NULL; | |
278 | } | |
279 | ||
f6a9efaa DG |
280 | /* |
281 | * RCU safe free context structure. | |
282 | */ | |
283 | static void destroy_context_rcu(struct rcu_head *head) | |
284 | { | |
285 | struct cds_lfht_node *node = | |
286 | caa_container_of(head, struct cds_lfht_node, head); | |
287 | struct ltt_ust_context *ctx = | |
288 | caa_container_of(node, struct ltt_ust_context, node); | |
289 | ||
290 | free(ctx); | |
291 | } | |
292 | ||
293 | /* | |
294 | * Cleanup UST context hash table. | |
295 | */ | |
296 | static void destroy_context(struct cds_lfht *ht) | |
297 | { | |
298 | int ret; | |
299 | struct cds_lfht_node *node; | |
300 | struct cds_lfht_iter iter; | |
301 | ||
ed52805d | 302 | cds_lfht_for_each(ht, &iter, node) { |
f6a9efaa DG |
303 | ret = hashtable_del(ht, &iter); |
304 | if (!ret) { | |
305 | call_rcu(&node->head, destroy_context_rcu); | |
306 | } | |
f6a9efaa | 307 | } |
ed52805d DG |
308 | |
309 | hashtable_destroy(ht); | |
f6a9efaa DG |
310 | } |
311 | ||
97ee3a89 DG |
312 | /* |
313 | * Cleanup ust event structure. | |
314 | */ | |
315 | void trace_ust_destroy_event(struct ltt_ust_event *event) | |
316 | { | |
f6a9efaa DG |
317 | DBG2("Trace destroy UST event %s", event->attr.name); |
318 | destroy_context(event->ctx); | |
ed52805d | 319 | |
97ee3a89 DG |
320 | free(event); |
321 | } | |
322 | ||
f6a9efaa DG |
323 | /* |
324 | * URCU intermediate call to complete destroy event. | |
325 | */ | |
326 | static void destroy_event_rcu(struct rcu_head *head) | |
327 | { | |
328 | struct cds_lfht_node *node = | |
329 | caa_container_of(head, struct cds_lfht_node, head); | |
330 | struct ltt_ust_event *event = | |
331 | caa_container_of(node, struct ltt_ust_event, node); | |
332 | ||
333 | trace_ust_destroy_event(event); | |
334 | } | |
335 | ||
284d8f55 DG |
336 | /* |
337 | * Cleanup UST events hashtable. | |
338 | */ | |
339 | static void destroy_event(struct cds_lfht *events) | |
ed52805d DG |
340 | { |
341 | int ret; | |
342 | struct cds_lfht_node *node; | |
343 | struct cds_lfht_iter iter; | |
344 | ||
284d8f55 DG |
345 | cds_lfht_for_each(events, &iter, node) { |
346 | ret = hashtable_del(events, &iter); | |
ed52805d DG |
347 | if (!ret) { |
348 | call_rcu(&node->head, destroy_event_rcu); | |
349 | } | |
350 | } | |
351 | ||
284d8f55 | 352 | hashtable_destroy(events); |
ed52805d DG |
353 | } |
354 | ||
97ee3a89 DG |
355 | /* |
356 | * Cleanup ust channel structure. | |
357 | */ | |
358 | void trace_ust_destroy_channel(struct ltt_ust_channel *channel) | |
359 | { | |
f6a9efaa DG |
360 | int ret; |
361 | struct cds_lfht_node *node; | |
362 | struct cds_lfht_iter iter; | |
97ee3a89 | 363 | |
f6a9efaa | 364 | DBG2("Trace destroy UST channel %s", channel->name); |
97ee3a89 | 365 | |
f6a9efaa DG |
366 | rcu_read_lock(); |
367 | ||
ed52805d | 368 | cds_lfht_for_each(channel->events, &iter, node) { |
f6a9efaa DG |
369 | ret = hashtable_del(channel->events, &iter); |
370 | if (!ret) { | |
ed52805d | 371 | destroy_event(channel->events); |
f6a9efaa | 372 | } |
97ee3a89 DG |
373 | } |
374 | ||
f6a9efaa | 375 | destroy_context(channel->ctx); |
97ee3a89 | 376 | free(channel); |
f6a9efaa DG |
377 | |
378 | rcu_read_unlock(); | |
379 | } | |
380 | ||
381 | /* | |
382 | * URCU intermediate call to complete destroy channel. | |
383 | */ | |
384 | static void destroy_channel_rcu(struct rcu_head *head) | |
385 | { | |
386 | struct cds_lfht_node *node = | |
387 | caa_container_of(head, struct cds_lfht_node, head); | |
388 | struct ltt_ust_channel *channel = | |
389 | caa_container_of(node, struct ltt_ust_channel, node); | |
390 | ||
391 | trace_ust_destroy_channel(channel); | |
97ee3a89 DG |
392 | } |
393 | ||
394 | /* | |
395 | * Cleanup ust metadata structure. | |
396 | */ | |
397 | void trace_ust_destroy_metadata(struct ltt_ust_metadata *metadata) | |
398 | { | |
f6a9efaa | 399 | DBG2("Trace UST destroy metadata %d", metadata->handle); |
97ee3a89 | 400 | |
97ee3a89 DG |
401 | free(metadata); |
402 | } | |
403 | ||
404 | /* | |
f6a9efaa | 405 | * Iterate over a hash table containing channels and cleanup safely. |
97ee3a89 | 406 | */ |
f6a9efaa DG |
407 | static void destroy_channels(struct cds_lfht *channels) |
408 | { | |
409 | int ret; | |
410 | struct cds_lfht_node *node; | |
411 | struct cds_lfht_iter iter; | |
412 | ||
ed52805d | 413 | cds_lfht_for_each(channels, &iter, node) { |
f6a9efaa DG |
414 | ret = hashtable_del(channels, &iter); |
415 | if (!ret) { | |
416 | call_rcu(&node->head, destroy_channel_rcu); | |
417 | } | |
f6a9efaa | 418 | } |
ed52805d DG |
419 | |
420 | hashtable_destroy(channels); | |
f6a9efaa DG |
421 | } |
422 | ||
423 | /* | |
424 | * Cleanup UST pid domain. | |
425 | */ | |
426 | static void destroy_domain_pid(struct cds_lfht *ht) | |
427 | { | |
428 | int ret; | |
f6a9efaa | 429 | struct cds_lfht_iter iter; |
ed52805d | 430 | struct ltt_ust_domain_pid *dpid; |
f6a9efaa | 431 | |
ed52805d | 432 | cds_lfht_for_each_entry(ht, &iter, dpid, node) { |
f6a9efaa DG |
433 | ret = hashtable_del(ht , &iter); |
434 | if (!ret) { | |
ed52805d | 435 | destroy_channels(dpid->channels); |
f6a9efaa | 436 | } |
f6a9efaa | 437 | } |
ed52805d DG |
438 | |
439 | hashtable_destroy(ht); | |
f6a9efaa DG |
440 | } |
441 | ||
442 | /* | |
443 | * Cleanup UST exec name domain. | |
444 | */ | |
445 | static void destroy_domain_exec(struct cds_lfht *ht) | |
97ee3a89 | 446 | { |
f6a9efaa | 447 | int ret; |
f6a9efaa | 448 | struct cds_lfht_iter iter; |
ed52805d | 449 | struct ltt_ust_domain_exec *dexec; |
f6a9efaa | 450 | |
ed52805d | 451 | cds_lfht_for_each_entry(ht, &iter, dexec, node) { |
f6a9efaa DG |
452 | ret = hashtable_del(ht , &iter); |
453 | if (!ret) { | |
ed52805d | 454 | destroy_channels(dexec->channels); |
f6a9efaa | 455 | } |
f6a9efaa | 456 | } |
ed52805d DG |
457 | |
458 | hashtable_destroy(ht); | |
f6a9efaa | 459 | } |
97ee3a89 | 460 | |
f6a9efaa DG |
461 | /* |
462 | * Cleanup UST global domain. | |
463 | */ | |
464 | static void destroy_domain_global(struct ltt_ust_domain_global *dom) | |
465 | { | |
466 | destroy_channels(dom->channels); | |
467 | } | |
97ee3a89 | 468 | |
f6a9efaa DG |
469 | /* |
470 | * Cleanup ust session structure | |
471 | */ | |
472 | void trace_ust_destroy_session(struct ltt_ust_session *session) | |
473 | { | |
ed52805d | 474 | /* Extra protection */ |
97ee3a89 DG |
475 | if (session == NULL) { |
476 | return; | |
477 | } | |
478 | ||
f6a9efaa DG |
479 | rcu_read_lock(); |
480 | ||
48842b30 | 481 | DBG2("Trace UST destroy session %d", session->uid); |
f6a9efaa | 482 | |
f6a9efaa DG |
483 | /* Cleaning up UST domain */ |
484 | destroy_domain_global(&session->domain_global); | |
485 | destroy_domain_pid(session->domain_pid); | |
486 | destroy_domain_exec(session->domain_exec); | |
44d3bd01 | 487 | |
97ee3a89 | 488 | free(session); |
f6a9efaa DG |
489 | |
490 | rcu_read_unlock(); | |
97ee3a89 | 491 | } |