X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=libringbuffer%2Fshm.c;h=79977017904308c4f5c05046f176caa7e07fb612;hb=69b8d2fae1590ec792409587123afa55b8959c07;hp=8f158e2f0507feeb8d05e000f08241a0e356b9e9;hpb=1d4981969313da002983ca979bd85c95493f7316;p=lttng-ust.git diff --git a/libringbuffer/shm.c b/libringbuffer/shm.c index 8f158e2f..79977017 100644 --- a/libringbuffer/shm.c +++ b/libringbuffer/shm.c @@ -1,9 +1,21 @@ /* * libringbuffer/shm.c * - * Copyright 2011 (c) - Mathieu Desnoyers + * Copyright (C) 2005-2012 Mathieu Desnoyers * - * Dual LGPL v2.1/GPL v2 license. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "shm.h" @@ -13,7 +25,51 @@ #include /* For mode constants */ #include /* For O_* constants */ #include -#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Ensure we have the required amount of space available by writing 0 + * into the entire buffer. Not doing so can trigger SIGBUS when going + * beyond the available shm space. + */ +static +int zero_file(int fd, size_t len) +{ + ssize_t retlen; + size_t written = 0; + char *zeropage; + long pagelen; + int ret; + + pagelen = sysconf(_SC_PAGESIZE); + if (pagelen < 0) + return (int) pagelen; + zeropage = calloc(pagelen, 1); + if (!zeropage) + return -ENOMEM; + + while (len > written) { + do { + retlen = write(fd, zeropage, + min_t(size_t, pagelen, len - written)); + } while (retlen == -1UL && errno == EINTR); + if (retlen < 0) { + ret = (int) retlen; + goto error; + } + written += retlen; + } + ret = 0; +error: + free(zeropage); + return ret; +} struct shm_object_table *shm_object_table_create(size_t max_nb_obj) { @@ -28,13 +84,15 @@ struct shm_object_table *shm_object_table_create(size_t max_nb_obj) struct shm_object *shm_object_table_append(struct shm_object_table *table, size_t memory_map_size) { - int shmfd, waitfd[2], ret, i; + int shmfd, waitfd[2], ret, i, sigblocked = 0; struct shm_object *obj; char *memory_map; + char tmp_name[NAME_MAX] = "ust-shm-tmp-XXXXXX"; + sigset_t all_sigs, orig_sigs; if (table->allocated_len >= table->size) return NULL; - obj = &table->objects[table->allocated_len++]; + obj = &table->objects[table->allocated_len]; /* wait_fd: create pipe */ ret = pipe(waitfd); @@ -49,10 +107,29 @@ struct shm_object *shm_object_table_append(struct shm_object_table *table, goto error_fcntl; } } - *obj->wait_fd = *waitfd; + /* The write end of the pipe needs to be non-blocking */ + ret = fcntl(waitfd[1], F_SETFL, O_NONBLOCK); + if (ret < 0) { + PERROR("fcntl"); + goto error_fcntl; + } + memcpy(obj->wait_fd, waitfd, sizeof(waitfd)); /* shm_fd: create shm */ + /* + * Theoretically, we could leak a shm if the application crashes + * between open and unlink. Disable signals on this thread for + * increased safety against this scenario. + */ + sigfillset(&all_sigs); + ret = pthread_sigmask(SIG_BLOCK, &all_sigs, &orig_sigs); + if (ret == -1) { + PERROR("pthread_sigmask"); + goto error_pthread_sigmask; + } + sigblocked = 1; + /* * Allocate shm, and immediately unlink its shm oject, keeping * only the file descriptor as a reference to the object. If it @@ -63,17 +140,37 @@ struct shm_object *shm_object_table_append(struct shm_object_table *table, * the process (POSIX leaves this implementation-defined). */ do { - shmfd = shm_open("ust-shm-tmp", + /* + * Using mktemp filename with O_CREAT | O_EXCL open + * flags. + */ + mktemp(tmp_name); + if (tmp_name[0] == '\0') { + PERROR("mktemp"); + goto error_shm_open; + } + shmfd = shm_open(tmp_name, O_CREAT | O_EXCL | O_RDWR, 0700); - } while (shmfd < 0 && errno == EEXIST); + } while (shmfd < 0 && (errno == EEXIST || errno == EACCES)); if (shmfd < 0) { PERROR("shm_open"); goto error_shm_open; } - ret = shm_unlink("ust-shm-tmp"); - if (ret) { + ret = shm_unlink(tmp_name); + if (ret < 0 && errno != ENOENT) { PERROR("shm_unlink"); - goto error_unlink; + goto error_shm_release; + } + sigblocked = 0; + ret = pthread_sigmask(SIG_SETMASK, &orig_sigs, NULL); + if (ret == -1) { + PERROR("pthread_sigmask"); + goto error_sigmask_release; + } + ret = zero_file(shmfd, memory_map_size); + if (ret) { + PERROR("zero_file"); + goto error_zero_file; } ret = ftruncate(shmfd, memory_map_size); if (ret) { @@ -92,17 +189,28 @@ struct shm_object *shm_object_table_append(struct shm_object_table *table, obj->memory_map = memory_map; obj->memory_map_size = memory_map_size; obj->allocated_len = 0; + obj->index = table->allocated_len++; + return obj; error_mmap: error_ftruncate: -error_unlink: +error_shm_release: +error_zero_file: +error_sigmask_release: ret = close(shmfd); if (ret) { PERROR("close"); assert(0); } error_shm_open: + if (sigblocked) { + ret = pthread_sigmask(SIG_SETMASK, &orig_sigs, NULL); + if (ret == -1) { + PERROR("pthread_sigmask"); + } + } +error_pthread_sigmask: error_fcntl: for (i = 0; i < 2; i++) { ret = close(waitfd[i]); @@ -112,27 +220,65 @@ error_fcntl: } } error_pipe: - free(obj); return NULL; } +struct shm_object *shm_object_table_append_shadow(struct shm_object_table *table, + int shm_fd, int wait_fd, size_t memory_map_size) +{ + struct shm_object *obj; + char *memory_map; + + if (table->allocated_len >= table->size) + return NULL; + obj = &table->objects[table->allocated_len]; + + /* wait_fd: set read end of the pipe. */ + obj->wait_fd[0] = wait_fd; + obj->wait_fd[1] = -1; /* write end is unset. */ + obj->shm_fd = shm_fd; + + /* memory_map: mmap */ + memory_map = mmap(NULL, memory_map_size, PROT_READ | PROT_WRITE, + MAP_SHARED, shm_fd, 0); + if (memory_map == MAP_FAILED) { + PERROR("mmap"); + goto error_mmap; + } + obj->memory_map = memory_map; + obj->memory_map_size = memory_map_size; + obj->allocated_len = memory_map_size; + obj->index = table->allocated_len++; + + return obj; + +error_mmap: + return NULL; +} + static void shmp_object_destroy(struct shm_object *obj) { int ret, i; - ret = munmap(obj->memory_map, obj->memory_map_size); - if (ret) { - PERROR("umnmap"); - assert(0); - } - ret = close(obj->shm_fd); - if (ret) { - PERROR("close"); - assert(0); + if (!obj->is_shadow) { + ret = munmap(obj->memory_map, obj->memory_map_size); + if (ret) { + PERROR("umnmap"); + assert(0); + } + } + if (obj->shm_fd >= 0) { + ret = close(obj->shm_fd); + if (ret) { + PERROR("close"); + assert(0); + } } for (i = 0; i < 2; i++) { + if (obj->wait_fd[i] < 0) + continue; ret = close(obj->wait_fd[i]); if (ret) { PERROR("close");