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