Add LOG4J2 domain to the Log4j 2.x agent
[lttng-ust.git] / src / common / ringbuffer / shm.c
CommitLineData
1d498196 1/*
c0c0989a 2 * SPDX-License-Identifier: LGPL-2.1-only
1d498196 3 *
e92f3e28 4 * Copyright (C) 2005-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
1d498196
MD
5 */
6
3fbec7dc 7#define _LGPL_SOURCE
1d498196
MD
8#include "shm.h"
9#include <unistd.h>
10#include <fcntl.h>
11#include <sys/mman.h>
a9ff648c 12#include <sys/types.h>
1d498196
MD
13#include <sys/stat.h> /* For mode constants */
14#include <fcntl.h> /* For O_* constants */
15#include <assert.h>
8da6cd6d
MD
16#include <stdio.h>
17#include <signal.h>
18#include <dirent.h>
96e80018 19#include <limits.h>
8a208943 20#include <stdbool.h>
fb31eb73 21#include <stdint.h>
3d3a2bb8 22
bfcda6ce 23#ifdef HAVE_LIBNUMA
4b68c31f 24#include <numa.h>
8a208943 25#include <numaif.h>
bfcda6ce 26#endif
3d3a2bb8 27
eae3c729 28#include <lttng/ust-utils.h>
3d3a2bb8 29
9d315d6d
MJ
30#include "common/macros.h"
31#include "common/ust-fd.h"
1be43539 32#include "common/compat/mmap.h"
3a81f31d
MD
33
34/*
35 * Ensure we have the required amount of space available by writing 0
36 * into the entire buffer. Not doing so can trigger SIGBUS when going
37 * beyond the available shm space.
38 */
39static
40int zero_file(int fd, size_t len)
41{
42 ssize_t retlen;
43 size_t written = 0;
44 char *zeropage;
45 long pagelen;
46 int ret;
47
48 pagelen = sysconf(_SC_PAGESIZE);
49 if (pagelen < 0)
50 return (int) pagelen;
51 zeropage = calloc(pagelen, 1);
52 if (!zeropage)
53 return -ENOMEM;
54
55 while (len > written) {
56 do {
57 retlen = write(fd, zeropage,
58 min_t(size_t, pagelen, len - written));
59 } while (retlen == -1UL && errno == EINTR);
60 if (retlen < 0) {
61 ret = (int) retlen;
62 goto error;
63 }
64 written += retlen;
65 }
66 ret = 0;
67error:
68 free(zeropage);
69 return ret;
70}
1d498196
MD
71
72struct shm_object_table *shm_object_table_create(size_t max_nb_obj)
73{
74 struct shm_object_table *table;
75
76 table = zmalloc(sizeof(struct shm_object_table) +
77 max_nb_obj * sizeof(table->objects[0]));
74d48abe
MD
78 if (!table)
79 return NULL;
1d498196
MD
80 table->size = max_nb_obj;
81 return table;
82}
83
74d81a6c
MD
84static
85struct shm_object *_shm_object_table_alloc_shm(struct shm_object_table *table,
a9ff648c 86 size_t memory_map_size,
5ea386c3 87 int stream_fd)
1d498196 88{
5ea386c3 89 int shmfd, waitfd[2], ret, i;
1d498196
MD
90 struct shm_object *obj;
91 char *memory_map;
92
5ea386c3
MD
93 if (stream_fd < 0)
94 return NULL;
1d498196
MD
95 if (table->allocated_len >= table->size)
96 return NULL;
7a9c21bd 97 obj = &table->objects[table->allocated_len];
1d498196
MD
98
99 /* wait_fd: create pipe */
100 ret = pipe(waitfd);
101 if (ret < 0) {
102 PERROR("pipe");
103 goto error_pipe;
104 }
105 for (i = 0; i < 2; i++) {
106 ret = fcntl(waitfd[i], F_SETFD, FD_CLOEXEC);
107 if (ret < 0) {
108 PERROR("fcntl");
109 goto error_fcntl;
110 }
111 }
5d61a504
MD
112 /* The write end of the pipe needs to be non-blocking */
113 ret = fcntl(waitfd[1], F_SETFL, O_NONBLOCK);
114 if (ret < 0) {
115 PERROR("fcntl");
116 goto error_fcntl;
117 }
7a9c21bd 118 memcpy(obj->wait_fd, waitfd, sizeof(waitfd));
1d498196 119
053e6e24
MJ
120 /*
121 * Set POSIX shared memory object size
122 *
123 * First, use ftruncate() to set its size, some implementations won't
124 * allow writes past the size set by ftruncate.
125 * Then, use write() to fill it with zeros, this allows us to fully
126 * allocate it and detect a shortage of shm space without dealing with
127 * a SIGBUS.
128 */
a9ff648c 129
5ea386c3 130 shmfd = stream_fd;
1d498196
MD
131 ret = ftruncate(shmfd, memory_map_size);
132 if (ret) {
133 PERROR("ftruncate");
134 goto error_ftruncate;
135 }
053e6e24
MJ
136 ret = zero_file(shmfd, memory_map_size);
137 if (ret) {
138 PERROR("zero_file");
139 goto error_zero_file;
140 }
71be0c53 141
d0f6cf57
MD
142 /*
143 * Also ensure the file metadata is synced with the storage by using
71be0c53
MJ
144 * fsync(2). Some platforms don't allow fsync on POSIX shm fds, ignore
145 * EINVAL accordingly.
d0f6cf57
MD
146 */
147 ret = fsync(shmfd);
71be0c53 148 if (ret && errno != EINVAL) {
d0f6cf57
MD
149 PERROR("fsync");
150 goto error_fsync;
151 }
5ea386c3 152 obj->shm_fd_ownership = 0;
1d498196
MD
153 obj->shm_fd = shmfd;
154
155 /* memory_map: mmap */
156 memory_map = mmap(NULL, memory_map_size, PROT_READ | PROT_WRITE,
4d4838ba 157 MAP_SHARED | LTTNG_MAP_POPULATE, shmfd, 0);
1d498196
MD
158 if (memory_map == MAP_FAILED) {
159 PERROR("mmap");
160 goto error_mmap;
161 }
74d81a6c 162 obj->type = SHM_OBJECT_SHM;
1d498196
MD
163 obj->memory_map = memory_map;
164 obj->memory_map_size = memory_map_size;
165 obj->allocated_len = 0;
dc613eb9 166 obj->index = table->allocated_len++;
7a9c21bd 167
1d498196
MD
168 return obj;
169
170error_mmap:
d0f6cf57 171error_fsync:
1d498196 172error_ftruncate:
3a81f31d 173error_zero_file:
1d498196
MD
174error_fcntl:
175 for (i = 0; i < 2; i++) {
176 ret = close(waitfd[i]);
177 if (ret) {
178 PERROR("close");
179 assert(0);
180 }
181 }
182error_pipe:
1d498196 183 return NULL;
1d498196
MD
184}
185
74d81a6c
MD
186static
187struct shm_object *_shm_object_table_alloc_mem(struct shm_object_table *table,
188 size_t memory_map_size)
189{
190 struct shm_object *obj;
191 void *memory_map;
ff0f5728 192 int waitfd[2], i, ret;
74d81a6c
MD
193
194 if (table->allocated_len >= table->size)
195 return NULL;
196 obj = &table->objects[table->allocated_len];
197
198 memory_map = zmalloc(memory_map_size);
199 if (!memory_map)
200 goto alloc_error;
201
ff0f5728
MD
202 /* wait_fd: create pipe */
203 ret = pipe(waitfd);
204 if (ret < 0) {
205 PERROR("pipe");
206 goto error_pipe;
207 }
208 for (i = 0; i < 2; i++) {
209 ret = fcntl(waitfd[i], F_SETFD, FD_CLOEXEC);
210 if (ret < 0) {
211 PERROR("fcntl");
212 goto error_fcntl;
213 }
214 }
215 /* The write end of the pipe needs to be non-blocking */
216 ret = fcntl(waitfd[1], F_SETFL, O_NONBLOCK);
217 if (ret < 0) {
218 PERROR("fcntl");
219 goto error_fcntl;
220 }
221 memcpy(obj->wait_fd, waitfd, sizeof(waitfd));
222
223 /* no shm_fd */
74d81a6c 224 obj->shm_fd = -1;
5ea386c3 225 obj->shm_fd_ownership = 0;
74d81a6c
MD
226
227 obj->type = SHM_OBJECT_MEM;
228 obj->memory_map = memory_map;
229 obj->memory_map_size = memory_map_size;
230 obj->allocated_len = 0;
231 obj->index = table->allocated_len++;
232
233 return obj;
234
ff0f5728
MD
235error_fcntl:
236 for (i = 0; i < 2; i++) {
237 ret = close(waitfd[i]);
238 if (ret) {
239 PERROR("close");
240 assert(0);
241 }
242 }
243error_pipe:
244 free(memory_map);
74d81a6c
MD
245alloc_error:
246 return NULL;
247}
248
8a208943
MD
249/*
250 * libnuma prints errors on the console even for numa_available().
251 * Work-around this limitation by using get_mempolicy() directly to
252 * check whether the kernel supports mempolicy.
253 */
254#ifdef HAVE_LIBNUMA
255static bool lttng_is_numa_available(void)
256{
257 int ret;
258
259 ret = get_mempolicy(NULL, NULL, 0, NULL, 0);
260 if (ret && errno == ENOSYS) {
261 return false;
262 }
263 return numa_available() > 0;
264}
265#endif
266
c494c0f1 267#ifdef HAVE_LIBNUMA
74d81a6c
MD
268struct shm_object *shm_object_table_alloc(struct shm_object_table *table,
269 size_t memory_map_size,
a9ff648c 270 enum shm_object_type type,
4b68c31f
MD
271 int stream_fd,
272 int cpu)
c494c0f1
MJ
273#else
274struct shm_object *shm_object_table_alloc(struct shm_object_table *table,
275 size_t memory_map_size,
276 enum shm_object_type type,
277 int stream_fd,
278 int cpu __attribute__((unused)))
279#endif
74d81a6c 280{
4b68c31f 281 struct shm_object *shm_object;
bfcda6ce 282#ifdef HAVE_LIBNUMA
8a208943
MD
283 int oldnode = 0, node;
284 bool numa_avail;
4b68c31f 285
8a208943
MD
286 numa_avail = lttng_is_numa_available();
287 if (numa_avail) {
288 oldnode = numa_preferred();
289 if (cpu >= 0) {
290 node = numa_node_of_cpu(cpu);
291 if (node >= 0)
292 numa_set_preferred(node);
293 }
294 if (cpu < 0 || node < 0)
295 numa_set_localalloc();
4b68c31f 296 }
bfcda6ce 297#endif /* HAVE_LIBNUMA */
74d81a6c
MD
298 switch (type) {
299 case SHM_OBJECT_SHM:
4b68c31f 300 shm_object = _shm_object_table_alloc_shm(table, memory_map_size,
5ea386c3 301 stream_fd);
4b68c31f 302 break;
74d81a6c 303 case SHM_OBJECT_MEM:
4b68c31f
MD
304 shm_object = _shm_object_table_alloc_mem(table, memory_map_size);
305 break;
74d81a6c
MD
306 default:
307 assert(0);
308 }
bfcda6ce 309#ifdef HAVE_LIBNUMA
8a208943
MD
310 if (numa_avail)
311 numa_set_preferred(oldnode);
bfcda6ce 312#endif /* HAVE_LIBNUMA */
4b68c31f 313 return shm_object;
74d81a6c
MD
314}
315
316struct shm_object *shm_object_table_append_shm(struct shm_object_table *table,
317 int shm_fd, int wakeup_fd, uint32_t stream_nr,
318 size_t memory_map_size)
193183fb
MD
319{
320 struct shm_object *obj;
321 char *memory_map;
74d81a6c 322 int ret;
193183fb
MD
323
324 if (table->allocated_len >= table->size)
325 return NULL;
74d81a6c
MD
326 /* streams _must_ be received in sequential order, else fail. */
327 if (stream_nr + 1 != table->allocated_len)
328 return NULL;
329
193183fb
MD
330 obj = &table->objects[table->allocated_len];
331
74d81a6c
MD
332 /* wait_fd: set write end of the pipe. */
333 obj->wait_fd[0] = -1; /* read end is unset */
334 obj->wait_fd[1] = wakeup_fd;
193183fb 335 obj->shm_fd = shm_fd;
5ea386c3 336 obj->shm_fd_ownership = 1;
193183fb 337
74d81a6c
MD
338 /* The write end of the pipe needs to be non-blocking */
339 ret = fcntl(obj->wait_fd[1], F_SETFL, O_NONBLOCK);
340 if (ret < 0) {
341 PERROR("fcntl");
342 goto error_fcntl;
343 }
344
193183fb
MD
345 /* memory_map: mmap */
346 memory_map = mmap(NULL, memory_map_size, PROT_READ | PROT_WRITE,
4d4838ba 347 MAP_SHARED | LTTNG_MAP_POPULATE, shm_fd, 0);
193183fb
MD
348 if (memory_map == MAP_FAILED) {
349 PERROR("mmap");
350 goto error_mmap;
351 }
74d81a6c 352 obj->type = SHM_OBJECT_SHM;
193183fb
MD
353 obj->memory_map = memory_map;
354 obj->memory_map_size = memory_map_size;
355 obj->allocated_len = memory_map_size;
356 obj->index = table->allocated_len++;
357
358 return obj;
359
74d81a6c 360error_fcntl:
193183fb
MD
361error_mmap:
362 return NULL;
363}
364
74d81a6c
MD
365/*
366 * Passing ownership of mem to object.
367 */
368struct shm_object *shm_object_table_append_mem(struct shm_object_table *table,
ff0f5728 369 void *mem, size_t memory_map_size, int wakeup_fd)
74d81a6c
MD
370{
371 struct shm_object *obj;
ff0f5728 372 int ret;
74d81a6c
MD
373
374 if (table->allocated_len >= table->size)
375 return NULL;
376 obj = &table->objects[table->allocated_len];
377
ff0f5728
MD
378 obj->wait_fd[0] = -1; /* read end is unset */
379 obj->wait_fd[1] = wakeup_fd;
74d81a6c 380 obj->shm_fd = -1;
5ea386c3 381 obj->shm_fd_ownership = 0;
74d81a6c 382
ff0f5728
MD
383 ret = fcntl(obj->wait_fd[1], F_SETFD, FD_CLOEXEC);
384 if (ret < 0) {
385 PERROR("fcntl");
386 goto error_fcntl;
387 }
388 /* The write end of the pipe needs to be non-blocking */
389 ret = fcntl(obj->wait_fd[1], F_SETFL, O_NONBLOCK);
390 if (ret < 0) {
391 PERROR("fcntl");
392 goto error_fcntl;
393 }
394
74d81a6c
MD
395 obj->type = SHM_OBJECT_MEM;
396 obj->memory_map = mem;
397 obj->memory_map_size = memory_map_size;
398 obj->allocated_len = memory_map_size;
399 obj->index = table->allocated_len++;
400
401 return obj;
ff0f5728
MD
402
403error_fcntl:
404 return NULL;
74d81a6c
MD
405}
406
1d498196 407static
6548fca4 408void shmp_object_destroy(struct shm_object *obj, int consumer)
1d498196 409{
74d81a6c
MD
410 switch (obj->type) {
411 case SHM_OBJECT_SHM:
412 {
413 int ret, i;
1d498196 414
7a784989
MD
415 ret = munmap(obj->memory_map, obj->memory_map_size);
416 if (ret) {
417 PERROR("umnmap");
418 assert(0);
419 }
6548fca4 420
5ea386c3 421 if (obj->shm_fd_ownership) {
6548fca4
MD
422 /* Delete FDs only if called from app (not consumer). */
423 if (!consumer) {
424 lttng_ust_lock_fd_tracker();
425 ret = close(obj->shm_fd);
426 if (!ret) {
427 lttng_ust_delete_fd_from_tracker(obj->shm_fd);
428 } else {
429 PERROR("close");
430 assert(0);
431 }
432 lttng_ust_unlock_fd_tracker();
433 } else {
434 ret = close(obj->shm_fd);
435 if (ret) {
436 PERROR("close");
437 assert(0);
438 }
a9ff648c
MD
439 }
440 }
74d81a6c
MD
441 for (i = 0; i < 2; i++) {
442 if (obj->wait_fd[i] < 0)
443 continue;
6548fca4
MD
444 if (!consumer) {
445 lttng_ust_lock_fd_tracker();
446 ret = close(obj->wait_fd[i]);
447 if (!ret) {
448 lttng_ust_delete_fd_from_tracker(obj->wait_fd[i]);
449 } else {
450 PERROR("close");
451 assert(0);
452 }
453 lttng_ust_unlock_fd_tracker();
454 } else {
455 ret = close(obj->wait_fd[i]);
456 if (ret) {
457 PERROR("close");
458 assert(0);
459 }
74d81a6c 460 }
1d498196 461 }
74d81a6c
MD
462 break;
463 }
464 case SHM_OBJECT_MEM:
ff0f5728
MD
465 {
466 int ret, i;
467
468 for (i = 0; i < 2; i++) {
469 if (obj->wait_fd[i] < 0)
470 continue;
6548fca4
MD
471 if (!consumer) {
472 lttng_ust_lock_fd_tracker();
473 ret = close(obj->wait_fd[i]);
474 if (!ret) {
475 lttng_ust_delete_fd_from_tracker(obj->wait_fd[i]);
476 } else {
477 PERROR("close");
478 assert(0);
479 }
480 lttng_ust_unlock_fd_tracker();
481 } else {
482 ret = close(obj->wait_fd[i]);
483 if (ret) {
484 PERROR("close");
485 assert(0);
486 }
ff0f5728
MD
487 }
488 }
74d81a6c
MD
489 free(obj->memory_map);
490 break;
ff0f5728 491 }
74d81a6c
MD
492 default:
493 assert(0);
1d498196
MD
494 }
495}
496
6548fca4 497void shm_object_table_destroy(struct shm_object_table *table, int consumer)
1d498196
MD
498{
499 int i;
500
501 for (i = 0; i < table->allocated_len; i++)
6548fca4 502 shmp_object_destroy(&table->objects[i], consumer);
1d498196
MD
503 free(table);
504}
505
506/*
507 * zalloc_shm - allocate memory within a shm object.
508 *
509 * Shared memory is already zeroed by shmget.
510 * *NOT* multithread-safe (should be protected by mutex).
511 * Returns a -1, -1 tuple on error.
512 */
513struct shm_ref zalloc_shm(struct shm_object *obj, size_t len)
514{
515 struct shm_ref ref;
516 struct shm_ref shm_ref_error = { -1, -1 };
517
518 if (obj->memory_map_size - obj->allocated_len < len)
519 return shm_ref_error;
520 ref.index = obj->index;
521 ref.offset = obj->allocated_len;
522 obj->allocated_len += len;
523 return ref;
524}
525
526void align_shm(struct shm_object *obj, size_t align)
527{
b72687b8 528 size_t offset_len = lttng_ust_offset_align(obj->allocated_len, align);
1d498196
MD
529 obj->allocated_len += offset_len;
530}
This page took 0.060281 seconds and 4 git commands to generate.