quick fixes
[lttng-tools.git] / src / bin / lttng-sessiond / rotation-thread.c
CommitLineData
6e0be6cc
JD
1/*
2 * Copyright (C) 2017 - Julien Desfossez <jdesfossez@efficios.com>
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, version 2 only, as
6 * published by the Free Software Foundation.
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., 51
15 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18#define _LGPL_SOURCE
19#include <lttng/trigger/trigger.h>
20#include <common/error.h>
21#include <common/config/session-config.h>
22#include <common/defaults.h>
23#include <common/utils.h>
24#include <common/futex.h>
25#include <common/align.h>
26#include <common/time.h>
27#include <common/hashtable/utils.h>
28#include <sys/eventfd.h>
29#include <sys/stat.h>
30#include <time.h>
31#include <signal.h>
32#include <inttypes.h>
33
34#include <common/kernel-ctl/kernel-ctl.h>
35#include "rotation-thread.h"
36#include "lttng-sessiond.h"
37#include "health-sessiond.h"
e8ed1ed1 38#include "rotate.h"
6e0be6cc
JD
39#include "cmd.h"
40
41#include <urcu.h>
42#include <urcu/list.h>
43#include <urcu/rculfhash.h>
44
45struct cds_lfht *channel_pending_rotate_ht;
46
6e0be6cc
JD
47static
48void channel_rotation_info_destroy(struct rotation_channel_info *channel_info)
49{
50 assert(channel_info);
51 free(channel_info);
52}
53
6e0be6cc
JD
54static
55int match_channel_info(struct cds_lfht_node *node, const void *key)
56{
57 struct rotation_channel_key *channel_key = (struct rotation_channel_key *) key;
58 struct rotation_channel_info *channel_info;
59
60 channel_info = caa_container_of(node, struct rotation_channel_info,
61 rotate_channels_ht_node);
62
63 return !!((channel_key->key == channel_info->channel_key.key) &&
64 (channel_key->domain == channel_info->channel_key.domain));
65}
66
67static
68struct rotation_channel_info *lookup_channel_pending(uint64_t key,
69 enum lttng_domain_type domain)
70{
71 struct cds_lfht_iter iter;
72 struct cds_lfht_node *node;
73 struct rotation_channel_info *channel_info = NULL;
74 struct rotation_channel_key channel_key = { .key = key,
75 .domain = domain };
76
77 cds_lfht_lookup(channel_pending_rotate_ht,
78 hash_channel_key(&channel_key),
79 match_channel_info,
80 &channel_key, &iter);
81 node = cds_lfht_iter_get_node(&iter);
82 if (!node) {
83 goto end;
84 }
85
86 channel_info = caa_container_of(node, struct rotation_channel_info,
87 rotate_channels_ht_node);
88 cds_lfht_del(channel_pending_rotate_ht, node);
89end:
90 return channel_info;
91}
92
93/*
94 * Destroy the thread data previously created by the init function.
95 */
96void rotation_thread_handle_destroy(
97 struct rotation_thread_handle *handle)
98{
99 int ret;
100
101 if (!handle) {
102 goto end;
103 }
104
105 if (handle->ust32_consumer >= 0) {
106 ret = close(handle->ust32_consumer);
107 if (ret) {
108 PERROR("close 32-bit consumer channel rotation pipe");
109 }
110 }
111 if (handle->ust64_consumer >= 0) {
112 ret = close(handle->ust64_consumer);
113 if (ret) {
114 PERROR("close 64-bit consumer channel rotation pipe");
115 }
116 }
117 if (handle->kernel_consumer >= 0) {
118 ret = close(handle->kernel_consumer);
119 if (ret) {
120 PERROR("close kernel consumer channel rotation pipe");
121 }
122 }
123
124end:
125 free(handle);
126}
127
128struct rotation_thread_handle *rotation_thread_handle_create(
129 struct lttng_pipe *ust32_channel_rotate_pipe,
130 struct lttng_pipe *ust64_channel_rotate_pipe,
131 struct lttng_pipe *kernel_channel_rotate_pipe,
132 int thread_quit_pipe)
133{
134 struct rotation_thread_handle *handle;
135
136 handle = zmalloc(sizeof(*handle));
137 if (!handle) {
138 goto end;
139 }
140
141 if (ust32_channel_rotate_pipe) {
142 handle->ust32_consumer =
143 lttng_pipe_release_readfd(
144 ust32_channel_rotate_pipe);
145 if (handle->ust32_consumer < 0) {
146 goto error;
147 }
148 } else {
149 handle->ust32_consumer = -1;
150 }
151 if (ust64_channel_rotate_pipe) {
152 handle->ust64_consumer =
153 lttng_pipe_release_readfd(
154 ust64_channel_rotate_pipe);
155 if (handle->ust64_consumer < 0) {
156 goto error;
157 }
158 } else {
159 handle->ust64_consumer = -1;
160 }
161 if (kernel_channel_rotate_pipe) {
162 handle->kernel_consumer =
163 lttng_pipe_release_readfd(
164 kernel_channel_rotate_pipe);
165 if (handle->kernel_consumer < 0) {
166 goto error;
167 }
168 } else {
169 handle->kernel_consumer = -1;
170 }
171 handle->thread_quit_pipe = thread_quit_pipe;
172
173end:
174 return handle;
175error:
176 rotation_thread_handle_destroy(handle);
177 return NULL;
178}
179
180static
181int init_poll_set(struct lttng_poll_event *poll_set,
182 struct rotation_thread_handle *handle)
183{
184 int ret;
185
186 /*
187 * Create pollset with size 4:
188 * - sessiond quit pipe
189 * - consumerd (32-bit user space) channel rotate pipe,
190 * - consumerd (64-bit user space) channel rotate pipe,
191 * - consumerd (kernel) channel rotate pipe.
192 */
193 ret = lttng_poll_create(poll_set, 4, LTTNG_CLOEXEC);
194 if (ret < 0) {
195 goto end;
196 }
197
198 ret = lttng_poll_add(poll_set, handle->thread_quit_pipe,
199 LPOLLIN | LPOLLERR);
200 if (ret < 0) {
201 ERR("[rotation-thread] Failed to add thread_quit_pipe fd to pollset");
202 goto error;
203 }
204 ret = lttng_poll_add(poll_set, handle->ust32_consumer,
205 LPOLLIN | LPOLLERR);
206 if (ret < 0) {
207 ERR("[rotation-thread] Failed to add ust-32 channel rotation pipe fd to pollset");
208 goto error;
209 }
210 ret = lttng_poll_add(poll_set, handle->ust64_consumer,
211 LPOLLIN | LPOLLERR);
212 if (ret < 0) {
213 ERR("[rotation-thread] Failed to add ust-64 channel rotation pipe fd to pollset");
214 goto error;
215 }
216 if (handle->kernel_consumer < 0) {
217 goto end;
218 }
219 ret = lttng_poll_add(poll_set, handle->kernel_consumer,
220 LPOLLIN | LPOLLERR);
221 if (ret < 0) {
222 ERR("[rotation-thread] Failed to add kernel channel rotation pipe fd to pollset");
223 goto error;
224 }
225
226end:
227 return ret;
228error:
229 lttng_poll_clean(poll_set);
230 return ret;
231}
232
233static
234void fini_thread_state(struct rotation_thread_state *state)
235{
236 lttng_poll_clean(&state->events);
237}
238
239static
240int init_thread_state(struct rotation_thread_handle *handle,
241 struct rotation_thread_state *state)
242{
243 int ret;
244
245 memset(state, 0, sizeof(*state));
246 lttng_poll_init(&state->events);
247
248 ret = init_poll_set(&state->events, handle);
249 if (ret) {
250 goto end;
251 }
252
253 channel_pending_rotate_ht = cds_lfht_new(DEFAULT_HT_SIZE,
254 1, 0, CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING, NULL);
255 if (!channel_pending_rotate_ht) {
256 ret = -1;
257 }
258
259end:
260 return 0;
261}
262
6e0be6cc
JD
263static
264int handle_channel_rotation_pipe(int fd, uint32_t revents,
265 struct rotation_thread_handle *handle,
266 struct rotation_thread_state *state)
267{
268 int ret = 0;
269 enum lttng_domain_type domain;
270 struct rotation_channel_info *channel_info;
271 uint64_t key;
272
273 if (fd == handle->ust32_consumer ||
274 fd == handle->ust64_consumer) {
275 domain = LTTNG_DOMAIN_UST;
276 } else if (fd == handle->kernel_consumer) {
277 domain = LTTNG_DOMAIN_KERNEL;
278 } else {
279 abort();
280 }
281
282 if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) {
283 ret = lttng_poll_del(&state->events, fd);
284 if (ret) {
103373d7
JD
285 ERR("[rotation-thread] Failed to remove consumer "
286 "rotation pipe from poll set");
6e0be6cc
JD
287 }
288 goto end;
289 }
290
291 do {
292 ret = read(fd, &key, sizeof(key));
293 } while (ret == -1 && errno == EINTR);
294 if (ret != sizeof(key)) {
295 ERR("[rotation-thread] Failed to read from pipe (fd = %i)",
296 fd);
297 ret = -1;
298 goto end;
299 }
300
301 DBG("[rotation-thread] Received notification for chan %" PRIu64
302 ", domain %d\n", key, domain);
303
304 channel_info = lookup_channel_pending(key, domain);
305 if (!channel_info) {
306 ERR("[rotation-thread] Failed to find channel_info (key = %"
307 PRIu64 ")", key);
308 ret = -1;
309 goto end;
310 }
311
312 if (--channel_info->session->nr_chan_rotate_pending == 0) {
313 time_t now = time(NULL);
314
315 if (now == (time_t) -1) {
4a478f45 316 channel_info->session->rotate_status = LTTNG_ROTATE_ERROR;
6e0be6cc
JD
317 ret = LTTNG_ERR_ROTATE_NOT_AVAILABLE;
318 goto end;
319 }
320
321 ret = rename_complete_chunk(channel_info->session, now);
322 if (ret < 0) {
323 ERR("Failed to rename completed rotation chunk");
324 goto end;
325 }
46a8d585 326 channel_info->session->rotate_pending = 0;
6e0be6cc
JD
327 }
328
329 channel_rotation_info_destroy(channel_info);
330
331 ret = 0;
332
333end:
334 return ret;
335}
336
337void *thread_rotation(void *data)
338{
339 int ret;
340 struct rotation_thread_handle *handle = data;
341 struct rotation_thread_state state;
342
343 DBG("[rotation-thread] Started rotation thread");
344
345 if (!handle) {
346 ERR("[rotation-thread] Invalid thread context provided");
347 goto end;
348 }
349
350 rcu_register_thread();
351 rcu_thread_online();
352
353 health_register(health_sessiond, HEALTH_SESSIOND_TYPE_ROTATION);
354 health_code_update();
355
356 ret = init_thread_state(handle, &state);
357 if (ret) {
358 goto end;
359 }
360
361 /* Ready to handle client connections. */
362 sessiond_notify_ready();
363
364 while (true) {
365 int fd_count, i;
366
367 health_poll_entry();
368 DBG("[rotation-thread] Entering poll wait");
369 ret = lttng_poll_wait(&state.events, -1);
370 DBG("[rotation-thread] Poll wait returned (%i)", ret);
371 health_poll_exit();
372 if (ret < 0) {
373 /*
374 * Restart interrupted system call.
375 */
376 if (errno == EINTR) {
377 continue;
378 }
379 ERR("[rotation-thread] Error encountered during lttng_poll_wait (%i)", ret);
380 goto error;
381 }
382
383 fd_count = ret;
384 for (i = 0; i < fd_count; i++) {
385 int fd = LTTNG_POLL_GETFD(&state.events, i);
386 uint32_t revents = LTTNG_POLL_GETEV(&state.events, i);
387
388 DBG("[rotation-thread] Handling fd (%i) activity (%u)",
389 fd, revents);
390
391 if (fd == handle->thread_quit_pipe) {
392 DBG("[rotation-thread] Quit pipe activity");
393 goto exit;
394 } else if (fd == handle->ust32_consumer ||
395 fd == handle->ust64_consumer ||
396 fd == handle->kernel_consumer) {
397 ret = handle_channel_rotation_pipe(fd,
398 revents, handle, &state);
399 if (ret) {
400 ERR("[rotation-thread] Exit main loop");
401 goto error;
402 }
403 }
404 }
405 }
406exit:
407error:
408 fini_thread_state(&state);
409 health_unregister(health_sessiond);
410 rcu_thread_offline();
411 rcu_unregister_thread();
412end:
413 return NULL;
414}
This page took 0.038914 seconds and 5 git commands to generate.