lttng add-trigger: replace log level options with --log-level
[lttng-tools.git] / src / bin / lttng-sessiond / ht-cleanup.c
1 /*
2 * Copyright (C) 2013 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
8 #define _LGPL_SOURCE
9 #include <assert.h>
10
11 #include <common/hashtable/hashtable.h>
12 #include <common/common.h>
13 #include <common/utils.h>
14 #include <pthread.h>
15
16 #include "lttng-sessiond.h"
17 #include "health-sessiond.h"
18 #include "testpoint.h"
19 #include "utils.h"
20 #include "ht-cleanup.h"
21
22 static int ht_cleanup_quit_pipe[2] = { -1, -1 };
23
24 /*
25 * Check if the ht_cleanup thread quit pipe was triggered.
26 *
27 * Return true if it was triggered else false;
28 */
29 static bool check_quit_pipe(int fd, uint32_t events)
30 {
31 return (fd == ht_cleanup_quit_pipe[0] && (events & LPOLLIN));
32 }
33
34 static int init_pipe(int *pipe_fds)
35 {
36 int ret, i;
37
38 ret = pipe(pipe_fds);
39 if (ret < 0) {
40 PERROR("ht_cleanup thread quit pipe");
41 goto error;
42 }
43
44 for (i = 0; i < 2; i++) {
45 ret = fcntl(pipe_fds[i], F_SETFD, FD_CLOEXEC);
46 if (ret < 0) {
47 PERROR("fcntl ht_cleanup_quit_pipe");
48 goto error;
49 }
50 }
51 error:
52 return ret;
53 }
54
55 /*
56 * Create a poll set with O_CLOEXEC and add the thread quit pipe to the set.
57 */
58 static int set_pollset(struct lttng_poll_event *events, size_t size)
59 {
60 int ret;
61
62 ret = lttng_poll_create(events, size, LTTNG_CLOEXEC);
63 if (ret < 0) {
64 goto error;
65 }
66
67 ret = lttng_poll_add(events, ht_cleanup_quit_pipe[0],
68 LPOLLIN | LPOLLERR);
69 if (ret < 0) {
70 goto error;
71 }
72
73 ret = lttng_poll_add(events, the_ht_cleanup_pipe[0], LPOLLIN | LPOLLERR);
74 if (ret < 0) {
75 DBG("[ht-thread] lttng_poll_add error %d.", ret);
76 goto error;
77 }
78
79 return 0;
80
81 error:
82 return ret;
83 }
84
85 static void cleanup_ht_cleanup_thread(void *data)
86 {
87 utils_close_pipe(ht_cleanup_quit_pipe);
88 utils_close_pipe(the_ht_cleanup_pipe);
89 }
90
91 static void *thread_ht_cleanup(void *data)
92 {
93 int ret, i, pollfd, err = -1;
94 ssize_t size_ret;
95 uint32_t revents, nb_fd;
96 struct lttng_poll_event events;
97
98 DBG("[ht-thread] startup.");
99
100 rcu_register_thread();
101 rcu_thread_online();
102
103 health_register(the_health_sessiond, HEALTH_SESSIOND_TYPE_HT_CLEANUP);
104
105 if (testpoint(sessiond_thread_ht_cleanup)) {
106 DBG("[ht-thread] testpoint.");
107 goto error_testpoint;
108 }
109
110 health_code_update();
111
112 ret = set_pollset(&events, 2);
113 if (ret < 0) {
114 DBG("[ht-thread] sessiond_set_ht_cleanup_thread_pollset error %d.", ret);
115 goto error_poll_create;
116 }
117
118 health_code_update();
119
120 while (1) {
121 restart:
122 DBG3("[ht-thread] Polling.");
123 health_poll_entry();
124 ret = lttng_poll_wait(&events, -1);
125 DBG3("[ht-thread] Returning from poll on %d fds.",
126 LTTNG_POLL_GETNB(&events));
127 health_poll_exit();
128 if (ret < 0) {
129 /*
130 * Restart interrupted system call.
131 */
132 if (errno == EINTR) {
133 continue;
134 }
135 goto error;
136 }
137
138 nb_fd = ret;
139 for (i = 0; i < nb_fd; i++) {
140 struct lttng_ht *ht;
141
142 health_code_update();
143
144 /* Fetch once the poll data */
145 revents = LTTNG_POLL_GETEV(&events, i);
146 pollfd = LTTNG_POLL_GETFD(&events, i);
147
148 if (pollfd != the_ht_cleanup_pipe[0]) {
149 continue;
150 }
151
152 if (revents & LPOLLIN) {
153 /* Get socket from dispatch thread. */
154 size_ret = lttng_read(the_ht_cleanup_pipe[0],
155 &ht, sizeof(ht));
156 if (size_ret < sizeof(ht)) {
157 PERROR("ht cleanup notify pipe");
158 goto error;
159 }
160 health_code_update();
161 /*
162 * The whole point of this thread is to call
163 * lttng_ht_destroy from a context that is NOT:
164 * 1) a read-side RCU lock,
165 * 2) a call_rcu thread.
166 */
167 lttng_ht_destroy(ht);
168
169 health_code_update();
170
171 /*
172 * Ensure that we never process the quit pipe
173 * event while there is still data available
174 * on the ht clean pipe.
175 */
176 goto restart;
177 } else if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) {
178 ERR("ht cleanup pipe error");
179 goto error;
180 } else {
181 ERR("Unexpected poll events %u for sock %d", revents, pollfd);
182 goto error;
183 }
184 }
185
186 for (i = 0; i < nb_fd; i++) {
187 health_code_update();
188
189 /* Fetch once the poll data */
190 revents = LTTNG_POLL_GETEV(&events, i);
191 pollfd = LTTNG_POLL_GETFD(&events, i);
192
193 if (!revents) {
194 /* No activity for this FD (poll implementation). */
195 continue;
196 }
197
198 if (pollfd == the_ht_cleanup_pipe[0]) {
199 continue;
200 }
201
202 /* Thread quit pipe has been closed. Killing thread. */
203 ret = check_quit_pipe(pollfd, revents);
204 if (ret) {
205 err = 0;
206 DBG("[ht-cleanup] quit.");
207 goto exit;
208 }
209 }
210 }
211
212 exit:
213 error:
214 lttng_poll_clean(&events);
215 error_poll_create:
216 error_testpoint:
217 DBG("[ht-cleanup] Thread terminates.");
218 if (err) {
219 health_error();
220 ERR("Health error occurred in %s", __func__);
221 }
222 health_unregister(the_health_sessiond);
223 rcu_thread_offline();
224 rcu_unregister_thread();
225 return NULL;
226 }
227
228 static bool shutdown_ht_cleanup_thread(void *data)
229 {
230 int ret;
231
232 ret = notify_thread_pipe(ht_cleanup_quit_pipe[1]);
233 if (ret < 0) {
234 ERR("write error on ht_cleanup quit pipe");
235 goto end;
236 }
237 end:
238 return ret;
239 }
240
241 struct lttng_thread *launch_ht_cleanup_thread(void)
242 {
243 int ret;
244 struct lttng_thread *thread;
245
246 ret = init_pipe(the_ht_cleanup_pipe);
247 if (ret) {
248 goto error;
249 }
250
251 ret = init_pipe(ht_cleanup_quit_pipe);
252 if (ret) {
253 goto error;
254 }
255
256 thread = lttng_thread_create("HT cleanup",
257 thread_ht_cleanup,
258 shutdown_ht_cleanup_thread,
259 cleanup_ht_cleanup_thread,
260 NULL);
261 if (!thread) {
262 goto error;
263 }
264 return thread;
265 error:
266 cleanup_ht_cleanup_thread(NULL);
267 return NULL;
268 }
This page took 0.037425 seconds and 4 git commands to generate.