Commit | Line | Data |
---|---|---|
57773204 MD |
1 | /* |
2 | * Copyright (C) 2011 - Julien Desfossez <julien.desfossez@polymtl.ca> | |
3 | * Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | |
4 | * | |
e92f3e28 MD |
5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation; version 2 of the License only. | |
57773204 MD |
8 | * |
9 | * This program is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
13 | * | |
e92f3e28 MD |
14 | * You should have received a copy of the GNU General Public License along |
15 | * with this program; if not, write to the Free Software Foundation, Inc., | |
16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
57773204 MD |
17 | */ |
18 | ||
9d335227 | 19 | #define _GNU_SOURCE |
57773204 | 20 | #include <string.h> |
4318ae1b MD |
21 | #include <lttng/ust-ctl.h> |
22 | #include <lttng/ust-abi.h> | |
c1fca457 | 23 | #include <lttng/ust-events.h> |
7a784989 | 24 | #include <sys/mman.h> |
44c72f10 MD |
25 | |
26 | #include <usterr-signal-safe.h> | |
b728d87e | 27 | #include <ust-comm.h> |
57773204 MD |
28 | |
29 | #include "../libringbuffer/backend.h" | |
30 | #include "../libringbuffer/frontend.h" | |
31 | ||
6b120308 MD |
32 | volatile enum ust_loglevel ust_loglevel; |
33 | ||
57773204 | 34 | static |
61f02aea | 35 | void init_object(struct lttng_ust_object_data *data) |
57773204 MD |
36 | { |
37 | data->handle = -1; | |
38 | data->shm_fd = -1; | |
bf5ff35e | 39 | data->shm_path = NULL; |
57773204 | 40 | data->wait_fd = -1; |
bf5ff35e | 41 | data->wait_pipe_path = NULL; |
57773204 MD |
42 | data->memory_map_size = 0; |
43 | } | |
44 | ||
2be0e72c MD |
45 | int ustctl_release_handle(int sock, int handle) |
46 | { | |
47 | struct ustcomm_ust_msg lum; | |
48 | struct ustcomm_ust_reply lur; | |
49 | int ret; | |
50 | ||
51 | if (sock >= 0) { | |
52 | memset(&lum, 0, sizeof(lum)); | |
53 | lum.handle = handle; | |
54 | lum.cmd = LTTNG_UST_RELEASE; | |
55 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); | |
56 | if (ret < 0) { | |
57 | return ret; | |
58 | } | |
59 | } | |
60 | return 0; | |
61 | } | |
12388166 MD |
62 | /* |
63 | * If sock is negative, it means we don't have to notify the other side | |
64 | * (e.g. application has already vanished). | |
65 | */ | |
d26228ae | 66 | int ustctl_release_object(int sock, struct lttng_ust_object_data *data) |
57773204 | 67 | { |
57773204 MD |
68 | int ret; |
69 | ||
9bfc503d MD |
70 | if (!data) |
71 | return -EINVAL; | |
72 | ||
d26228ae MD |
73 | if (data->shm_fd >= 0) { |
74 | ret = close(data->shm_fd); | |
75 | if (ret < 0) { | |
76 | return ret; | |
77 | } | |
78 | } | |
bf5ff35e CB |
79 | |
80 | if (data->shm_path) { | |
81 | free(data->shm_path); | |
82 | } | |
83 | ||
d26228ae MD |
84 | if (data->wait_fd >= 0) { |
85 | ret = close(data->wait_fd); | |
86 | if (ret < 0) { | |
87 | return ret; | |
88 | } | |
89 | } | |
bf5ff35e CB |
90 | |
91 | if (data->wait_pipe_path) { | |
92 | free(data->wait_pipe_path); | |
93 | } | |
94 | ||
2be0e72c | 95 | return ustctl_release_handle(sock, data->handle); |
57773204 MD |
96 | } |
97 | ||
1c5e467e MD |
98 | /* |
99 | * Send registration done packet to the application. | |
100 | */ | |
101 | int ustctl_register_done(int sock) | |
102 | { | |
103 | struct ustcomm_ust_msg lum; | |
104 | struct ustcomm_ust_reply lur; | |
105 | int ret; | |
106 | ||
107 | DBG("Sending register done command to %d", sock); | |
108 | memset(&lum, 0, sizeof(lum)); | |
109 | lum.handle = LTTNG_UST_ROOT_HANDLE; | |
110 | lum.cmd = LTTNG_UST_REGISTER_DONE; | |
111 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); | |
112 | if (ret) | |
113 | return ret; | |
114 | if (lur.ret_code != USTCOMM_OK) { | |
115 | DBG("Return code: %s", ustcomm_get_readable_code(lur.ret_code)); | |
116 | goto error; | |
117 | } | |
118 | return 0; | |
119 | ||
120 | error: | |
121 | return -1; | |
122 | } | |
123 | ||
57773204 MD |
124 | /* |
125 | * returns session handle. | |
126 | */ | |
127 | int ustctl_create_session(int sock) | |
128 | { | |
129 | struct ustcomm_ust_msg lum; | |
130 | struct ustcomm_ust_reply lur; | |
131 | int ret, session_handle; | |
132 | ||
133 | /* Create session */ | |
134 | memset(&lum, 0, sizeof(lum)); | |
135 | lum.handle = LTTNG_UST_ROOT_HANDLE; | |
136 | lum.cmd = LTTNG_UST_SESSION; | |
137 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); | |
138 | if (ret) | |
139 | return ret; | |
140 | session_handle = lur.ret_val; | |
141 | DBG("received session handle %u", session_handle); | |
142 | return session_handle; | |
143 | } | |
144 | ||
145 | /* open the metadata global channel */ | |
146 | int ustctl_open_metadata(int sock, int session_handle, | |
147 | struct lttng_ust_channel_attr *chops, | |
61f02aea | 148 | struct lttng_ust_object_data **_metadata_data) |
57773204 MD |
149 | { |
150 | struct ustcomm_ust_msg lum; | |
151 | struct ustcomm_ust_reply lur; | |
61f02aea | 152 | struct lttng_ust_object_data *metadata_data; |
eeee05f3 | 153 | int ret, err = 0; |
bf5ff35e | 154 | char *shm_path, *wait_pipe_path; |
57773204 | 155 | |
9bfc503d MD |
156 | if (!chops || !_metadata_data) |
157 | return -EINVAL; | |
158 | ||
57773204 MD |
159 | metadata_data = malloc(sizeof(*metadata_data)); |
160 | if (!metadata_data) | |
161 | return -ENOMEM; | |
162 | init_object(metadata_data); | |
163 | /* Create metadata channel */ | |
164 | memset(&lum, 0, sizeof(lum)); | |
165 | lum.handle = session_handle; | |
166 | lum.cmd = LTTNG_UST_METADATA; | |
167 | lum.u.channel.overwrite = chops->overwrite; | |
168 | lum.u.channel.subbuf_size = chops->subbuf_size; | |
169 | lum.u.channel.num_subbuf = chops->num_subbuf; | |
170 | lum.u.channel.switch_timer_interval = chops->switch_timer_interval; | |
171 | lum.u.channel.read_timer_interval = chops->read_timer_interval; | |
172 | lum.u.channel.output = chops->output; | |
173 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); | |
174 | if (ret) { | |
175 | free(metadata_data); | |
176 | return ret; | |
177 | } | |
178 | if (lur.ret_code != USTCOMM_OK) { | |
179 | free(metadata_data); | |
180 | return lur.ret_code; | |
181 | } | |
182 | metadata_data->handle = lur.ret_val; | |
183 | DBG("received metadata handle %u", metadata_data->handle); | |
184 | metadata_data->memory_map_size = lur.u.channel.memory_map_size; | |
bf5ff35e CB |
185 | /* get shm path */ |
186 | shm_path = ustcomm_recv_string(sock); | |
187 | if (!shm_path) { | |
eeee05f3 | 188 | err = 1; |
bf5ff35e CB |
189 | } else { |
190 | DBG("Received shm path: %s\n", shm_path); | |
191 | metadata_data->shm_fd = -1; | |
192 | metadata_data->shm_path = shm_path; | |
193 | } | |
194 | ||
eeee05f3 MD |
195 | /* |
196 | * We need to get the second FD even if the first fails, because | |
197 | * libust expects us to read the two FDs. | |
198 | */ | |
bf5ff35e CB |
199 | |
200 | /* get wait pipe path */ | |
201 | wait_pipe_path = ustcomm_recv_string(sock); | |
202 | if (!wait_pipe_path) { | |
203 | free(shm_path); | |
eeee05f3 | 204 | err = 1; |
bf5ff35e CB |
205 | } else { |
206 | DBG("Received wait pipe path: %s\n", wait_pipe_path); | |
207 | metadata_data->wait_fd = -1; | |
208 | metadata_data->wait_pipe_path = wait_pipe_path; | |
209 | } | |
210 | ||
211 | ||
eeee05f3 | 212 | if (err) |
57773204 | 213 | goto error; |
57773204 MD |
214 | *_metadata_data = metadata_data; |
215 | return 0; | |
216 | ||
217 | error: | |
d26228ae | 218 | (void) ustctl_release_object(sock, metadata_data); |
38970582 | 219 | free(metadata_data); |
57773204 MD |
220 | return -EINVAL; |
221 | } | |
222 | ||
223 | int ustctl_create_channel(int sock, int session_handle, | |
224 | struct lttng_ust_channel_attr *chops, | |
61f02aea | 225 | struct lttng_ust_object_data **_channel_data) |
57773204 MD |
226 | { |
227 | struct ustcomm_ust_msg lum; | |
228 | struct ustcomm_ust_reply lur; | |
61f02aea | 229 | struct lttng_ust_object_data *channel_data; |
eeee05f3 | 230 | int ret, err = 0; |
bf5ff35e | 231 | char *shm_path, *wait_pipe_path; |
57773204 | 232 | |
9bfc503d MD |
233 | if (!chops || !_channel_data) |
234 | return -EINVAL; | |
235 | ||
57773204 MD |
236 | channel_data = malloc(sizeof(*channel_data)); |
237 | if (!channel_data) | |
238 | return -ENOMEM; | |
239 | init_object(channel_data); | |
240 | /* Create metadata channel */ | |
241 | memset(&lum, 0, sizeof(lum)); | |
242 | lum.handle = session_handle; | |
243 | lum.cmd = LTTNG_UST_CHANNEL; | |
244 | lum.u.channel.overwrite = chops->overwrite; | |
245 | lum.u.channel.subbuf_size = chops->subbuf_size; | |
246 | lum.u.channel.num_subbuf = chops->num_subbuf; | |
247 | lum.u.channel.switch_timer_interval = chops->switch_timer_interval; | |
248 | lum.u.channel.read_timer_interval = chops->read_timer_interval; | |
249 | lum.u.channel.output = chops->output; | |
250 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); | |
251 | if (ret) { | |
252 | free(channel_data); | |
253 | return ret; | |
254 | } | |
255 | if (lur.ret_code != USTCOMM_OK) { | |
256 | free(channel_data); | |
257 | return lur.ret_code; | |
258 | } | |
259 | channel_data->handle = lur.ret_val; | |
260 | DBG("received channel handle %u", channel_data->handle); | |
261 | channel_data->memory_map_size = lur.u.channel.memory_map_size; | |
bf5ff35e CB |
262 | /* get shm path */ |
263 | shm_path = ustcomm_recv_string(sock); | |
264 | if (!shm_path) { | |
eeee05f3 | 265 | err = 1; |
bf5ff35e CB |
266 | } else { |
267 | DBG("Received shm path: %s\n", shm_path); | |
268 | channel_data->shm_fd = -1; | |
269 | channel_data->shm_path = shm_path; | |
270 | } | |
271 | ||
eeee05f3 MD |
272 | /* |
273 | * We need to get the second FD even if the first fails, because | |
274 | * libust expects us to read the two FDs. | |
275 | */ | |
bf5ff35e CB |
276 | /* get wait pipe path */ |
277 | wait_pipe_path = ustcomm_recv_string(sock); | |
278 | if (!wait_pipe_path) { | |
279 | free(shm_path); | |
eeee05f3 | 280 | err = 1; |
bf5ff35e CB |
281 | } else { |
282 | DBG("Received wait pipe path: %s\n", wait_pipe_path); | |
283 | channel_data->wait_fd = -1; | |
284 | channel_data->wait_pipe_path = wait_pipe_path; | |
285 | } | |
286 | ||
eeee05f3 | 287 | if (err) |
57773204 | 288 | goto error; |
57773204 MD |
289 | *_channel_data = channel_data; |
290 | return 0; | |
291 | ||
292 | error: | |
d26228ae | 293 | (void) ustctl_release_object(sock, channel_data); |
38970582 | 294 | free(channel_data); |
57773204 MD |
295 | return -EINVAL; |
296 | } | |
297 | ||
298 | /* | |
299 | * Return -ENOENT if no more stream is available for creation. | |
300 | * Return 0 on success. | |
301 | * Return negative error value on error. | |
302 | */ | |
61f02aea MD |
303 | int ustctl_create_stream(int sock, struct lttng_ust_object_data *channel_data, |
304 | struct lttng_ust_object_data **_stream_data) | |
57773204 MD |
305 | { |
306 | struct ustcomm_ust_msg lum; | |
307 | struct ustcomm_ust_reply lur; | |
61f02aea | 308 | struct lttng_ust_object_data *stream_data; |
bf5ff35e CB |
309 | int ret, err = 0; |
310 | char *shm_path, *wait_pipe_path; | |
57773204 | 311 | |
9bfc503d MD |
312 | if (!channel_data || !_stream_data) |
313 | return -EINVAL; | |
314 | ||
57773204 MD |
315 | stream_data = malloc(sizeof(*stream_data)); |
316 | if (!stream_data) | |
317 | return -ENOMEM; | |
318 | init_object(stream_data); | |
319 | memset(&lum, 0, sizeof(lum)); | |
320 | lum.handle = channel_data->handle; | |
321 | lum.cmd = LTTNG_UST_STREAM; | |
322 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); | |
323 | if (ret) { | |
324 | free(stream_data); | |
325 | return ret; | |
326 | } | |
327 | if (lur.ret_code != USTCOMM_OK) { | |
328 | free(stream_data); | |
329 | return lur.ret_code; | |
330 | } | |
331 | ||
332 | stream_data->handle = lur.ret_val; | |
333 | DBG("received stream handle %u", stream_data->handle); | |
334 | stream_data->memory_map_size = lur.u.stream.memory_map_size; | |
bf5ff35e CB |
335 | /* get shm path */ |
336 | shm_path = ustcomm_recv_string(sock); | |
337 | if (!shm_path) { | |
eeee05f3 | 338 | err = 1; |
bf5ff35e CB |
339 | } else { |
340 | DBG("Received shm path: %s\n", shm_path); | |
341 | stream_data->shm_fd = -1; | |
342 | stream_data->shm_path = shm_path; | |
343 | } | |
344 | ||
eeee05f3 MD |
345 | /* |
346 | * We need to get the second FD even if the first fails, because | |
347 | * libust expects us to read the two FDs. | |
348 | */ | |
bf5ff35e CB |
349 | /* get wait pipe path */ |
350 | wait_pipe_path = ustcomm_recv_string(sock); | |
351 | if (!wait_pipe_path) { | |
352 | free(shm_path); | |
eeee05f3 | 353 | err = 1; |
bf5ff35e CB |
354 | } else { |
355 | DBG("Received wait pipe path: %s\n", wait_pipe_path); | |
356 | stream_data->wait_fd = -1; | |
357 | stream_data->wait_pipe_path = wait_pipe_path; | |
358 | } | |
359 | ||
eeee05f3 | 360 | if (err) |
57773204 | 361 | goto error; |
57773204 MD |
362 | *_stream_data = stream_data; |
363 | return ret; | |
364 | ||
365 | error: | |
d26228ae | 366 | (void) ustctl_release_object(sock, stream_data); |
38970582 | 367 | free(stream_data); |
57773204 MD |
368 | return -EINVAL; |
369 | } | |
370 | ||
371 | int ustctl_create_event(int sock, struct lttng_ust_event *ev, | |
61f02aea MD |
372 | struct lttng_ust_object_data *channel_data, |
373 | struct lttng_ust_object_data **_event_data) | |
57773204 MD |
374 | { |
375 | struct ustcomm_ust_msg lum; | |
376 | struct ustcomm_ust_reply lur; | |
61f02aea | 377 | struct lttng_ust_object_data *event_data; |
57773204 MD |
378 | int ret; |
379 | ||
9bfc503d MD |
380 | if (!channel_data || !_event_data) |
381 | return -EINVAL; | |
382 | ||
57773204 MD |
383 | event_data = malloc(sizeof(*event_data)); |
384 | if (!event_data) | |
385 | return -ENOMEM; | |
386 | init_object(event_data); | |
387 | memset(&lum, 0, sizeof(lum)); | |
388 | lum.handle = channel_data->handle; | |
389 | lum.cmd = LTTNG_UST_EVENT; | |
390 | strncpy(lum.u.event.name, ev->name, | |
391 | LTTNG_UST_SYM_NAME_LEN); | |
392 | lum.u.event.instrumentation = ev->instrumentation; | |
457a6b58 MD |
393 | lum.u.event.loglevel_type = ev->loglevel_type; |
394 | lum.u.event.loglevel = ev->loglevel; | |
57773204 MD |
395 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); |
396 | if (ret) { | |
397 | free(event_data); | |
398 | return ret; | |
399 | } | |
400 | event_data->handle = lur.ret_val; | |
401 | DBG("received event handle %u", event_data->handle); | |
402 | *_event_data = event_data; | |
403 | return 0; | |
404 | } | |
405 | ||
406 | int ustctl_add_context(int sock, struct lttng_ust_context *ctx, | |
61f02aea MD |
407 | struct lttng_ust_object_data *obj_data, |
408 | struct lttng_ust_object_data **_context_data) | |
57773204 MD |
409 | { |
410 | struct ustcomm_ust_msg lum; | |
411 | struct ustcomm_ust_reply lur; | |
61f02aea | 412 | struct lttng_ust_object_data *context_data; |
57773204 MD |
413 | int ret; |
414 | ||
9bfc503d MD |
415 | if (!obj_data || !_context_data) |
416 | return -EINVAL; | |
417 | ||
57773204 MD |
418 | context_data = malloc(sizeof(*context_data)); |
419 | if (!context_data) | |
420 | return -ENOMEM; | |
421 | init_object(context_data); | |
422 | memset(&lum, 0, sizeof(lum)); | |
3039d8ed | 423 | lum.handle = obj_data->handle; |
57773204 MD |
424 | lum.cmd = LTTNG_UST_CONTEXT; |
425 | lum.u.context.ctx = ctx->ctx; | |
426 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); | |
427 | if (ret) { | |
428 | free(context_data); | |
429 | return ret; | |
430 | } | |
431 | context_data->handle = lur.ret_val; | |
432 | DBG("received context handle %u", context_data->handle); | |
433 | *_context_data = context_data; | |
434 | return ret; | |
435 | } | |
436 | ||
437 | /* Enable event, channel and session ioctl */ | |
61f02aea | 438 | int ustctl_enable(int sock, struct lttng_ust_object_data *object) |
57773204 MD |
439 | { |
440 | struct ustcomm_ust_msg lum; | |
441 | struct ustcomm_ust_reply lur; | |
442 | int ret; | |
443 | ||
9bfc503d MD |
444 | if (!object) |
445 | return -EINVAL; | |
446 | ||
57773204 MD |
447 | memset(&lum, 0, sizeof(lum)); |
448 | lum.handle = object->handle; | |
449 | lum.cmd = LTTNG_UST_ENABLE; | |
450 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); | |
451 | if (ret) | |
452 | return ret; | |
453 | DBG("enabled handle %u", object->handle); | |
454 | return 0; | |
455 | } | |
456 | ||
457 | /* Disable event, channel and session ioctl */ | |
61f02aea | 458 | int ustctl_disable(int sock, struct lttng_ust_object_data *object) |
57773204 MD |
459 | { |
460 | struct ustcomm_ust_msg lum; | |
461 | struct ustcomm_ust_reply lur; | |
462 | int ret; | |
463 | ||
9bfc503d MD |
464 | if (!object) |
465 | return -EINVAL; | |
466 | ||
57773204 MD |
467 | memset(&lum, 0, sizeof(lum)); |
468 | lum.handle = object->handle; | |
469 | lum.cmd = LTTNG_UST_DISABLE; | |
470 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); | |
471 | if (ret) | |
472 | return ret; | |
473 | DBG("disable handle %u", object->handle); | |
474 | return 0; | |
475 | } | |
476 | ||
4a6ca058 | 477 | int ustctl_start_session(int sock, int handle) |
57773204 | 478 | { |
61f02aea | 479 | struct lttng_ust_object_data obj; |
4a6ca058 MD |
480 | |
481 | obj.handle = handle; | |
482 | return ustctl_enable(sock, &obj); | |
57773204 MD |
483 | } |
484 | ||
4a6ca058 | 485 | int ustctl_stop_session(int sock, int handle) |
57773204 | 486 | { |
61f02aea | 487 | struct lttng_ust_object_data obj; |
4a6ca058 MD |
488 | |
489 | obj.handle = handle; | |
490 | return ustctl_disable(sock, &obj); | |
57773204 MD |
491 | } |
492 | ||
57773204 MD |
493 | int ustctl_tracepoint_list(int sock) |
494 | { | |
b115631f MD |
495 | struct ustcomm_ust_msg lum; |
496 | struct ustcomm_ust_reply lur; | |
497 | int ret, tp_list_handle; | |
498 | ||
499 | memset(&lum, 0, sizeof(lum)); | |
500 | lum.handle = LTTNG_UST_ROOT_HANDLE; | |
501 | lum.cmd = LTTNG_UST_TRACEPOINT_LIST; | |
502 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); | |
503 | if (ret) | |
504 | return ret; | |
505 | tp_list_handle = lur.ret_val; | |
506 | DBG("received tracepoint list handle %u", tp_list_handle); | |
507 | return tp_list_handle; | |
508 | } | |
509 | ||
510 | int ustctl_tracepoint_list_get(int sock, int tp_list_handle, | |
cbef6901 | 511 | struct lttng_ust_tracepoint_iter *iter) |
b115631f MD |
512 | { |
513 | struct ustcomm_ust_msg lum; | |
514 | struct ustcomm_ust_reply lur; | |
515 | int ret; | |
516 | ||
9bfc503d MD |
517 | if (!iter) |
518 | return -EINVAL; | |
519 | ||
b115631f MD |
520 | memset(&lum, 0, sizeof(lum)); |
521 | lum.handle = tp_list_handle; | |
522 | lum.cmd = LTTNG_UST_TRACEPOINT_LIST_GET; | |
523 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); | |
524 | if (ret) | |
525 | return ret; | |
882a56d7 | 526 | DBG("received tracepoint list entry name %s loglevel %d", |
cbef6901 | 527 | lur.u.tracepoint.name, |
882a56d7 | 528 | lur.u.tracepoint.loglevel); |
cbef6901 | 529 | memcpy(iter, &lur.u.tracepoint, sizeof(*iter)); |
b115631f | 530 | return 0; |
57773204 MD |
531 | } |
532 | ||
533 | int ustctl_tracer_version(int sock, struct lttng_ust_tracer_version *v) | |
534 | { | |
535 | struct ustcomm_ust_msg lum; | |
536 | struct ustcomm_ust_reply lur; | |
537 | int ret; | |
538 | ||
9bfc503d MD |
539 | if (!v) |
540 | return -EINVAL; | |
541 | ||
57773204 MD |
542 | memset(&lum, 0, sizeof(lum)); |
543 | lum.handle = LTTNG_UST_ROOT_HANDLE; | |
544 | lum.cmd = LTTNG_UST_TRACER_VERSION; | |
545 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); | |
546 | if (ret) | |
547 | return ret; | |
548 | memcpy(v, &lur.u.version, sizeof(*v)); | |
549 | DBG("received tracer version"); | |
550 | return 0; | |
551 | } | |
552 | ||
553 | int ustctl_wait_quiescent(int sock) | |
554 | { | |
555 | struct ustcomm_ust_msg lum; | |
556 | struct ustcomm_ust_reply lur; | |
557 | int ret; | |
558 | ||
559 | memset(&lum, 0, sizeof(lum)); | |
560 | lum.handle = LTTNG_UST_ROOT_HANDLE; | |
561 | lum.cmd = LTTNG_UST_WAIT_QUIESCENT; | |
562 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); | |
563 | if (ret) | |
564 | return ret; | |
565 | DBG("waited for quiescent state"); | |
566 | return 0; | |
567 | } | |
568 | ||
569 | int ustctl_calibrate(int sock, struct lttng_ust_calibrate *calibrate) | |
570 | { | |
9bfc503d MD |
571 | if (!calibrate) |
572 | return -EINVAL; | |
573 | ||
57773204 MD |
574 | return -ENOSYS; |
575 | } | |
576 | ||
f1fffc57 MD |
577 | int ustctl_sock_flush_buffer(int sock, struct lttng_ust_object_data *object) |
578 | { | |
579 | struct ustcomm_ust_msg lum; | |
580 | struct ustcomm_ust_reply lur; | |
581 | int ret; | |
582 | ||
9bfc503d MD |
583 | if (!object) |
584 | return -EINVAL; | |
585 | ||
f1fffc57 MD |
586 | memset(&lum, 0, sizeof(lum)); |
587 | lum.handle = object->handle; | |
588 | lum.cmd = LTTNG_UST_FLUSH_BUFFER; | |
589 | ret = ustcomm_send_app_cmd(sock, &lum, &lur); | |
590 | if (ret) | |
591 | return ret; | |
592 | DBG("flushed buffer handle %u", object->handle); | |
593 | return 0; | |
594 | } | |
595 | ||
57773204 MD |
596 | /* Buffer operations */ |
597 | ||
598 | /* Map channel shm into process memory */ | |
38fae1d3 | 599 | struct lttng_ust_shm_handle *ustctl_map_channel(struct lttng_ust_object_data *chan_data) |
57773204 | 600 | { |
38fae1d3 | 601 | struct lttng_ust_shm_handle *handle; |
57773204 MD |
602 | struct channel *chan; |
603 | size_t chan_size; | |
c1fca457 | 604 | struct lttng_ust_lib_ring_buffer_config *config; |
7a784989 | 605 | int ret; |
57773204 | 606 | |
9bfc503d MD |
607 | if (!chan_data) |
608 | return NULL; | |
609 | ||
57773204 MD |
610 | handle = channel_handle_create(chan_data->shm_fd, |
611 | chan_data->wait_fd, | |
612 | chan_data->memory_map_size); | |
613 | if (!handle) { | |
614 | ERR("create handle error"); | |
615 | return NULL; | |
616 | } | |
617 | /* | |
0bfe09ec MD |
618 | * Set to -1, and then close the shm fd, and set the handle shm |
619 | * fd to -1 too. We don't need the shm fds after they have been | |
620 | * mapped. | |
621 | * The wait_fd is set to -1 in chan_data because it is now owned | |
622 | * by the handle. | |
57773204 MD |
623 | */ |
624 | chan_data->shm_fd = -1; | |
625 | chan_data->wait_fd = -1; | |
626 | ||
0bfe09ec MD |
627 | /* chan is object 0. This is hardcoded. */ |
628 | if (handle->table->objects[0].shm_fd >= 0) { | |
629 | ret = close(handle->table->objects[0].shm_fd); | |
630 | if (ret) { | |
631 | perror("Error closing shm_fd"); | |
632 | } | |
633 | handle->table->objects[0].shm_fd = -1; | |
634 | } | |
635 | ||
57773204 MD |
636 | /* |
637 | * TODO: add consistency checks to be resilient if the | |
638 | * application try to feed us with incoherent channel structure | |
639 | * values. | |
640 | */ | |
641 | chan = shmp(handle, handle->chan); | |
642 | /* chan is object 0. This is hardcoded. */ | |
643 | chan_size = handle->table->objects[0].allocated_len; | |
644 | handle->shadow_chan = malloc(chan_size); | |
645 | if (!handle->shadow_chan) { | |
646 | channel_destroy(chan, handle, 1); | |
647 | return NULL; | |
648 | } | |
649 | memcpy(handle->shadow_chan, chan, chan_size); | |
bbc70d1b MD |
650 | /* |
651 | * The callback pointers in the producer are invalid in the | |
c1fca457 | 652 | * consumer. We need to look them up here. |
bbc70d1b | 653 | */ |
c1fca457 MD |
654 | config = &handle->shadow_chan->backend.config; |
655 | switch (config->client_type) { | |
656 | case LTTNG_CLIENT_METADATA: | |
657 | memcpy(&config->cb, lttng_client_callbacks_metadata, | |
658 | sizeof(config->cb)); | |
659 | break; | |
660 | case LTTNG_CLIENT_DISCARD: | |
661 | memcpy(&config->cb, lttng_client_callbacks_discard, | |
662 | sizeof(config->cb)); | |
663 | break; | |
664 | case LTTNG_CLIENT_OVERWRITE: | |
665 | memcpy(&config->cb, lttng_client_callbacks_overwrite, | |
666 | sizeof(config->cb)); | |
667 | break; | |
668 | default: | |
669 | ERR("Unknown client type %d", config->client_type); | |
670 | channel_destroy(chan, handle, 1); | |
671 | return NULL; | |
672 | } | |
7a784989 MD |
673 | /* Replace the object table pointer. */ |
674 | ret = munmap(handle->table->objects[0].memory_map, | |
675 | handle->table->objects[0].memory_map_size); | |
676 | if (ret) { | |
677 | perror("munmap"); | |
678 | assert(0); | |
679 | } | |
680 | handle->table->objects[0].memory_map = (char *) handle->shadow_chan; | |
681 | handle->table->objects[0].is_shadow = 1; | |
57773204 MD |
682 | return handle; |
683 | } | |
684 | ||
685 | /* Add stream to channel shm and map its shm into process memory */ | |
38fae1d3 | 686 | int ustctl_add_stream(struct lttng_ust_shm_handle *handle, |
61f02aea | 687 | struct lttng_ust_object_data *stream_data) |
57773204 MD |
688 | { |
689 | int ret; | |
690 | ||
9bfc503d MD |
691 | if (!handle || !stream_data) |
692 | return -EINVAL; | |
693 | ||
57773204 MD |
694 | if (!stream_data->handle) |
695 | return -ENOENT; | |
696 | /* map stream */ | |
697 | ret = channel_handle_add_stream(handle, | |
698 | stream_data->shm_fd, | |
699 | stream_data->wait_fd, | |
700 | stream_data->memory_map_size); | |
701 | if (ret) { | |
702 | ERR("add stream error\n"); | |
703 | return ret; | |
704 | } | |
705 | /* | |
38fae1d3 | 706 | * Set to -1 because the lttng_ust_shm_handle destruction will take care |
57773204 MD |
707 | * of closing shm_fd and wait_fd. |
708 | */ | |
709 | stream_data->shm_fd = -1; | |
710 | stream_data->wait_fd = -1; | |
711 | return 0; | |
712 | } | |
713 | ||
38fae1d3 | 714 | void ustctl_unmap_channel(struct lttng_ust_shm_handle *handle) |
5224b5c8 MD |
715 | { |
716 | struct channel *chan; | |
717 | ||
9bfc503d | 718 | assert(handle); |
5224b5c8 MD |
719 | chan = shmp(handle, handle->chan); |
720 | channel_destroy(chan, handle, 1); | |
721 | } | |
722 | ||
0bfe09ec MD |
723 | /* |
724 | * ustctl closes the shm_fd fds after mapping it. | |
725 | */ | |
4cfec15c | 726 | struct lttng_ust_lib_ring_buffer *ustctl_open_stream_read(struct lttng_ust_shm_handle *handle, |
6e922b24 MD |
727 | int cpu) |
728 | { | |
36860b65 | 729 | struct channel *chan; |
ef9ff354 | 730 | int *shm_fd, *wait_fd; |
bf5ff35e | 731 | char *shm_path, *wait_pipe_path; |
ef9ff354 | 732 | uint64_t *memory_map_size; |
4cfec15c | 733 | struct lttng_ust_lib_ring_buffer *buf; |
6e922b24 MD |
734 | int ret; |
735 | ||
9bfc503d MD |
736 | if (!handle) |
737 | return NULL; | |
738 | ||
36860b65 | 739 | chan = handle->shadow_chan; |
6e922b24 | 740 | buf = channel_get_ring_buffer(&chan->backend.config, |
bf5ff35e CB |
741 | chan, cpu, handle, |
742 | &shm_fd, &shm_path, | |
743 | &wait_fd, &wait_pipe_path, | |
744 | &memory_map_size); | |
6e922b24 MD |
745 | if (!buf) |
746 | return NULL; | |
747 | ret = lib_ring_buffer_open_read(buf, handle, 1); | |
748 | if (ret) | |
749 | return NULL; | |
0bfe09ec MD |
750 | /* |
751 | * We can close shm_fd early, right after is has been mapped. | |
752 | */ | |
753 | if (*shm_fd >= 0) { | |
754 | ret = close(*shm_fd); | |
755 | if (ret) { | |
756 | perror("Error closing shm_fd"); | |
757 | } | |
758 | *shm_fd = -1; | |
759 | } | |
6e922b24 MD |
760 | return buf; |
761 | } | |
762 | ||
38fae1d3 | 763 | void ustctl_close_stream_read(struct lttng_ust_shm_handle *handle, |
4cfec15c | 764 | struct lttng_ust_lib_ring_buffer *buf) |
6e922b24 | 765 | { |
9bfc503d | 766 | assert(handle && buf); |
6e922b24 MD |
767 | lib_ring_buffer_release_read(buf, handle, 1); |
768 | } | |
769 | ||
57773204 MD |
770 | /* For mmap mode, readable without "get" operation */ |
771 | ||
38fae1d3 | 772 | void *ustctl_get_mmap_base(struct lttng_ust_shm_handle *handle, |
4cfec15c | 773 | struct lttng_ust_lib_ring_buffer *buf) |
9095efe9 | 774 | { |
9bfc503d MD |
775 | if (!handle || !buf) |
776 | return NULL; | |
9095efe9 MD |
777 | return shmp(handle, buf->backend.memory_map); |
778 | } | |
779 | ||
57773204 | 780 | /* returns the length to mmap. */ |
38fae1d3 | 781 | int ustctl_get_mmap_len(struct lttng_ust_shm_handle *handle, |
4cfec15c | 782 | struct lttng_ust_lib_ring_buffer *buf, |
57773204 MD |
783 | unsigned long *len) |
784 | { | |
785 | unsigned long mmap_buf_len; | |
36860b65 | 786 | struct channel *chan; |
57773204 | 787 | |
9bfc503d MD |
788 | if (!handle || !buf || !len) |
789 | return -EINVAL; | |
790 | ||
36860b65 | 791 | chan = handle->shadow_chan; |
57773204 MD |
792 | if (chan->backend.config.output != RING_BUFFER_MMAP) |
793 | return -EINVAL; | |
794 | mmap_buf_len = chan->backend.buf_size; | |
795 | if (chan->backend.extra_reader_sb) | |
796 | mmap_buf_len += chan->backend.subbuf_size; | |
797 | if (mmap_buf_len > INT_MAX) | |
798 | return -EFBIG; | |
799 | *len = mmap_buf_len; | |
800 | return 0; | |
801 | } | |
802 | ||
803 | /* returns the maximum size for sub-buffers. */ | |
38fae1d3 | 804 | int ustctl_get_max_subbuf_size(struct lttng_ust_shm_handle *handle, |
4cfec15c | 805 | struct lttng_ust_lib_ring_buffer *buf, |
57773204 MD |
806 | unsigned long *len) |
807 | { | |
36860b65 | 808 | struct channel *chan; |
57773204 | 809 | |
9bfc503d MD |
810 | if (!handle || !buf || !len) |
811 | return -EINVAL; | |
812 | ||
36860b65 | 813 | chan = handle->shadow_chan; |
57773204 MD |
814 | *len = chan->backend.subbuf_size; |
815 | return 0; | |
816 | } | |
817 | ||
818 | /* | |
819 | * For mmap mode, operate on the current packet (between get/put or | |
820 | * get_next/put_next). | |
821 | */ | |
822 | ||
823 | /* returns the offset of the subbuffer belonging to the mmap reader. */ | |
38fae1d3 | 824 | int ustctl_get_mmap_read_offset(struct lttng_ust_shm_handle *handle, |
4cfec15c | 825 | struct lttng_ust_lib_ring_buffer *buf, unsigned long *off) |
57773204 | 826 | { |
36860b65 | 827 | struct channel *chan; |
57773204 MD |
828 | unsigned long sb_bindex; |
829 | ||
9bfc503d MD |
830 | if (!handle || !buf || !off) |
831 | return -EINVAL; | |
832 | ||
36860b65 | 833 | chan = handle->shadow_chan; |
57773204 MD |
834 | if (chan->backend.config.output != RING_BUFFER_MMAP) |
835 | return -EINVAL; | |
836 | sb_bindex = subbuffer_id_get_index(&chan->backend.config, | |
837 | buf->backend.buf_rsb.id); | |
838 | *off = shmp(handle, shmp_index(handle, buf->backend.array, sb_bindex)->shmp)->mmap_offset; | |
839 | return 0; | |
840 | } | |
841 | ||
842 | /* returns the size of the current sub-buffer, without padding (for mmap). */ | |
38fae1d3 | 843 | int ustctl_get_subbuf_size(struct lttng_ust_shm_handle *handle, |
4cfec15c | 844 | struct lttng_ust_lib_ring_buffer *buf, unsigned long *len) |
57773204 | 845 | { |
36860b65 | 846 | struct channel *chan; |
57773204 | 847 | |
9bfc503d MD |
848 | if (!handle || !buf || !len) |
849 | return -EINVAL; | |
850 | ||
36860b65 | 851 | chan = handle->shadow_chan; |
57773204 MD |
852 | *len = lib_ring_buffer_get_read_data_size(&chan->backend.config, buf, |
853 | handle); | |
854 | return 0; | |
855 | } | |
856 | ||
857 | /* returns the size of the current sub-buffer, without padding (for mmap). */ | |
38fae1d3 | 858 | int ustctl_get_padded_subbuf_size(struct lttng_ust_shm_handle *handle, |
4cfec15c | 859 | struct lttng_ust_lib_ring_buffer *buf, unsigned long *len) |
57773204 | 860 | { |
36860b65 | 861 | struct channel *chan; |
57773204 | 862 | |
9bfc503d MD |
863 | if (!handle || !buf || !len) |
864 | return -EINVAL; | |
865 | ||
36860b65 | 866 | chan = handle->shadow_chan; |
57773204 MD |
867 | *len = lib_ring_buffer_get_read_data_size(&chan->backend.config, buf, |
868 | handle); | |
869 | *len = PAGE_ALIGN(*len); | |
870 | return 0; | |
871 | } | |
872 | ||
873 | /* Get exclusive read access to the next sub-buffer that can be read. */ | |
38fae1d3 | 874 | int ustctl_get_next_subbuf(struct lttng_ust_shm_handle *handle, |
4cfec15c | 875 | struct lttng_ust_lib_ring_buffer *buf) |
57773204 | 876 | { |
9bfc503d MD |
877 | if (!handle || !buf) |
878 | return -EINVAL; | |
879 | ||
57773204 MD |
880 | return lib_ring_buffer_get_next_subbuf(buf, handle); |
881 | } | |
882 | ||
883 | ||
884 | /* Release exclusive sub-buffer access, move consumer forward. */ | |
38fae1d3 | 885 | int ustctl_put_next_subbuf(struct lttng_ust_shm_handle *handle, |
4cfec15c | 886 | struct lttng_ust_lib_ring_buffer *buf) |
57773204 | 887 | { |
9bfc503d MD |
888 | if (!handle || !buf) |
889 | return -EINVAL; | |
890 | ||
57773204 MD |
891 | lib_ring_buffer_put_next_subbuf(buf, handle); |
892 | return 0; | |
893 | } | |
894 | ||
895 | /* snapshot */ | |
896 | ||
897 | /* Get a snapshot of the current ring buffer producer and consumer positions */ | |
38fae1d3 | 898 | int ustctl_snapshot(struct lttng_ust_shm_handle *handle, |
4cfec15c | 899 | struct lttng_ust_lib_ring_buffer *buf) |
57773204 | 900 | { |
9bfc503d MD |
901 | if (!handle || !buf) |
902 | return -EINVAL; | |
903 | ||
57773204 MD |
904 | return lib_ring_buffer_snapshot(buf, &buf->cons_snapshot, |
905 | &buf->prod_snapshot, handle); | |
906 | } | |
907 | ||
908 | /* Get the consumer position (iteration start) */ | |
38fae1d3 | 909 | int ustctl_snapshot_get_consumed(struct lttng_ust_shm_handle *handle, |
4cfec15c | 910 | struct lttng_ust_lib_ring_buffer *buf, unsigned long *pos) |
57773204 | 911 | { |
9bfc503d MD |
912 | if (!handle || !buf || !pos) |
913 | return -EINVAL; | |
914 | ||
57773204 MD |
915 | *pos = buf->cons_snapshot; |
916 | return 0; | |
917 | } | |
918 | ||
919 | /* Get the producer position (iteration end) */ | |
38fae1d3 | 920 | int ustctl_snapshot_get_produced(struct lttng_ust_shm_handle *handle, |
4cfec15c | 921 | struct lttng_ust_lib_ring_buffer *buf, unsigned long *pos) |
57773204 | 922 | { |
9bfc503d MD |
923 | if (!handle || !buf || !pos) |
924 | return -EINVAL; | |
925 | ||
57773204 MD |
926 | *pos = buf->prod_snapshot; |
927 | return 0; | |
928 | } | |
929 | ||
930 | /* Get exclusive read access to the specified sub-buffer position */ | |
38fae1d3 | 931 | int ustctl_get_subbuf(struct lttng_ust_shm_handle *handle, |
4cfec15c | 932 | struct lttng_ust_lib_ring_buffer *buf, unsigned long *pos) |
57773204 | 933 | { |
9bfc503d MD |
934 | if (!handle || !buf || !pos) |
935 | return -EINVAL; | |
936 | ||
57773204 MD |
937 | return lib_ring_buffer_get_subbuf(buf, *pos, handle); |
938 | } | |
939 | ||
940 | /* Release exclusive sub-buffer access */ | |
38fae1d3 | 941 | int ustctl_put_subbuf(struct lttng_ust_shm_handle *handle, |
4cfec15c | 942 | struct lttng_ust_lib_ring_buffer *buf) |
57773204 | 943 | { |
9bfc503d MD |
944 | if (!handle || !buf) |
945 | return -EINVAL; | |
946 | ||
57773204 MD |
947 | lib_ring_buffer_put_subbuf(buf, handle); |
948 | return 0; | |
949 | } | |
950 | ||
02a15cfb | 951 | void ustctl_flush_buffer(struct lttng_ust_shm_handle *handle, |
b52190f2 MD |
952 | struct lttng_ust_lib_ring_buffer *buf, |
953 | int producer_active) | |
57773204 | 954 | { |
9bfc503d | 955 | assert(handle && buf); |
b52190f2 MD |
956 | lib_ring_buffer_switch_slow(buf, |
957 | producer_active ? SWITCH_ACTIVE : SWITCH_FLUSH, | |
958 | handle); | |
57773204 | 959 | } |