Cleanup: Move `create_posix_shm()` to common/shm.c
[lttng-tools.git] / src / bin / lttng-sessiond / register.c
1 /*
2 * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
3 * Copyright (C) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 * Copyright (C) 2013 Jérémie Galarneau <jeremie.galarneau@efficios.com>
5 *
6 * SPDX-License-Identifier: GPL-2.0-only
7 *
8 */
9
10 #include <stddef.h>
11 #include <stdlib.h>
12 #include <urcu.h>
13 #include <common/futex.h>
14 #include <common/macros.h>
15 #include <common/shm.h>
16 #include <common/utils.h>
17 #include <sys/stat.h>
18
19 #include "register.h"
20 #include "lttng-sessiond.h"
21 #include "testpoint.h"
22 #include "health-sessiond.h"
23 #include "fd-limit.h"
24 #include "utils.h"
25 #include "thread.h"
26
27 struct thread_state {
28 struct lttng_pipe *quit_pipe;
29 struct ust_cmd_queue *ust_cmd_queue;
30 sem_t ready;
31 bool running;
32 int application_socket;
33 };
34
35 /*
36 * Creates the application socket.
37 */
38 static int create_application_socket(void)
39 {
40 int ret = 0;
41 int apps_sock;
42 const mode_t old_umask = umask(0);
43
44 /* Create the application unix socket */
45 apps_sock = lttcomm_create_unix_sock(config.apps_unix_sock_path.value);
46 if (apps_sock < 0) {
47 ERR("Create unix sock failed: %s", config.apps_unix_sock_path.value);
48 ret = -1;
49 goto end;
50 }
51
52 /* Set the cloexec flag */
53 ret = utils_set_fd_cloexec(apps_sock);
54 if (ret < 0) {
55 ERR("Unable to set CLOEXEC flag to the app Unix socket (fd: %d). "
56 "Continuing but note that the consumer daemon will have a "
57 "reference to this socket on exec()", apps_sock);
58 }
59
60 /* File permission MUST be 666 */
61 ret = chmod(config.apps_unix_sock_path.value,
62 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
63 if (ret < 0) {
64 PERROR("Set file permissions failed on %s",
65 config.apps_unix_sock_path.value);
66 goto error_close_socket;
67 }
68
69 DBG3("Session daemon application socket created (fd = %d) ", apps_sock);
70 ret = apps_sock;
71 end:
72 umask(old_umask);
73 return ret;
74 error_close_socket:
75 if (close(apps_sock)) {
76 PERROR("Failed to close application socket in error path");
77 }
78 apps_sock = -1;
79 ret = -1;
80 goto end;
81 }
82
83 /*
84 * Notify UST applications using the shm mmap futex.
85 */
86 static 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
104 error:
105 return -1;
106 }
107
108 static void cleanup_application_registration_thread(void *data)
109 {
110 struct thread_state *thread_state = data;
111
112 if (!data) {
113 return;
114 }
115
116 lttng_pipe_destroy(thread_state->quit_pipe);
117 free(thread_state);
118 }
119
120 static void set_thread_status(struct thread_state *thread_state, bool running)
121 {
122 DBG("Marking application registration thread's state as %s", running ? "running" : "error");
123 thread_state->running = running;
124 sem_post(&thread_state->ready);
125 }
126
127 static bool wait_thread_status(struct thread_state *thread_state)
128 {
129 DBG("Waiting for application registration thread to be ready");
130 sem_wait(&thread_state->ready);
131 if (thread_state->running) {
132 DBG("Application registration thread is ready");
133 } else {
134 ERR("Initialization of application registration thread failed");
135 }
136
137 return thread_state->running;
138 }
139
140 static void thread_init_cleanup(void *data)
141 {
142 struct thread_state *thread_state = data;
143
144 set_thread_status(thread_state, false);
145 }
146
147 /*
148 * This thread manage application registration.
149 */
150 static void *thread_application_registration(void *data)
151 {
152 int sock = -1, i, ret, pollfd, err = -1;
153 uint32_t revents, nb_fd;
154 struct lttng_poll_event events;
155 /*
156 * Gets allocated in this thread, enqueued to a global queue, dequeued
157 * and freed in the manage apps thread.
158 */
159 struct ust_command *ust_cmd = NULL;
160 const bool is_root = (getuid() == 0);
161 struct thread_state *thread_state = data;
162 const int application_socket = thread_state->application_socket;
163 const int quit_pipe_read_fd = lttng_pipe_get_readfd(
164 thread_state->quit_pipe);
165
166 DBG("[thread] Manage application registration started");
167
168 pthread_cleanup_push(thread_init_cleanup, thread_state);
169 health_register(health_sessiond, HEALTH_SESSIOND_TYPE_APP_REG);
170
171 ret = lttcomm_listen_unix_sock(application_socket);
172 if (ret < 0) {
173 goto error_listen;
174 }
175
176 /*
177 * Pass 2 as size here for the thread quit pipe and apps_sock. Nothing
178 * more will be added to this poll set.
179 */
180 ret = lttng_poll_create(&events, 2, LTTNG_CLOEXEC);
181 if (ret < 0) {
182 goto error_create_poll;
183 }
184
185 /* Add the application registration socket */
186 ret = lttng_poll_add(&events, application_socket, LPOLLIN | LPOLLRDHUP);
187 if (ret < 0) {
188 goto error_poll_add;
189 }
190
191 /* Add the application registration socket */
192 ret = lttng_poll_add(&events, quit_pipe_read_fd, LPOLLIN | LPOLLRDHUP);
193 if (ret < 0) {
194 goto error_poll_add;
195 }
196
197 set_thread_status(thread_state, true);
198 pthread_cleanup_pop(0);
199
200 if (testpoint(sessiond_thread_registration_apps)) {
201 goto error_poll_add;
202 }
203
204 while (1) {
205 DBG("Accepting application registration");
206
207 /* Inifinite blocking call, waiting for transmission */
208 restart:
209 health_poll_entry();
210 ret = lttng_poll_wait(&events, -1);
211 health_poll_exit();
212 if (ret < 0) {
213 /*
214 * Restart interrupted system call.
215 */
216 if (errno == EINTR) {
217 goto restart;
218 }
219 goto error;
220 }
221
222 nb_fd = ret;
223
224 for (i = 0; i < nb_fd; i++) {
225 health_code_update();
226
227 /* Fetch once the poll data */
228 revents = LTTNG_POLL_GETEV(&events, i);
229 pollfd = LTTNG_POLL_GETFD(&events, i);
230
231 /* Thread quit pipe has been closed. Killing thread. */
232 if (pollfd == quit_pipe_read_fd) {
233 err = 0;
234 goto exit;
235 } else {
236 /* Event on the registration socket */
237 if (revents & LPOLLIN) {
238 sock = lttcomm_accept_unix_sock(application_socket);
239 if (sock < 0) {
240 goto error;
241 }
242
243 /*
244 * Set socket timeout for both receiving and ending.
245 * app_socket_timeout is in seconds, whereas
246 * lttcomm_setsockopt_rcv_timeout and
247 * lttcomm_setsockopt_snd_timeout expect msec as
248 * parameter.
249 */
250 if (config.app_socket_timeout >= 0) {
251 (void) lttcomm_setsockopt_rcv_timeout(sock,
252 config.app_socket_timeout * 1000);
253 (void) lttcomm_setsockopt_snd_timeout(sock,
254 config.app_socket_timeout * 1000);
255 }
256
257 /*
258 * Set the CLOEXEC flag. Return code is useless because
259 * either way, the show must go on.
260 */
261 (void) utils_set_fd_cloexec(sock);
262
263 /* Create UST registration command for enqueuing */
264 ust_cmd = zmalloc(sizeof(struct ust_command));
265 if (ust_cmd == NULL) {
266 PERROR("ust command zmalloc");
267 ret = close(sock);
268 if (ret) {
269 PERROR("close");
270 }
271 sock = -1;
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(&thread_state->ust_cmd_queue->head,
321 &thread_state->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(&thread_state->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
340 exit:
341 error:
342 /* Notify that the registration thread is gone */
343 notify_ust_apps(0, is_root);
344
345 ret = close(application_socket);
346 if (ret) {
347 PERROR("Failed to close application registration socket");
348 }
349 if (sock >= 0) {
350 ret = close(sock);
351 if (ret) {
352 PERROR("Failed to close application socket");
353 }
354 lttng_fd_put(LTTNG_FD_APPS, 1);
355 }
356 unlink(config.apps_unix_sock_path.value);
357
358 error_poll_add:
359 lttng_poll_clean(&events);
360 error_listen:
361 error_create_poll:
362 DBG("UST Registration thread cleanup complete");
363 if (err) {
364 health_error();
365 ERR("Health error occurred in %s", __func__);
366 }
367 health_unregister(health_sessiond);
368 return NULL;
369 }
370
371 static bool shutdown_application_registration_thread(void *data)
372 {
373 struct thread_state *thread_state = data;
374 const int write_fd = lttng_pipe_get_writefd(thread_state->quit_pipe);
375
376 return notify_thread_pipe(write_fd) == 1;
377 }
378
379 struct lttng_thread *launch_application_registration_thread(
380 struct ust_cmd_queue *cmd_queue)
381 {
382 int ret;
383 struct lttng_pipe *quit_pipe;
384 struct thread_state *thread_state = NULL;
385 struct lttng_thread *thread = NULL;
386 const bool is_root = (getuid() == 0);
387 int application_socket = -1;
388
389 thread_state = zmalloc(sizeof(*thread_state));
390 if (!thread_state) {
391 goto error_alloc;
392 }
393 quit_pipe = lttng_pipe_open(FD_CLOEXEC);
394 if (!quit_pipe) {
395 goto error;
396 }
397 thread_state->quit_pipe = quit_pipe;
398 thread_state->ust_cmd_queue = cmd_queue;
399 application_socket = create_application_socket();
400 if (application_socket < 0) {
401 goto error;
402 }
403 thread_state->application_socket = application_socket;
404 sem_init(&thread_state->ready, 0, 0);
405
406 thread = lttng_thread_create("UST application registration",
407 thread_application_registration,
408 shutdown_application_registration_thread,
409 cleanup_application_registration_thread,
410 thread_state);
411 if (!thread) {
412 goto error;
413 }
414 /*
415 * The application registration thread now owns the application socket
416 * and the global thread state. The thread state is used to wait for
417 * the thread's status, but its ownership now belongs to the thread.
418 */
419 application_socket = -1;
420 if (!wait_thread_status(thread_state)) {
421 thread_state = NULL;
422 goto error;
423 }
424
425 /* Notify all applications to register. */
426 ret = notify_ust_apps(1, is_root);
427 if (ret < 0) {
428 ERR("Failed to notify applications or create the wait shared memory.\n"
429 "Execution continues but there might be problems for already\n"
430 "running applications that wishes to register.");
431 }
432
433 return thread;
434 error:
435 lttng_thread_put(thread);
436 cleanup_application_registration_thread(thread_state);
437 if (application_socket >= 0) {
438 if (close(application_socket)) {
439 PERROR("Failed to close application registration socket");
440 }
441 }
442 error_alloc:
443 return NULL;
444 }
This page took 0.056866 seconds and 4 git commands to generate.