Sync ax_have_epoll.m4 with autoconf-archive
[lttng-tools.git] / src / lib / lttng-ctl / clear.c
CommitLineData
f2c1f0d4
MD
1/*
2 * Copyright (C) 2019 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 * Copyright (C) 2019 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 *
5 * This library is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU Lesser General Public License, version 2.1 only,
7 * as published by the Free Software Foundation.
8 *
9 * This library is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
12 * for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this library; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19#define _LGPL_SOURCE
20#include <assert.h>
21#include <string.h>
22
23#include <lttng/lttng-error.h>
24#include <lttng/clear.h>
25#include <lttng/clear-handle.h>
26#include <common/sessiond-comm/sessiond-comm.h>
27#include <common/macros.h>
28#include <common/compat/poll.h>
29#include <common/dynamic-buffer.h>
30#include <common/buffer-view.h>
31#include <common/optional.h>
32
33#include "lttng-ctl-helper.h"
34
35enum communication_state {
36 COMMUNICATION_STATE_RECEIVE_LTTNG_MSG,
37 COMMUNICATION_STATE_RECEIVE_COMMAND_HEADER,
38 COMMUNICATION_STATE_END,
39 COMMUNICATION_STATE_ERROR,
40};
41
42struct lttng_clear_handle {
43 LTTNG_OPTIONAL(enum lttng_error_code) clear_return_code;
44 struct {
45 int socket;
46 struct lttng_poll_event events;
47 size_t bytes_left_to_receive;
48 enum communication_state state;
49 struct lttng_dynamic_buffer buffer;
50 LTTNG_OPTIONAL(size_t) data_size;
51 } communication;
52};
53
54void lttng_clear_handle_destroy(struct lttng_clear_handle *handle)
55{
56 int ret;
57
58 if (!handle) {
59 return;
60 }
61
62 if (handle->communication.socket >= 0) {
63 ret = close(handle->communication.socket);
64 if (ret) {
65 PERROR("Failed to close lttng-sessiond command socket");
66 }
67 }
68 lttng_poll_clean(&handle->communication.events);
69 lttng_dynamic_buffer_reset(&handle->communication.buffer);
70 free(handle);
71}
72
73static
74struct lttng_clear_handle *lttng_clear_handle_create(int sessiond_socket)
75{
76 int ret;
77 struct lttng_clear_handle *handle = zmalloc(sizeof(*handle));
78
79 if (!handle) {
80 goto end;
81 }
82 lttng_dynamic_buffer_init(&handle->communication.buffer);
83 handle->communication.socket = sessiond_socket;
84 ret = lttng_poll_create(&handle->communication.events, 1, 0);
85 if (ret) {
86 goto error;
87 }
88
89 ret = lttng_poll_add(&handle->communication.events, sessiond_socket,
90 LPOLLIN | LPOLLHUP | LPOLLRDHUP | LPOLLERR);
91 if (ret) {
92 goto error;
93 }
94
95 handle->communication.bytes_left_to_receive =
96 sizeof(struct lttcomm_lttng_msg);
97 handle->communication.state = COMMUNICATION_STATE_RECEIVE_LTTNG_MSG;
98end:
99 return handle;
100error:
101 lttng_clear_handle_destroy(handle);
102 return NULL;
103}
104
105static
106int handle_state_transition(struct lttng_clear_handle *handle)
107{
108 int ret = 0;
109
110 assert(handle->communication.bytes_left_to_receive == 0);
111
112 switch (handle->communication.state) {
113 case COMMUNICATION_STATE_RECEIVE_LTTNG_MSG:
114 {
115 const struct lttcomm_lttng_msg *msg =
116 (typeof(msg)) handle->communication.buffer.data;
117
118 LTTNG_OPTIONAL_SET(&handle->clear_return_code,
119 (enum lttng_error_code) msg->ret_code);
120 if (handle->clear_return_code.value != LTTNG_OK) {
121 handle->communication.state = COMMUNICATION_STATE_END;
122 break;
123 } else if (msg->cmd_header_size != 0 || msg->data_size != 0) {
124 handle->communication.state = COMMUNICATION_STATE_ERROR;
125 ret = -1;
126 break;
127 }
128
129 handle->communication.state = COMMUNICATION_STATE_END;
130 handle->communication.bytes_left_to_receive = 0;
131 LTTNG_OPTIONAL_SET(&handle->communication.data_size, 0);
132 ret = lttng_dynamic_buffer_set_size(
133 &handle->communication.buffer, 0);
134 assert(!ret);
135 break;
136 }
137 default:
138 abort();
139 }
140
141 /* Clear reception buffer on state transition. */
142 if (lttng_dynamic_buffer_set_size(&handle->communication.buffer, 0)) {
143 abort();
144 }
145 return ret;
146}
147
148static
149int handle_incoming_data(struct lttng_clear_handle *handle)
150{
151 int ret;
152 ssize_t comm_ret;
153 const size_t original_buffer_size = handle->communication.buffer.size;
154
155 /* Reserve space for reception. */
156 ret = lttng_dynamic_buffer_set_size(&handle->communication.buffer,
157 original_buffer_size + handle->communication.bytes_left_to_receive);
158 if (ret) {
159 goto end;
160 }
161
162 comm_ret = lttcomm_recv_unix_sock(handle->communication.socket,
163 handle->communication.buffer.data + original_buffer_size,
164 handle->communication.bytes_left_to_receive);
165 if (comm_ret <= 0) {
166 ret = -1;
167 goto end;
168 }
169
170 handle->communication.bytes_left_to_receive -= comm_ret;
171 if (handle->communication.bytes_left_to_receive == 0) {
172 ret = handle_state_transition(handle);
173 } else {
174 ret = lttng_dynamic_buffer_set_size(
175 &handle->communication.buffer,
176 original_buffer_size + comm_ret);
177 }
178end:
179 return ret;
180}
181
182extern enum lttng_clear_handle_status
183 lttng_clear_handle_wait_for_completion(
184 struct lttng_clear_handle *handle, int timeout_ms)
185{
186 int ret;
187 enum lttng_clear_handle_status status;
188 unsigned long time_left_ms = 0;
189 const bool has_timeout = timeout_ms > 0;
190 struct timespec initial_time;
191
192 if (handle->communication.state == COMMUNICATION_STATE_ERROR) {
193 status = LTTNG_CLEAR_HANDLE_STATUS_ERROR;
194 goto end;
195 } else if (handle->communication.state == COMMUNICATION_STATE_END) {
196 status = LTTNG_CLEAR_HANDLE_STATUS_COMPLETED;
197 goto end;
198 }
199 if (has_timeout) {
200 ret = lttng_clock_gettime(CLOCK_MONOTONIC, &initial_time);
201 if (ret) {
202 status = LTTNG_CLEAR_HANDLE_STATUS_ERROR;
203 goto end;
204 }
205 time_left_ms = (unsigned long) timeout_ms;
206 }
207
208 while (handle->communication.state != COMMUNICATION_STATE_END &&
209 (time_left_ms || !has_timeout)) {
210 int ret;
211 uint32_t revents;
212 struct timespec current_time, diff;
213 unsigned long diff_ms;
214
215 ret = lttng_poll_wait(&handle->communication.events,
216 has_timeout ? time_left_ms : -1);
217 if (ret == 0) {
218 /* timeout */
219 break;
220 } else if (ret < 0) {
221 status = LTTNG_CLEAR_HANDLE_STATUS_ERROR;
222 goto end;
223 }
224
225 /* The sessiond connection socket is the only monitored fd. */
226 revents = LTTNG_POLL_GETEV(&handle->communication.events, 0);
227 if (revents & LPOLLIN) {
228 ret = handle_incoming_data(handle);
229 if (ret) {
230 handle->communication.state =
231 COMMUNICATION_STATE_ERROR;
232 status = LTTNG_CLEAR_HANDLE_STATUS_ERROR;
233 goto end;
234 }
235 } else {
236 handle->communication.state = COMMUNICATION_STATE_ERROR;
237 status = LTTNG_CLEAR_HANDLE_STATUS_ERROR;
238 goto end;
239 }
240 if (!has_timeout) {
241 continue;
242 }
243
244 ret = lttng_clock_gettime(CLOCK_MONOTONIC, &current_time);
245 if (ret) {
246 status = LTTNG_CLEAR_HANDLE_STATUS_ERROR;
247 goto end;
248 }
249 diff = timespec_abs_diff(initial_time, current_time);
250 ret = timespec_to_ms(diff, &diff_ms);
251 if (ret) {
252 ERR("Failed to compute elapsed time while waiting for completion");
253 status = LTTNG_CLEAR_HANDLE_STATUS_ERROR;
254 goto end;
255 }
256 DBG("%lums elapsed while waiting for session clear completion",
257 diff_ms);
258 diff_ms = max_t(unsigned long, diff_ms, 1);
259 diff_ms = min_t(unsigned long, diff_ms, time_left_ms);
260 time_left_ms -= diff_ms;
261 }
262
263 status = handle->communication.state == COMMUNICATION_STATE_END ?
264 LTTNG_CLEAR_HANDLE_STATUS_COMPLETED :
265 LTTNG_CLEAR_HANDLE_STATUS_TIMEOUT;
266end:
267 return status;
268}
269
270extern enum lttng_clear_handle_status
271 lttng_clear_handle_get_result(
272 const struct lttng_clear_handle *handle,
273 enum lttng_error_code *result)
274{
275 enum lttng_clear_handle_status status =
276 LTTNG_CLEAR_HANDLE_STATUS_OK;
277
278 if (!handle->clear_return_code.is_set) {
279 status = LTTNG_CLEAR_HANDLE_STATUS_INVALID;
280 goto end;
281 }
282 *result = handle->clear_return_code.value;
283end:
284 return status;
285}
286
287/*
288 * Clear the session
289 */
290enum lttng_error_code lttng_clear_session(const char *session_name,
291 struct lttng_clear_handle **_handle)
292{
293 enum lttng_error_code ret_code = LTTNG_OK;
294 struct lttng_clear_handle *handle = NULL;
295 struct lttcomm_session_msg lsm = {
296 .cmd_type = LTTNG_CLEAR_SESSION,
297 };
298 int sessiond_socket = -1;
299 ssize_t comm_ret;
300 int ret;
301
302 if (session_name == NULL) {
303 ret_code = LTTNG_ERR_INVALID;
304 goto error;
305 }
306 ret = lttng_strncpy(lsm.session.name, session_name,
307 sizeof(lsm.session.name));
308 if (ret) {
309 ret_code = LTTNG_ERR_INVALID;
310 goto error;
311 }
312 ret = connect_sessiond();
313 if (ret < 0) {
314 ret_code = LTTNG_ERR_NO_SESSIOND;
315 goto error;
316 } else {
317 sessiond_socket = ret;
318 }
319 handle = lttng_clear_handle_create(sessiond_socket);
320 if (!handle) {
321 ret_code = LTTNG_ERR_NOMEM;
322 goto error;
323 }
324 comm_ret = lttcomm_send_creds_unix_sock(sessiond_socket, &lsm, sizeof(lsm));
325 if (comm_ret < 0) {
326 ret_code = LTTNG_ERR_FATAL;
327 goto error;
328 }
329 sessiond_socket = -1;
330
331error:
332 /* Transfer the handle to the caller. */
333 if (_handle) {
334 *_handle = handle;
335 handle = NULL;
336 }
337 if (sessiond_socket >= 0) {
338 ret = close(sessiond_socket);
339 if (ret < 0) {
340 PERROR("Failed to close the LTTng session daemon connection socket");
341 }
342 }
343 if (handle) {
344 lttng_clear_handle_destroy(handle);
345 }
346 return ret_code;
347}
This page took 0.034903 seconds and 4 git commands to generate.