X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=libringbuffer%2Fshm.c;h=06724e58999aad7169a232bdff91866e66413e97;hb=bf5ff35ed0a3a7f60e92d654a5b97e73b94da852;hp=fd0919fac3b75ad057e9c0aed87efd676847a76a;hpb=824f40b81426c6ac82685251018dae00947786a9;p=lttng-ust.git diff --git a/libringbuffer/shm.c b/libringbuffer/shm.c index fd0919fa..06724e58 100644 --- a/libringbuffer/shm.c +++ b/libringbuffer/shm.c @@ -1,13 +1,26 @@ /* * 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" #include +#include #include #include #include /* For mode constants */ @@ -16,7 +29,50 @@ #include #include #include -#include +#include +#include +#include +#include +/* FIXME: Include UUID the proper way, e.g. config.h... */ +#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,39 +84,95 @@ struct shm_object_table *shm_object_table_create(size_t max_nb_obj) return table; } +/* + * Generate a unique name with the desired prefix. + * Pattern is as follow: prefix-pid-uuid. + * Caller is responsible of freeing the resulting string. + */ +static +char *gen_unique_name(const char *prefix) +{ + int written; + pid_t pid; + uuid_t uuid; + char uuid_str[37]; + char tmp_name[NAME_MAX]; + char *name; + + if (!prefix) + return NULL; + + pid = getpid(); + + uuid_generate(uuid); + uuid_unparse(uuid, uuid_str); + + written = snprintf(tmp_name, NAME_MAX, + "%s-%d-%s", prefix, pid, uuid_str); + + if (written < 0 || written >= NAME_MAX) + return NULL; + + name = zmalloc(written + 1); + + if (!name) + return NULL; + + return strncpy(name, tmp_name, written); +} + struct shm_object *shm_object_table_append(struct shm_object_table *table, size_t memory_map_size) { - int shmfd, waitfd[2], ret, i, sigblocked = 0; + int shmfd, ret, sigblocked = 0; struct shm_object *obj; char *memory_map; + + const char *base_shm = "/dev/shm/"; + const char *base_path = "/tmp/lttng-fds/"; + const char *waitfd_prefix = "ust-wait"; + const char *shm_prefix = "ust-shm"; + + char *wait_pipe_path, *wait_pipe_file; + char *shm_path, *shm_symlink_path, *shm_file; + 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]; - /* wait_fd: create pipe */ - ret = pipe(waitfd); - if (ret < 0) { - PERROR("pipe"); - goto error_pipe; + wait_pipe_file = gen_unique_name(waitfd_prefix); + + if (!wait_pipe_file) { + goto error_gen_unique_wait; } - for (i = 0; i < 2; i++) { - ret = fcntl(waitfd[i], F_SETFD, FD_CLOEXEC); - if (ret < 0) { - PERROR("fcntl"); - goto error_fcntl; - } + + wait_pipe_path = zmalloc(strlen(base_path) + + strlen(wait_pipe_file) + 1); + + if (!wait_pipe_path) { + free(wait_pipe_file); + goto error_wait_alloc; } - /* The write end of the pipe needs to be non-blocking */ - ret = fcntl(waitfd[1], F_SETFL, O_NONBLOCK); + + strncat(wait_pipe_path, base_path, strlen(base_path)); + strncat(wait_pipe_path, wait_pipe_file, strlen(wait_pipe_file)); + + free(wait_pipe_file); + + /* wait_fd: create named pipe */ + ret = mkfifo(wait_pipe_path, 0777); if (ret < 0) { - PERROR("fcntl"); - goto error_fcntl; + PERROR("mkfifo"); + goto error_mkfifo; } - memcpy(obj->wait_fd, waitfd, sizeof(waitfd)); + + obj->wait_fd[0] = -1; + obj->wait_fd[1] = -1; + obj->wait_pipe_path = wait_pipe_path; /* shm_fd: create shm */ @@ -78,10 +190,6 @@ struct shm_object *shm_object_table_append(struct shm_object_table *table, sigblocked = 1; /* - * Allocate shm, and immediately unlink its shm oject, keeping - * only the file descriptor as a reference to the object. If it - * already exists (caused by short race window during which the - * global object exists in a concurrent shm_open), simply retry. * We specifically do _not_ use the / at the beginning of the * pathname so that some OS implementations can keep it local to * the process (POSIX leaves this implementation-defined). @@ -103,23 +211,66 @@ struct shm_object *shm_object_table_append(struct shm_object_table *table, PERROR("shm_open"); goto error_shm_open; } - ret = shm_unlink(tmp_name); - if (ret < 0 && errno != ENOENT) { - PERROR("shm_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; } + + /* Create unique symlink to shm */ + shm_path = zmalloc(strlen(base_shm) + strlen(tmp_name) + 1); + + if (!shm_path) { + goto error_shm_alloc; + } + + strncat(shm_path, base_shm, strlen(base_shm)); + strncat(shm_path, tmp_name, strlen(tmp_name)); + + shm_file = gen_unique_name(shm_prefix); + + if (!shm_file) { + free(shm_path); + goto error_gen_unique_shm; + } + + shm_symlink_path = zmalloc(strlen(base_path) + strlen(shm_file) + 1); + + if (!shm_symlink_path) { + free(shm_path); + free(shm_file); + goto error_symlink_alloc; + } + + strncat(shm_symlink_path, base_path, strlen(base_path)); + strncat(shm_symlink_path, shm_file, strlen(shm_file)); + + free(shm_file); + + ret = symlink(shm_path, shm_symlink_path); + if (ret < 0) { + PERROR("symlink"); + free(shm_path); + free(shm_symlink_path); + goto error_symlink_shm; + } + + free(shm_path); + + 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"); goto error_ftruncate; } obj->shm_fd = shmfd; + obj->shm_path = shm_symlink_path; /* memory_map: mmap */ memory_map = mmap(NULL, memory_map_size, PROT_READ | PROT_WRITE, @@ -137,7 +288,12 @@ struct shm_object *shm_object_table_append(struct shm_object_table *table, error_mmap: error_ftruncate: -error_shm_release: +error_zero_file: + free(shm_symlink_path); +error_symlink_shm: +error_symlink_alloc: +error_gen_unique_shm: +error_shm_alloc: error_sigmask_release: ret = close(shmfd); if (ret) { @@ -152,17 +308,11 @@ error_shm_open: } } error_pthread_sigmask: -error_fcntl: - for (i = 0; i < 2; i++) { - ret = close(waitfd[i]); - if (ret) { - PERROR("close"); - assert(0); - } - } -error_pipe: +error_mkfifo: + free(wait_pipe_path); +error_wait_alloc: +error_gen_unique_wait: return NULL; - } struct shm_object *shm_object_table_append_shadow(struct shm_object_table *table, @@ -203,16 +353,25 @@ 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); + } + } + + if (obj->shm_path) { + free(obj->shm_path); + } + for (i = 0; i < 2; i++) { if (obj->wait_fd[i] < 0) continue; @@ -222,6 +381,10 @@ void shmp_object_destroy(struct shm_object *obj) assert(0); } } + + if (obj->wait_pipe_path) { + free(obj->wait_pipe_path); + } } void shm_object_table_destroy(struct shm_object_table *table)