X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;f=libringbuffer%2Fshm.c;h=3bf648d253bd4f00ad8791b34cecb3d75e0c19d2;hb=911360f660e1a4ad85813ae363168e1ddd558f67;hp=ae63b004fd50723cd9c73511049bb8d042928f59;hpb=193183fb924aef705f30358e54e7386a3a64c78d;p=lttng-ust.git diff --git a/libringbuffer/shm.c b/libringbuffer/shm.c index ae63b004..3bf648d2 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" @@ -16,7 +28,48 @@ #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) { @@ -24,17 +77,20 @@ struct shm_object_table *shm_object_table_create(size_t max_nb_obj) table = zmalloc(sizeof(struct shm_object_table) + max_nb_obj * sizeof(table->objects[0])); + if (!table) + return NULL; table->size = max_nb_obj; return table; } -struct shm_object *shm_object_table_append(struct shm_object_table *table, +static +struct shm_object *_shm_object_table_alloc_shm(struct shm_object_table *table, size_t memory_map_size) { int shmfd, waitfd[2], ret, i, sigblocked = 0; struct shm_object *obj; char *memory_map; - char tmp_name[NAME_MAX] = "ust-shm-tmp-XXXXXX"; + char tmp_name[NAME_MAX] = "/ust-shm-tmp-XXXXXX"; sigset_t all_sigs, orig_sigs; if (table->allocated_len >= table->size) @@ -91,7 +147,7 @@ struct shm_object *shm_object_table_append(struct shm_object_table *table, * Using mktemp filename with O_CREAT | O_EXCL open * flags. */ - mktemp(tmp_name); + (void) mktemp(tmp_name); if (tmp_name[0] == '\0') { PERROR("mktemp"); goto error_shm_open; @@ -114,6 +170,11 @@ struct shm_object *shm_object_table_append(struct shm_object_table *table, 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) { PERROR("ftruncate"); @@ -128,6 +189,7 @@ struct shm_object *shm_object_table_append(struct shm_object_table *table, PERROR("mmap"); goto error_mmap; } + obj->type = SHM_OBJECT_SHM; obj->memory_map = memory_map; obj->memory_map_size = memory_map_size; obj->allocated_len = 0; @@ -138,6 +200,7 @@ struct shm_object *shm_object_table_append(struct shm_object_table *table, error_mmap: error_ftruncate: error_shm_release: +error_zero_file: error_sigmask_release: ret = close(shmfd); if (ret) { @@ -162,24 +225,118 @@ error_fcntl: } error_pipe: 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) +static +struct shm_object *_shm_object_table_alloc_mem(struct shm_object_table *table, + size_t memory_map_size) +{ + struct shm_object *obj; + void *memory_map; + int waitfd[2], i, ret; + + if (table->allocated_len >= table->size) + return NULL; + obj = &table->objects[table->allocated_len]; + + memory_map = zmalloc(memory_map_size); + if (!memory_map) + goto alloc_error; + + /* wait_fd: create pipe */ + ret = pipe(waitfd); + if (ret < 0) { + PERROR("pipe"); + goto error_pipe; + } + for (i = 0; i < 2; i++) { + ret = fcntl(waitfd[i], F_SETFD, FD_CLOEXEC); + if (ret < 0) { + PERROR("fcntl"); + goto error_fcntl; + } + } + /* 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)); + + /* no shm_fd */ + obj->shm_fd = -1; + + obj->type = SHM_OBJECT_MEM; + obj->memory_map = memory_map; + obj->memory_map_size = memory_map_size; + obj->allocated_len = 0; + obj->index = table->allocated_len++; + + return obj; + +error_fcntl: + for (i = 0; i < 2; i++) { + ret = close(waitfd[i]); + if (ret) { + PERROR("close"); + assert(0); + } + } +error_pipe: + free(memory_map); +alloc_error: + return NULL; +} + +struct shm_object *shm_object_table_alloc(struct shm_object_table *table, + size_t memory_map_size, + enum shm_object_type type) +{ + switch (type) { + case SHM_OBJECT_SHM: + return _shm_object_table_alloc_shm(table, memory_map_size); + case SHM_OBJECT_MEM: + return _shm_object_table_alloc_mem(table, memory_map_size); + default: + assert(0); + } + return NULL; +} + +struct shm_object *shm_object_table_append_shm(struct shm_object_table *table, + int shm_fd, int wakeup_fd, uint32_t stream_nr, + size_t memory_map_size) { struct shm_object *obj; char *memory_map; + int ret; if (table->allocated_len >= table->size) return NULL; + /* streams _must_ be received in sequential order, else fail. */ + if (stream_nr + 1 != table->allocated_len) + 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. */ + /* wait_fd: set write end of the pipe. */ + obj->wait_fd[0] = -1; /* read end is unset */ + obj->wait_fd[1] = wakeup_fd; obj->shm_fd = shm_fd; + ret = fcntl(obj->wait_fd[1], F_SETFD, FD_CLOEXEC); + if (ret < 0) { + PERROR("fcntl"); + goto error_fcntl; + } + /* The write end of the pipe needs to be non-blocking */ + ret = fcntl(obj->wait_fd[1], F_SETFL, O_NONBLOCK); + if (ret < 0) { + PERROR("fcntl"); + goto error_fcntl; + } + /* memory_map: mmap */ memory_map = mmap(NULL, memory_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); @@ -187,6 +344,7 @@ struct shm_object *shm_object_table_append_shadow(struct shm_object_table *table PERROR("mmap"); goto error_mmap; } + obj->type = SHM_OBJECT_SHM; obj->memory_map = memory_map; obj->memory_map_size = memory_map_size; obj->allocated_len = memory_map_size; @@ -194,31 +352,99 @@ struct shm_object *shm_object_table_append_shadow(struct shm_object_table *table return obj; +error_fcntl: error_mmap: return NULL; } +/* + * Passing ownership of mem to object. + */ +struct shm_object *shm_object_table_append_mem(struct shm_object_table *table, + void *mem, size_t memory_map_size, int wakeup_fd) +{ + struct shm_object *obj; + int ret; + + if (table->allocated_len >= table->size) + return NULL; + obj = &table->objects[table->allocated_len]; + + obj->wait_fd[0] = -1; /* read end is unset */ + obj->wait_fd[1] = wakeup_fd; + obj->shm_fd = -1; + + ret = fcntl(obj->wait_fd[1], F_SETFD, FD_CLOEXEC); + if (ret < 0) { + PERROR("fcntl"); + goto error_fcntl; + } + /* The write end of the pipe needs to be non-blocking */ + ret = fcntl(obj->wait_fd[1], F_SETFL, O_NONBLOCK); + if (ret < 0) { + PERROR("fcntl"); + goto error_fcntl; + } + + obj->type = SHM_OBJECT_MEM; + obj->memory_map = mem; + obj->memory_map_size = memory_map_size; + obj->allocated_len = memory_map_size; + obj->index = table->allocated_len++; + + return obj; + +error_fcntl: + 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); - } - for (i = 0; i < 2; i++) { - ret = close(obj->wait_fd[i]); + switch (obj->type) { + case SHM_OBJECT_SHM: + { + 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); } + for (i = 0; i < 2; i++) { + if (obj->wait_fd[i] < 0) + continue; + ret = close(obj->wait_fd[i]); + if (ret) { + PERROR("close"); + assert(0); + } + } + break; + } + case SHM_OBJECT_MEM: + { + int ret, i; + + for (i = 0; i < 2; i++) { + if (obj->wait_fd[i] < 0) + continue; + ret = close(obj->wait_fd[i]); + if (ret) { + PERROR("close"); + assert(0); + } + } + free(obj->memory_map); + break; + } + default: + assert(0); } }