X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;f=libringbuffer%2Ffrontend_internal.h;h=2f837f7d80134449816afcb3e97546bd311aea0e;hb=refs%2Fheads%2Fstable-2.0;hp=aa7876e81e422da67e47c672f9453c62e0fe7df4;hpb=2fed87aef82aaa8edfb6d8d8ac6bbf5f1e67b955;p=lttng-ust.git diff --git a/libringbuffer/frontend_internal.h b/libringbuffer/frontend_internal.h index aa7876e8..2f837f7d 100644 --- a/libringbuffer/frontend_internal.h +++ b/libringbuffer/frontend_internal.h @@ -1,13 +1,28 @@ -#ifndef _LINUX_RING_BUFFER_FRONTEND_INTERNAL_H -#define _LINUX_RING_BUFFER_FRONTEND_INTERNAL_H +#ifndef _LTTNG_RING_BUFFER_FRONTEND_INTERNAL_H +#define _LTTNG_RING_BUFFER_FRONTEND_INTERNAL_H /* - * linux/ringbuffer/frontend_internal.h - * - * (C) Copyright 2005-2010 - Mathieu Desnoyers + * libringbuffer/frontend_internal.h * * Ring Buffer Library Synchronization Header (internal helpers). * + * Copyright (C) 2005-2012 Mathieu Desnoyers + * + * 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 + * + * * Author: * Mathieu Desnoyers * @@ -17,6 +32,8 @@ */ #include +#include +#include #include #include "backend_types.h" @@ -324,6 +341,12 @@ void lib_ring_buffer_check_deliver(const struct lttng_ust_lib_ring_buffer_config * The subbuffer size is least 2 bytes (minimum size: 1 page). * This guarantees that old_commit_count + 1 != commit_count. */ + + /* + * Order prior updates to reserve count prior to the + * commit_cold cc_sb update. + */ + cmm_smp_wmb(); if (caa_likely(v_cmpxchg(config, &shmp_index(handle, buf->commit_cold, idx)->cc_sb, old_commit_count, old_commit_count + 1) == old_commit_count)) { @@ -369,6 +392,11 @@ void lib_ring_buffer_check_deliver(const struct lttng_ust_lib_ring_buffer_config /* End of exclusive subbuffer access */ v_set(config, &shmp_index(handle, buf->commit_cold, idx)->cc_sb, commit_count); + /* + * Order later updates to reserve count after + * the commit cold cc_sb update. + */ + cmm_smp_wmb(); lib_ring_buffer_vmcore_check_deliver(config, buf, commit_count, idx, handle); @@ -382,7 +410,9 @@ void lib_ring_buffer_check_deliver(const struct lttng_ust_lib_ring_buffer_config int wakeup_fd = shm_get_wakeup_fd(handle, &buf->self._ref); if (wakeup_fd >= 0) { - int ret; + sigset_t sigpipe_set, pending_set, old_set; + int ret, sigpipe_was_pending = 0; + /* * Wake-up the other end by * writing a null byte in the @@ -401,13 +431,55 @@ void lib_ring_buffer_check_deliver(const struct lttng_ust_lib_ring_buffer_config * 2) check if there is data in * the buffer. * 3) wait on the pipe (poll). + * + * Discard the SIGPIPE from write(), not + * disturbing any SIGPIPE that might be + * already pending. If a bogus SIGPIPE + * is sent to the entire process + * concurrently by a malicious user, it + * may be simply discarded. + */ + ret = sigemptyset(&pending_set); + assert(!ret); + /* + * sigpending returns the mask + * of signals that are _both_ + * blocked for the thread _and_ + * pending for either the thread + * or the entire process. + */ + ret = sigpending(&pending_set); + assert(!ret); + sigpipe_was_pending = sigismember(&pending_set, SIGPIPE); + /* + * If sigpipe was pending, it + * means it was already blocked, + * so no need to block it. */ + if (!sigpipe_was_pending) { + ret = sigemptyset(&sigpipe_set); + assert(!ret); + ret = sigaddset(&sigpipe_set, SIGPIPE); + assert(!ret); + ret = pthread_sigmask(SIG_BLOCK, &sigpipe_set, &old_set); + assert(!ret); + } do { ret = write(wakeup_fd, "", 1); } while (ret == -1L && errno == EINTR); + if (ret == -1L && errno == EPIPE && !sigpipe_was_pending) { + struct timespec timeout = { 0, 0 }; + do { + ret = sigtimedwait(&sigpipe_set, NULL, + &timeout); + } while (ret == -1L && errno == EINTR); + } + if (!sigpipe_was_pending) { + ret = pthread_sigmask(SIG_SETMASK, &old_set, NULL); + assert(!ret); + } } } - } } } @@ -462,4 +534,4 @@ extern void lib_ring_buffer_free(struct lttng_ust_lib_ring_buffer *buf, /* Keep track of trap nesting inside ring buffer code */ extern __thread unsigned int lib_ring_buffer_nesting; -#endif /* _LINUX_RING_BUFFER_FRONTEND_INTERNAL_H */ +#endif /* _LTTNG_RING_BUFFER_FRONTEND_INTERNAL_H */