Fix: add missing NULL check after allocation
[lttng-ust.git] / libringbuffer / shm.c
CommitLineData
1d498196
MD
1/*
2 * libringbuffer/shm.c
3 *
e92f3e28 4 * Copyright (C) 2005-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
1d498196 5 *
e92f3e28
MD
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; only
9 * version 2.1 of the License.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1d498196
MD
19 */
20
21#include "shm.h"
22#include <unistd.h>
23#include <fcntl.h>
24#include <sys/mman.h>
25#include <sys/stat.h> /* For mode constants */
26#include <fcntl.h> /* For O_* constants */
27#include <assert.h>
8da6cd6d
MD
28#include <stdio.h>
29#include <signal.h>
30#include <dirent.h>
4318ae1b 31#include <lttng/align.h>
35897f8b 32#include <helper.h>
96e80018 33#include <limits.h>
3a81f31d
MD
34#include <helper.h>
35
36/*
37 * Ensure we have the required amount of space available by writing 0
38 * into the entire buffer. Not doing so can trigger SIGBUS when going
39 * beyond the available shm space.
40 */
41static
42int zero_file(int fd, size_t len)
43{
44 ssize_t retlen;
45 size_t written = 0;
46 char *zeropage;
47 long pagelen;
48 int ret;
49
50 pagelen = sysconf(_SC_PAGESIZE);
51 if (pagelen < 0)
52 return (int) pagelen;
53 zeropage = calloc(pagelen, 1);
54 if (!zeropage)
55 return -ENOMEM;
56
57 while (len > written) {
58 do {
59 retlen = write(fd, zeropage,
60 min_t(size_t, pagelen, len - written));
61 } while (retlen == -1UL && errno == EINTR);
62 if (retlen < 0) {
63 ret = (int) retlen;
64 goto error;
65 }
66 written += retlen;
67 }
68 ret = 0;
69error:
70 free(zeropage);
71 return ret;
72}
1d498196
MD
73
74struct shm_object_table *shm_object_table_create(size_t max_nb_obj)
75{
76 struct shm_object_table *table;
77
78 table = zmalloc(sizeof(struct shm_object_table) +
79 max_nb_obj * sizeof(table->objects[0]));
911360f6
MD
80 if (!table)
81 return NULL;
1d498196
MD
82 table->size = max_nb_obj;
83 return table;
84}
85
74d81a6c
MD
86static
87struct shm_object *_shm_object_table_alloc_shm(struct shm_object_table *table,
1d498196
MD
88 size_t memory_map_size)
89{
5a61337d 90 int shmfd, waitfd[2], ret, i, sigblocked = 0;
1d498196
MD
91 struct shm_object *obj;
92 char *memory_map;
dda4784f 93 char tmp_name[NAME_MAX] = "/ust-shm-tmp-XXXXXX";
8da6cd6d 94 sigset_t all_sigs, orig_sigs;
1d498196
MD
95
96 if (table->allocated_len >= table->size)
97 return NULL;
7a9c21bd 98 obj = &table->objects[table->allocated_len];
1d498196
MD
99
100 /* wait_fd: create pipe */
101 ret = pipe(waitfd);
102 if (ret < 0) {
103 PERROR("pipe");
104 goto error_pipe;
105 }
106 for (i = 0; i < 2; i++) {
107 ret = fcntl(waitfd[i], F_SETFD, FD_CLOEXEC);
108 if (ret < 0) {
109 PERROR("fcntl");
110 goto error_fcntl;
111 }
112 }
5d61a504
MD
113 /* The write end of the pipe needs to be non-blocking */
114 ret = fcntl(waitfd[1], F_SETFL, O_NONBLOCK);
115 if (ret < 0) {
116 PERROR("fcntl");
117 goto error_fcntl;
118 }
7a9c21bd 119 memcpy(obj->wait_fd, waitfd, sizeof(waitfd));
1d498196
MD
120
121 /* shm_fd: create shm */
122
8da6cd6d
MD
123 /*
124 * Theoretically, we could leak a shm if the application crashes
125 * between open and unlink. Disable signals on this thread for
126 * increased safety against this scenario.
127 */
128 sigfillset(&all_sigs);
129 ret = pthread_sigmask(SIG_BLOCK, &all_sigs, &orig_sigs);
130 if (ret == -1) {
131 PERROR("pthread_sigmask");
132 goto error_pthread_sigmask;
133 }
5a61337d 134 sigblocked = 1;
8da6cd6d 135
1d498196
MD
136 /*
137 * Allocate shm, and immediately unlink its shm oject, keeping
138 * only the file descriptor as a reference to the object. If it
139 * already exists (caused by short race window during which the
140 * global object exists in a concurrent shm_open), simply retry.
141 * We specifically do _not_ use the / at the beginning of the
142 * pathname so that some OS implementations can keep it local to
143 * the process (POSIX leaves this implementation-defined).
144 */
145 do {
8da6cd6d
MD
146 /*
147 * Using mktemp filename with O_CREAT | O_EXCL open
148 * flags.
149 */
af21f781 150 (void) mktemp(tmp_name);
8da6cd6d
MD
151 if (tmp_name[0] == '\0') {
152 PERROR("mktemp");
153 goto error_shm_open;
a8803897 154 }
8da6cd6d 155 shmfd = shm_open(tmp_name,
1d498196 156 O_CREAT | O_EXCL | O_RDWR, 0700);
8da6cd6d 157 } while (shmfd < 0 && (errno == EEXIST || errno == EACCES));
1d498196
MD
158 if (shmfd < 0) {
159 PERROR("shm_open");
160 goto error_shm_open;
161 }
8da6cd6d 162 ret = shm_unlink(tmp_name);
a8803897
MD
163 if (ret < 0 && errno != ENOENT) {
164 PERROR("shm_unlink");
165 goto error_shm_release;
166 }
5a61337d 167 sigblocked = 0;
8da6cd6d
MD
168 ret = pthread_sigmask(SIG_SETMASK, &orig_sigs, NULL);
169 if (ret == -1) {
170 PERROR("pthread_sigmask");
5a61337d 171 goto error_sigmask_release;
8da6cd6d 172 }
3a81f31d
MD
173 ret = zero_file(shmfd, memory_map_size);
174 if (ret) {
175 PERROR("zero_file");
176 goto error_zero_file;
177 }
1d498196
MD
178 ret = ftruncate(shmfd, memory_map_size);
179 if (ret) {
180 PERROR("ftruncate");
181 goto error_ftruncate;
182 }
183 obj->shm_fd = shmfd;
184
185 /* memory_map: mmap */
186 memory_map = mmap(NULL, memory_map_size, PROT_READ | PROT_WRITE,
187 MAP_SHARED, shmfd, 0);
188 if (memory_map == MAP_FAILED) {
189 PERROR("mmap");
190 goto error_mmap;
191 }
74d81a6c 192 obj->type = SHM_OBJECT_SHM;
1d498196
MD
193 obj->memory_map = memory_map;
194 obj->memory_map_size = memory_map_size;
195 obj->allocated_len = 0;
dc613eb9 196 obj->index = table->allocated_len++;
7a9c21bd 197
1d498196
MD
198 return obj;
199
200error_mmap:
201error_ftruncate:
a8803897 202error_shm_release:
3a81f31d 203error_zero_file:
5a61337d 204error_sigmask_release:
1d498196
MD
205 ret = close(shmfd);
206 if (ret) {
207 PERROR("close");
208 assert(0);
209 }
210error_shm_open:
5a61337d
MD
211 if (sigblocked) {
212 ret = pthread_sigmask(SIG_SETMASK, &orig_sigs, NULL);
213 if (ret == -1) {
214 PERROR("pthread_sigmask");
215 }
216 }
8da6cd6d 217error_pthread_sigmask:
1d498196
MD
218error_fcntl:
219 for (i = 0; i < 2; i++) {
220 ret = close(waitfd[i]);
221 if (ret) {
222 PERROR("close");
223 assert(0);
224 }
225 }
226error_pipe:
1d498196 227 return NULL;
1d498196
MD
228}
229
74d81a6c
MD
230static
231struct shm_object *_shm_object_table_alloc_mem(struct shm_object_table *table,
232 size_t memory_map_size)
233{
234 struct shm_object *obj;
235 void *memory_map;
ff0f5728 236 int waitfd[2], i, ret;
74d81a6c
MD
237
238 if (table->allocated_len >= table->size)
239 return NULL;
240 obj = &table->objects[table->allocated_len];
241
242 memory_map = zmalloc(memory_map_size);
243 if (!memory_map)
244 goto alloc_error;
245
ff0f5728
MD
246 /* wait_fd: create pipe */
247 ret = pipe(waitfd);
248 if (ret < 0) {
249 PERROR("pipe");
250 goto error_pipe;
251 }
252 for (i = 0; i < 2; i++) {
253 ret = fcntl(waitfd[i], F_SETFD, FD_CLOEXEC);
254 if (ret < 0) {
255 PERROR("fcntl");
256 goto error_fcntl;
257 }
258 }
259 /* The write end of the pipe needs to be non-blocking */
260 ret = fcntl(waitfd[1], F_SETFL, O_NONBLOCK);
261 if (ret < 0) {
262 PERROR("fcntl");
263 goto error_fcntl;
264 }
265 memcpy(obj->wait_fd, waitfd, sizeof(waitfd));
266
267 /* no shm_fd */
74d81a6c
MD
268 obj->shm_fd = -1;
269
270 obj->type = SHM_OBJECT_MEM;
271 obj->memory_map = memory_map;
272 obj->memory_map_size = memory_map_size;
273 obj->allocated_len = 0;
274 obj->index = table->allocated_len++;
275
276 return obj;
277
ff0f5728
MD
278error_fcntl:
279 for (i = 0; i < 2; i++) {
280 ret = close(waitfd[i]);
281 if (ret) {
282 PERROR("close");
283 assert(0);
284 }
285 }
286error_pipe:
287 free(memory_map);
74d81a6c
MD
288alloc_error:
289 return NULL;
290}
291
292struct shm_object *shm_object_table_alloc(struct shm_object_table *table,
293 size_t memory_map_size,
294 enum shm_object_type type)
295{
296 switch (type) {
297 case SHM_OBJECT_SHM:
298 return _shm_object_table_alloc_shm(table, memory_map_size);
299 case SHM_OBJECT_MEM:
300 return _shm_object_table_alloc_mem(table, memory_map_size);
301 default:
302 assert(0);
303 }
304 return NULL;
305}
306
307struct shm_object *shm_object_table_append_shm(struct shm_object_table *table,
308 int shm_fd, int wakeup_fd, uint32_t stream_nr,
309 size_t memory_map_size)
193183fb
MD
310{
311 struct shm_object *obj;
312 char *memory_map;
74d81a6c 313 int ret;
193183fb
MD
314
315 if (table->allocated_len >= table->size)
316 return NULL;
74d81a6c
MD
317 /* streams _must_ be received in sequential order, else fail. */
318 if (stream_nr + 1 != table->allocated_len)
319 return NULL;
320
193183fb
MD
321 obj = &table->objects[table->allocated_len];
322
74d81a6c
MD
323 /* wait_fd: set write end of the pipe. */
324 obj->wait_fd[0] = -1; /* read end is unset */
325 obj->wait_fd[1] = wakeup_fd;
193183fb
MD
326 obj->shm_fd = shm_fd;
327
74d81a6c
MD
328 ret = fcntl(obj->wait_fd[1], F_SETFD, FD_CLOEXEC);
329 if (ret < 0) {
330 PERROR("fcntl");
331 goto error_fcntl;
332 }
333 /* The write end of the pipe needs to be non-blocking */
334 ret = fcntl(obj->wait_fd[1], F_SETFL, O_NONBLOCK);
335 if (ret < 0) {
336 PERROR("fcntl");
337 goto error_fcntl;
338 }
339
193183fb
MD
340 /* memory_map: mmap */
341 memory_map = mmap(NULL, memory_map_size, PROT_READ | PROT_WRITE,
342 MAP_SHARED, shm_fd, 0);
343 if (memory_map == MAP_FAILED) {
344 PERROR("mmap");
345 goto error_mmap;
346 }
74d81a6c 347 obj->type = SHM_OBJECT_SHM;
193183fb
MD
348 obj->memory_map = memory_map;
349 obj->memory_map_size = memory_map_size;
350 obj->allocated_len = memory_map_size;
351 obj->index = table->allocated_len++;
352
353 return obj;
354
74d81a6c 355error_fcntl:
193183fb
MD
356error_mmap:
357 return NULL;
358}
359
74d81a6c
MD
360/*
361 * Passing ownership of mem to object.
362 */
363struct shm_object *shm_object_table_append_mem(struct shm_object_table *table,
ff0f5728 364 void *mem, size_t memory_map_size, int wakeup_fd)
74d81a6c
MD
365{
366 struct shm_object *obj;
ff0f5728 367 int ret;
74d81a6c
MD
368
369 if (table->allocated_len >= table->size)
370 return NULL;
371 obj = &table->objects[table->allocated_len];
372
ff0f5728
MD
373 obj->wait_fd[0] = -1; /* read end is unset */
374 obj->wait_fd[1] = wakeup_fd;
74d81a6c
MD
375 obj->shm_fd = -1;
376
ff0f5728
MD
377 ret = fcntl(obj->wait_fd[1], F_SETFD, FD_CLOEXEC);
378 if (ret < 0) {
379 PERROR("fcntl");
380 goto error_fcntl;
381 }
382 /* The write end of the pipe needs to be non-blocking */
383 ret = fcntl(obj->wait_fd[1], F_SETFL, O_NONBLOCK);
384 if (ret < 0) {
385 PERROR("fcntl");
386 goto error_fcntl;
387 }
388
74d81a6c
MD
389 obj->type = SHM_OBJECT_MEM;
390 obj->memory_map = mem;
391 obj->memory_map_size = memory_map_size;
392 obj->allocated_len = memory_map_size;
393 obj->index = table->allocated_len++;
394
395 return obj;
ff0f5728
MD
396
397error_fcntl:
398 return NULL;
74d81a6c
MD
399}
400
1d498196
MD
401static
402void shmp_object_destroy(struct shm_object *obj)
403{
74d81a6c
MD
404 switch (obj->type) {
405 case SHM_OBJECT_SHM:
406 {
407 int ret, i;
1d498196 408
7a784989
MD
409 ret = munmap(obj->memory_map, obj->memory_map_size);
410 if (ret) {
411 PERROR("umnmap");
412 assert(0);
413 }
ef9ff354
MD
414 ret = close(obj->shm_fd);
415 if (ret) {
416 PERROR("close");
417 assert(0);
418 }
74d81a6c
MD
419 for (i = 0; i < 2; i++) {
420 if (obj->wait_fd[i] < 0)
421 continue;
422 ret = close(obj->wait_fd[i]);
423 if (ret) {
424 PERROR("close");
425 assert(0);
426 }
1d498196 427 }
74d81a6c
MD
428 break;
429 }
430 case SHM_OBJECT_MEM:
ff0f5728
MD
431 {
432 int ret, i;
433
434 for (i = 0; i < 2; i++) {
435 if (obj->wait_fd[i] < 0)
436 continue;
437 ret = close(obj->wait_fd[i]);
438 if (ret) {
439 PERROR("close");
440 assert(0);
441 }
442 }
74d81a6c
MD
443 free(obj->memory_map);
444 break;
ff0f5728 445 }
74d81a6c
MD
446 default:
447 assert(0);
1d498196
MD
448 }
449}
450
451void shm_object_table_destroy(struct shm_object_table *table)
452{
453 int i;
454
455 for (i = 0; i < table->allocated_len; i++)
456 shmp_object_destroy(&table->objects[i]);
457 free(table);
458}
459
460/*
461 * zalloc_shm - allocate memory within a shm object.
462 *
463 * Shared memory is already zeroed by shmget.
464 * *NOT* multithread-safe (should be protected by mutex).
465 * Returns a -1, -1 tuple on error.
466 */
467struct shm_ref zalloc_shm(struct shm_object *obj, size_t len)
468{
469 struct shm_ref ref;
470 struct shm_ref shm_ref_error = { -1, -1 };
471
472 if (obj->memory_map_size - obj->allocated_len < len)
473 return shm_ref_error;
474 ref.index = obj->index;
475 ref.offset = obj->allocated_len;
476 obj->allocated_len += len;
477 return ref;
478}
479
480void align_shm(struct shm_object *obj, size_t align)
481{
482 size_t offset_len = offset_align(obj->allocated_len, align);
483 obj->allocated_len += offset_len;
484}
This page took 0.044949 seconds and 4 git commands to generate.