Stop the application registration thread before orphaned threads
[lttng-tools.git] / src / bin / lttng-sessiond / register.c
CommitLineData
1785d7f2
JG
1/*
2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 * Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 * 2013 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version 2 only,
8 * as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#include <stddef.h>
21#include <stdlib.h>
22#include <urcu.h>
23#include <common/futex.h>
24#include <common/macros.h>
25#include <common/utils.h>
26#include <sys/stat.h>
27
28#include "register.h"
29#include "lttng-sessiond.h"
30#include "testpoint.h"
31#include "health-sessiond.h"
32#include "fd-limit.h"
33#include "shm.h"
34#include "utils.h"
35#include "thread.h"
36
37struct thread_notifiers {
38 struct lttng_pipe *quit_pipe;
39 struct ust_cmd_queue *ust_cmd_queue;
40};
41
42/*
43 * Creates the application socket.
44 */
45static int create_application_socket(void)
46{
47 int ret = 0;
48 int apps_sock;
49 const mode_t old_umask = umask(0);
50
51 /* Create the application unix socket */
52 apps_sock = lttcomm_create_unix_sock(config.apps_unix_sock_path.value);
53 if (apps_sock < 0) {
54 ERR("Create unix sock failed: %s", config.apps_unix_sock_path.value);
55 ret = -1;
56 goto end;
57 }
58
59 /* Set the cloexec flag */
60 ret = utils_set_fd_cloexec(apps_sock);
61 if (ret < 0) {
62 ERR("Unable to set CLOEXEC flag to the app Unix socket (fd: %d). "
63 "Continuing but note that the consumer daemon will have a "
64 "reference to this socket on exec()", apps_sock);
65 }
66
67 /* File permission MUST be 666 */
68 ret = chmod(config.apps_unix_sock_path.value,
69 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
70 if (ret < 0) {
71 PERROR("Set file permissions failed on %s",
72 config.apps_unix_sock_path.value);
73 goto end;
74 }
75
76 DBG3("Session daemon application socket created (fd = %d) ", apps_sock);
77 ret = apps_sock;
78end:
79 umask(old_umask);
80 return ret;
81}
82
83/*
84 * Notify UST applications using the shm mmap futex.
85 */
86static int notify_ust_apps(int active, bool is_root)
87{
88 char *wait_shm_mmap;
89
90 DBG("Notifying applications of session daemon state: %d", active);
91
92 /* See shm.c for this call implying mmap, shm and futex calls */
93 wait_shm_mmap = shm_ust_get_mmap(config.wait_shm_path.value, is_root);
94 if (wait_shm_mmap == NULL) {
95 goto error;
96 }
97
98 /* Wake waiting process */
99 futex_wait_update((int32_t *) wait_shm_mmap, active);
100
101 /* Apps notified successfully */
102 return 0;
103
104error:
105 return -1;
106}
107
108static void cleanup_application_registration_thread(void *data)
109{
110 struct thread_notifiers *notifiers = data;
111
112 lttng_pipe_destroy(notifiers->quit_pipe);
113 free(notifiers);
114}
115
116/*
117 * This thread manage application registration.
118 */
119static void *thread_application_registration(void *data)
120{
121 int sock = -1, i, ret, pollfd, err = -1;
122 int apps_sock = -1;
123 uint32_t revents, nb_fd;
124 struct lttng_poll_event events;
125 /*
126 * Gets allocated in this thread, enqueued to a global queue, dequeued
127 * and freed in the manage apps thread.
128 */
129 struct ust_command *ust_cmd = NULL;
130 const bool is_root = (getuid() == 0);
131 struct thread_notifiers *notifiers = data;
132 const int quit_pipe_read_fd = lttng_pipe_get_readfd(
133 notifiers->quit_pipe);
134
135 DBG("[thread] Manage application registration started");
136
137 health_register(health_sessiond, HEALTH_SESSIOND_TYPE_APP_REG);
138
139 if (testpoint(sessiond_thread_registration_apps)) {
140 goto error_testpoint;
141 }
142
143 apps_sock = create_application_socket();
144 if (apps_sock < 0) {
145 goto error_listen;
146 }
147
148 ret = lttcomm_listen_unix_sock(apps_sock);
149 if (ret < 0) {
150 goto error_listen;
151 }
152
153 /*
154 * Pass 2 as size here for the thread quit pipe and apps_sock. Nothing
155 * more will be added to this poll set.
156 */
157 ret = lttng_poll_create(&events, 2, LTTNG_CLOEXEC);
158 if (ret < 0) {
159 goto error_create_poll;
160 }
161
162 /* Add the application registration socket */
163 ret = lttng_poll_add(&events, apps_sock, LPOLLIN | LPOLLRDHUP);
164 if (ret < 0) {
165 goto error_poll_add;
166 }
167
168 /* Add the application registration socket */
169 ret = lttng_poll_add(&events, quit_pipe_read_fd, LPOLLIN | LPOLLRDHUP);
170 if (ret < 0) {
171 goto error_poll_add;
172 }
173
174 /* Notify all applications to register */
175 ret = notify_ust_apps(1, is_root);
176 if (ret < 0) {
177 ERR("Failed to notify applications or create the wait shared memory.\n"
178 "Execution continues but there might be problem for already\n"
179 "running applications that wishes to register.");
180 }
181
182 while (1) {
183 DBG("Accepting application registration");
184
185 /* Inifinite blocking call, waiting for transmission */
186 restart:
187 health_poll_entry();
188 ret = lttng_poll_wait(&events, -1);
189 health_poll_exit();
190 if (ret < 0) {
191 /*
192 * Restart interrupted system call.
193 */
194 if (errno == EINTR) {
195 goto restart;
196 }
197 goto error;
198 }
199
200 nb_fd = ret;
201
202 for (i = 0; i < nb_fd; i++) {
203 health_code_update();
204
205 /* Fetch once the poll data */
206 revents = LTTNG_POLL_GETEV(&events, i);
207 pollfd = LTTNG_POLL_GETFD(&events, i);
208
209 if (!revents) {
210 /* No activity for this FD (poll implementation). */
211 continue;
212 }
213
214 /* Thread quit pipe has been closed. Killing thread. */
215 if (pollfd == quit_pipe_read_fd) {
216 err = 0;
217 goto exit;
218 } else {
219 /* Event on the registration socket */
220 if (revents & LPOLLIN) {
221 sock = lttcomm_accept_unix_sock(apps_sock);
222 if (sock < 0) {
223 goto error;
224 }
225
226 /*
227 * Set socket timeout for both receiving and ending.
228 * app_socket_timeout is in seconds, whereas
229 * lttcomm_setsockopt_rcv_timeout and
230 * lttcomm_setsockopt_snd_timeout expect msec as
231 * parameter.
232 */
233 if (config.app_socket_timeout >= 0) {
234 (void) lttcomm_setsockopt_rcv_timeout(sock,
235 config.app_socket_timeout * 1000);
236 (void) lttcomm_setsockopt_snd_timeout(sock,
237 config.app_socket_timeout * 1000);
238 }
239
240 /*
241 * Set the CLOEXEC flag. Return code is useless because
242 * either way, the show must go on.
243 */
244 (void) utils_set_fd_cloexec(sock);
245
246 /* Create UST registration command for enqueuing */
247 ust_cmd = zmalloc(sizeof(struct ust_command));
248 if (ust_cmd == NULL) {
249 PERROR("ust command zmalloc");
250 ret = close(sock);
251 if (ret) {
252 PERROR("close");
253 }
254 goto error;
255 }
256
257 /*
258 * Using message-based transmissions to ensure we don't
259 * have to deal with partially received messages.
260 */
261 ret = lttng_fd_get(LTTNG_FD_APPS, 1);
262 if (ret < 0) {
263 ERR("Exhausted file descriptors allowed for applications.");
264 free(ust_cmd);
265 ret = close(sock);
266 if (ret) {
267 PERROR("close");
268 }
269 sock = -1;
270 continue;
271 }
272
273 health_code_update();
274 ret = ust_app_recv_registration(sock, &ust_cmd->reg_msg);
275 if (ret < 0) {
276 free(ust_cmd);
277 /* Close socket of the application. */
278 ret = close(sock);
279 if (ret) {
280 PERROR("close");
281 }
282 lttng_fd_put(LTTNG_FD_APPS, 1);
283 sock = -1;
284 continue;
285 }
286 health_code_update();
287
288 ust_cmd->sock = sock;
289 sock = -1;
290
291 DBG("UST registration received with pid:%d ppid:%d uid:%d"
292 " gid:%d sock:%d name:%s (version %d.%d)",
293 ust_cmd->reg_msg.pid, ust_cmd->reg_msg.ppid,
294 ust_cmd->reg_msg.uid, ust_cmd->reg_msg.gid,
295 ust_cmd->sock, ust_cmd->reg_msg.name,
296 ust_cmd->reg_msg.major, ust_cmd->reg_msg.minor);
297
298 /*
299 * Lock free enqueue the registration request. The red pill
300 * has been taken! This apps will be part of the *system*.
301 */
302 cds_wfcq_enqueue(&notifiers->ust_cmd_queue->head,
303 &notifiers->ust_cmd_queue->tail,
304 &ust_cmd->node);
305
306 /*
307 * Wake the registration queue futex. Implicit memory
308 * barrier with the exchange in cds_wfcq_enqueue.
309 */
310 futex_nto1_wake(&notifiers->ust_cmd_queue->futex);
311 } else if (revents & (LPOLLERR | LPOLLHUP | LPOLLRDHUP)) {
312 ERR("Register apps socket poll error");
313 goto error;
314 } else {
315 ERR("Unexpected poll events %u for sock %d", revents, pollfd);
316 goto error;
317 }
318 }
319 }
320 }
321
322exit:
323error:
324 /* Notify that the registration thread is gone */
325 notify_ust_apps(0, is_root);
326
327 if (apps_sock >= 0) {
328 ret = close(apps_sock);
329 if (ret) {
330 PERROR("close");
331 }
332 }
333 if (sock >= 0) {
334 ret = close(sock);
335 if (ret) {
336 PERROR("close");
337 }
338 lttng_fd_put(LTTNG_FD_APPS, 1);
339 }
340 unlink(config.apps_unix_sock_path.value);
341
342error_poll_add:
343 lttng_poll_clean(&events);
344error_listen:
345error_create_poll:
346error_testpoint:
347 DBG("UST Registration thread cleanup complete");
348 if (err) {
349 health_error();
350 ERR("Health error occurred in %s", __func__);
351 }
352 health_unregister(health_sessiond);
353 return NULL;
354}
355
356static bool shutdown_application_registration_thread(void *data)
357{
358 struct thread_notifiers *notifiers = data;
359 const int write_fd = lttng_pipe_get_writefd(notifiers->quit_pipe);
360
361 return notify_thread_pipe(write_fd) == 1;
362}
363
bd9addf7 364struct lttng_thread *launch_application_registration_thread(
1785d7f2
JG
365 struct ust_cmd_queue *cmd_queue)
366{
367 struct lttng_pipe *quit_pipe;
368 struct thread_notifiers *notifiers = NULL;
369 struct lttng_thread *thread;
370
371 quit_pipe = lttng_pipe_open(FD_CLOEXEC);
372 if (!quit_pipe) {
373 goto error;
374 }
375
376 notifiers = zmalloc(sizeof(*notifiers));
377 if (!notifiers) {
378 goto error;
379 }
380 notifiers->quit_pipe = quit_pipe;
381 notifiers->ust_cmd_queue = cmd_queue;
382
383 thread = lttng_thread_create("UST application registration",
384 thread_application_registration,
385 shutdown_application_registration_thread,
386 cleanup_application_registration_thread,
387 notifiers);
388 if (!thread) {
389 goto error;
390 }
bd9addf7 391 return thread;
1785d7f2
JG
392error:
393 cleanup_application_registration_thread(notifiers);
bd9addf7 394 return NULL;
1785d7f2 395}
This page took 0.056979 seconds and 4 git commands to generate.