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 */ | |
94 | lus = malloc(sizeof(struct ltt_ust_session)); | |
95 | if (lus == NULL) { | |
36dc12cc | 96 | PERROR("create ust session malloc"); |
97ee3a89 DG |
97 | goto error; |
98 | } | |
99 | ||
100 | /* Init data structure */ | |
3bd1e081 | 101 | lus->consumer_fds_sent = 0; |
48842b30 | 102 | lus->uid = uid; |
36dc12cc | 103 | lus->start_trace = 0; |
97ee3a89 | 104 | |
f6a9efaa DG |
105 | /* Alloc UST domain hash tables */ |
106 | lus->domain_pid = hashtable_new(0); | |
107 | lus->domain_exec = hashtable_new_str(0); | |
108 | ||
109 | /* Alloc UST global domain channels' HT */ | |
110 | lus->domain_global.channels = hashtable_new_str(0); | |
44d3bd01 | 111 | |
0177d773 | 112 | /* Set session path */ |
48842b30 | 113 | ret = snprintf(lus->pathname, PATH_MAX, "%s/ust", path); |
0177d773 | 114 | if (ret < 0) { |
44d3bd01 | 115 | PERROR("snprintf kernel traces path"); |
44844c29 | 116 | goto error_free_session; |
0177d773 DG |
117 | } |
118 | ||
44d3bd01 DG |
119 | DBG2("UST trace session create successful"); |
120 | ||
97ee3a89 DG |
121 | return lus; |
122 | ||
44844c29 MD |
123 | error_free_session: |
124 | free(lus); | |
97ee3a89 DG |
125 | error: |
126 | return NULL; | |
127 | } | |
128 | ||
129 | /* | |
130 | * Allocate and initialize a ust channel data structure. | |
131 | * | |
132 | * Return pointer to structure or NULL. | |
133 | */ | |
44d3bd01 DG |
134 | struct ltt_ust_channel *trace_ust_create_channel(struct lttng_channel *chan, |
135 | char *path) | |
97ee3a89 DG |
136 | { |
137 | int ret; | |
138 | struct ltt_ust_channel *luc; | |
139 | ||
140 | luc = malloc(sizeof(struct ltt_ust_channel)); | |
141 | if (luc == NULL) { | |
142 | perror("ltt_ust_channel malloc"); | |
143 | goto error; | |
144 | } | |
145 | ||
44d3bd01 | 146 | /* Copy UST channel attributes */ |
48842b30 DG |
147 | luc->attr.overwrite = chan->attr.overwrite; |
148 | luc->attr.subbuf_size = chan->attr.subbuf_size; | |
149 | luc->attr.num_subbuf = chan->attr.num_subbuf; | |
150 | luc->attr.switch_timer_interval = chan->attr.switch_timer_interval; | |
151 | luc->attr.read_timer_interval = chan->attr.read_timer_interval; | |
152 | luc->attr.output = chan->attr.output; | |
44d3bd01 DG |
153 | |
154 | /* Translate to UST output enum */ | |
155 | switch (luc->attr.output) { | |
156 | default: | |
157 | luc->attr.output = LTTNG_UST_MMAP; | |
158 | break; | |
97ee3a89 | 159 | } |
97ee3a89 | 160 | |
97ee3a89 | 161 | /* Copy channel name */ |
44d3bd01 | 162 | strncpy(luc->name, chan->name, sizeof(&luc->name)); |
97ee3a89 DG |
163 | luc->name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0'; |
164 | ||
f6a9efaa DG |
165 | /* Init node */ |
166 | hashtable_node_init(&luc->node, (void *) luc->name, strlen(luc->name)); | |
167 | /* Alloc hash tables */ | |
168 | luc->events = hashtable_new_str(0); | |
169 | luc->ctx = hashtable_new_str(0); | |
170 | ||
97ee3a89 | 171 | /* Set trace output path */ |
48842b30 | 172 | ret = snprintf(luc->pathname, PATH_MAX, "%s", path); |
97ee3a89 DG |
173 | if (ret < 0) { |
174 | perror("asprintf ust create channel"); | |
44844c29 | 175 | goto error_free_channel; |
97ee3a89 DG |
176 | } |
177 | ||
f6a9efaa DG |
178 | DBG2("Trace UST channel %s created", luc->name); |
179 | ||
97ee3a89 DG |
180 | return luc; |
181 | ||
44844c29 MD |
182 | error_free_channel: |
183 | free(luc); | |
97ee3a89 DG |
184 | error: |
185 | return NULL; | |
186 | } | |
187 | ||
188 | /* | |
189 | * Allocate and initialize a ust event. Set name and event type. | |
190 | * | |
191 | * Return pointer to structure or NULL. | |
192 | */ | |
193 | struct ltt_ust_event *trace_ust_create_event(struct lttng_event *ev) | |
194 | { | |
195 | struct ltt_ust_event *lue; | |
97ee3a89 DG |
196 | |
197 | lue = malloc(sizeof(struct ltt_ust_event)); | |
44d3bd01 DG |
198 | if (lue == NULL) { |
199 | PERROR("ust event malloc"); | |
97ee3a89 DG |
200 | goto error; |
201 | } | |
202 | ||
203 | switch (ev->type) { | |
204 | case LTTNG_EVENT_PROBE: | |
44d3bd01 | 205 | lue->attr.instrumentation = LTTNG_UST_PROBE; |
97ee3a89 DG |
206 | break; |
207 | case LTTNG_EVENT_FUNCTION: | |
44d3bd01 | 208 | lue->attr.instrumentation = LTTNG_UST_FUNCTION; |
97ee3a89 DG |
209 | break; |
210 | case LTTNG_EVENT_FUNCTION_ENTRY: | |
44d3bd01 | 211 | lue->attr.instrumentation = LTTNG_UST_FUNCTION; |
97ee3a89 DG |
212 | break; |
213 | case LTTNG_EVENT_TRACEPOINT: | |
44d3bd01 | 214 | lue->attr.instrumentation = LTTNG_UST_TRACEPOINT; |
97ee3a89 DG |
215 | break; |
216 | default: | |
217 | ERR("Unknown ust instrumentation type (%d)", ev->type); | |
44844c29 | 218 | goto error_free_event; |
97ee3a89 DG |
219 | } |
220 | ||
221 | /* Copy event name */ | |
44d3bd01 DG |
222 | strncpy(lue->attr.name, ev->name, LTTNG_UST_SYM_NAME_LEN); |
223 | lue->attr.name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0'; | |
97ee3a89 | 224 | |
f6a9efaa DG |
225 | /* Init node */ |
226 | hashtable_node_init(&lue->node, (void *) lue->attr.name, | |
227 | strlen(lue->attr.name)); | |
228 | /* Alloc context hash tables */ | |
e03e3332 | 229 | lue->ctx = hashtable_new_str(0); |
97ee3a89 | 230 | |
284d8f55 DG |
231 | DBG2("Trace UST event %s created", lue->attr.name); |
232 | ||
97ee3a89 DG |
233 | return lue; |
234 | ||
44844c29 MD |
235 | error_free_event: |
236 | free(lue); | |
97ee3a89 DG |
237 | error: |
238 | return NULL; | |
239 | } | |
240 | ||
241 | /* | |
242 | * Allocate and initialize a ust metadata. | |
243 | * | |
244 | * Return pointer to structure or NULL. | |
245 | */ | |
246 | struct ltt_ust_metadata *trace_ust_create_metadata(char *path) | |
247 | { | |
248 | int ret; | |
249 | struct ltt_ust_metadata *lum; | |
97ee3a89 | 250 | |
3a009adb | 251 | lum = zmalloc(sizeof(struct ltt_ust_metadata)); |
44d3bd01 | 252 | if (lum == NULL) { |
97ee3a89 DG |
253 | perror("ust metadata malloc"); |
254 | goto error; | |
255 | } | |
256 | ||
257 | /* Set default attributes */ | |
44d3bd01 DG |
258 | lum->attr.overwrite = DEFAULT_CHANNEL_OVERWRITE; |
259 | lum->attr.subbuf_size = DEFAULT_METADATA_SUBBUF_SIZE; | |
260 | lum->attr.num_subbuf = DEFAULT_METADATA_SUBBUF_NUM; | |
261 | lum->attr.switch_timer_interval = DEFAULT_CHANNEL_SWITCH_TIMER; | |
262 | lum->attr.read_timer_interval = DEFAULT_CHANNEL_READ_TIMER; | |
d41f73b7 | 263 | lum->attr.output = LTTNG_UST_MMAP; |
44d3bd01 | 264 | |
97ee3a89 DG |
265 | lum->handle = -1; |
266 | /* Set metadata trace path */ | |
f6a9efaa | 267 | ret = snprintf(lum->pathname, PATH_MAX, "%s/metadata", path); |
97ee3a89 DG |
268 | if (ret < 0) { |
269 | perror("asprintf ust metadata"); | |
44844c29 | 270 | goto error_free_metadata; |
97ee3a89 DG |
271 | } |
272 | ||
273 | return lum; | |
274 | ||
44844c29 MD |
275 | error_free_metadata: |
276 | free(lum); | |
97ee3a89 DG |
277 | error: |
278 | return NULL; | |
279 | } | |
280 | ||
f6a9efaa DG |
281 | /* |
282 | * RCU safe free context structure. | |
283 | */ | |
284 | static void destroy_context_rcu(struct rcu_head *head) | |
285 | { | |
286 | struct cds_lfht_node *node = | |
287 | caa_container_of(head, struct cds_lfht_node, head); | |
288 | struct ltt_ust_context *ctx = | |
289 | caa_container_of(node, struct ltt_ust_context, node); | |
290 | ||
291 | free(ctx); | |
292 | } | |
293 | ||
294 | /* | |
295 | * Cleanup UST context hash table. | |
296 | */ | |
297 | static void destroy_context(struct cds_lfht *ht) | |
298 | { | |
299 | int ret; | |
300 | struct cds_lfht_node *node; | |
301 | struct cds_lfht_iter iter; | |
302 | ||
ed52805d | 303 | cds_lfht_for_each(ht, &iter, node) { |
f6a9efaa DG |
304 | ret = hashtable_del(ht, &iter); |
305 | if (!ret) { | |
306 | call_rcu(&node->head, destroy_context_rcu); | |
307 | } | |
f6a9efaa | 308 | } |
ed52805d DG |
309 | |
310 | hashtable_destroy(ht); | |
f6a9efaa DG |
311 | } |
312 | ||
97ee3a89 DG |
313 | /* |
314 | * Cleanup ust event structure. | |
315 | */ | |
316 | void trace_ust_destroy_event(struct ltt_ust_event *event) | |
317 | { | |
f6a9efaa DG |
318 | DBG2("Trace destroy UST event %s", event->attr.name); |
319 | destroy_context(event->ctx); | |
ed52805d | 320 | |
97ee3a89 DG |
321 | free(event); |
322 | } | |
323 | ||
f6a9efaa DG |
324 | /* |
325 | * URCU intermediate call to complete destroy event. | |
326 | */ | |
327 | static void destroy_event_rcu(struct rcu_head *head) | |
328 | { | |
329 | struct cds_lfht_node *node = | |
330 | caa_container_of(head, struct cds_lfht_node, head); | |
331 | struct ltt_ust_event *event = | |
332 | caa_container_of(node, struct ltt_ust_event, node); | |
333 | ||
334 | trace_ust_destroy_event(event); | |
335 | } | |
336 | ||
284d8f55 DG |
337 | /* |
338 | * Cleanup UST events hashtable. | |
339 | */ | |
340 | static void destroy_event(struct cds_lfht *events) | |
ed52805d DG |
341 | { |
342 | int ret; | |
343 | struct cds_lfht_node *node; | |
344 | struct cds_lfht_iter iter; | |
345 | ||
284d8f55 DG |
346 | cds_lfht_for_each(events, &iter, node) { |
347 | ret = hashtable_del(events, &iter); | |
ed52805d DG |
348 | if (!ret) { |
349 | call_rcu(&node->head, destroy_event_rcu); | |
350 | } | |
351 | } | |
352 | ||
284d8f55 | 353 | hashtable_destroy(events); |
ed52805d DG |
354 | } |
355 | ||
97ee3a89 DG |
356 | /* |
357 | * Cleanup ust channel structure. | |
358 | */ | |
359 | void trace_ust_destroy_channel(struct ltt_ust_channel *channel) | |
360 | { | |
f6a9efaa DG |
361 | int ret; |
362 | struct cds_lfht_node *node; | |
363 | struct cds_lfht_iter iter; | |
97ee3a89 | 364 | |
f6a9efaa | 365 | DBG2("Trace destroy UST channel %s", channel->name); |
97ee3a89 | 366 | |
f6a9efaa DG |
367 | rcu_read_lock(); |
368 | ||
ed52805d | 369 | cds_lfht_for_each(channel->events, &iter, node) { |
f6a9efaa DG |
370 | ret = hashtable_del(channel->events, &iter); |
371 | if (!ret) { | |
ed52805d | 372 | destroy_event(channel->events); |
f6a9efaa | 373 | } |
97ee3a89 DG |
374 | } |
375 | ||
f6a9efaa | 376 | destroy_context(channel->ctx); |
97ee3a89 | 377 | free(channel); |
f6a9efaa DG |
378 | |
379 | rcu_read_unlock(); | |
380 | } | |
381 | ||
382 | /* | |
383 | * URCU intermediate call to complete destroy channel. | |
384 | */ | |
385 | static void destroy_channel_rcu(struct rcu_head *head) | |
386 | { | |
387 | struct cds_lfht_node *node = | |
388 | caa_container_of(head, struct cds_lfht_node, head); | |
389 | struct ltt_ust_channel *channel = | |
390 | caa_container_of(node, struct ltt_ust_channel, node); | |
391 | ||
392 | trace_ust_destroy_channel(channel); | |
97ee3a89 DG |
393 | } |
394 | ||
395 | /* | |
396 | * Cleanup ust metadata structure. | |
397 | */ | |
398 | void trace_ust_destroy_metadata(struct ltt_ust_metadata *metadata) | |
399 | { | |
f6a9efaa | 400 | DBG2("Trace UST destroy metadata %d", metadata->handle); |
97ee3a89 | 401 | |
97ee3a89 DG |
402 | free(metadata); |
403 | } | |
404 | ||
405 | /* | |
f6a9efaa | 406 | * Iterate over a hash table containing channels and cleanup safely. |
97ee3a89 | 407 | */ |
f6a9efaa DG |
408 | static void destroy_channels(struct cds_lfht *channels) |
409 | { | |
410 | int ret; | |
411 | struct cds_lfht_node *node; | |
412 | struct cds_lfht_iter iter; | |
413 | ||
ed52805d | 414 | cds_lfht_for_each(channels, &iter, node) { |
f6a9efaa DG |
415 | ret = hashtable_del(channels, &iter); |
416 | if (!ret) { | |
417 | call_rcu(&node->head, destroy_channel_rcu); | |
418 | } | |
f6a9efaa | 419 | } |
ed52805d DG |
420 | |
421 | hashtable_destroy(channels); | |
f6a9efaa DG |
422 | } |
423 | ||
424 | /* | |
425 | * Cleanup UST pid domain. | |
426 | */ | |
427 | static void destroy_domain_pid(struct cds_lfht *ht) | |
428 | { | |
429 | int ret; | |
f6a9efaa | 430 | struct cds_lfht_iter iter; |
ed52805d | 431 | struct ltt_ust_domain_pid *dpid; |
f6a9efaa | 432 | |
ed52805d | 433 | cds_lfht_for_each_entry(ht, &iter, dpid, node) { |
f6a9efaa DG |
434 | ret = hashtable_del(ht , &iter); |
435 | if (!ret) { | |
ed52805d | 436 | destroy_channels(dpid->channels); |
f6a9efaa | 437 | } |
f6a9efaa | 438 | } |
ed52805d DG |
439 | |
440 | hashtable_destroy(ht); | |
f6a9efaa DG |
441 | } |
442 | ||
443 | /* | |
444 | * Cleanup UST exec name domain. | |
445 | */ | |
446 | static void destroy_domain_exec(struct cds_lfht *ht) | |
97ee3a89 | 447 | { |
f6a9efaa | 448 | int ret; |
f6a9efaa | 449 | struct cds_lfht_iter iter; |
ed52805d | 450 | struct ltt_ust_domain_exec *dexec; |
f6a9efaa | 451 | |
ed52805d | 452 | cds_lfht_for_each_entry(ht, &iter, dexec, node) { |
f6a9efaa DG |
453 | ret = hashtable_del(ht , &iter); |
454 | if (!ret) { | |
ed52805d | 455 | destroy_channels(dexec->channels); |
f6a9efaa | 456 | } |
f6a9efaa | 457 | } |
ed52805d DG |
458 | |
459 | hashtable_destroy(ht); | |
f6a9efaa | 460 | } |
97ee3a89 | 461 | |
f6a9efaa DG |
462 | /* |
463 | * Cleanup UST global domain. | |
464 | */ | |
465 | static void destroy_domain_global(struct ltt_ust_domain_global *dom) | |
466 | { | |
467 | destroy_channels(dom->channels); | |
468 | } | |
97ee3a89 | 469 | |
f6a9efaa DG |
470 | /* |
471 | * Cleanup ust session structure | |
472 | */ | |
473 | void trace_ust_destroy_session(struct ltt_ust_session *session) | |
474 | { | |
ed52805d | 475 | /* Extra protection */ |
97ee3a89 DG |
476 | if (session == NULL) { |
477 | return; | |
478 | } | |
479 | ||
f6a9efaa DG |
480 | rcu_read_lock(); |
481 | ||
48842b30 | 482 | DBG2("Trace UST destroy session %d", session->uid); |
f6a9efaa | 483 | |
f6a9efaa DG |
484 | /* Cleaning up UST domain */ |
485 | destroy_domain_global(&session->domain_global); | |
486 | destroy_domain_pid(session->domain_pid); | |
487 | destroy_domain_exec(session->domain_exec); | |
44d3bd01 | 488 | |
97ee3a89 | 489 | free(session); |
f6a9efaa DG |
490 | |
491 | rcu_read_unlock(); | |
97ee3a89 | 492 | } |