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