X-Git-Url: http://git.lttng.org/?p=ust.git;a=blobdiff_plain;f=libust%2Fbuffers.h;h=30445000beb0e380d7af3c7cc657ad9ba51d3b21;hp=2dcc9245967a2315c07fe871463a2b5c71d19bb0;hb=e9b58dc0868620ba4c0e63b605602f2044a02251;hpb=dc2848112a55ee60632491148089cc60984f683d diff --git a/libust/buffers.h b/libust/buffers.h index 2dcc924..3044500 100644 --- a/libust/buffers.h +++ b/libust/buffers.h @@ -1,21 +1,37 @@ /* * buffers.h + * LTTng userspace tracer buffering system * * Copyright (C) 2009 - Pierre-Marc Fournier (pierre-marc dot fournier at polymtl dot ca) * Copyright (C) 2008 - Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca) * + * 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; either + * version 2.1 of the License, or (at your option) any later version. + * + * 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 */ #ifndef _UST_BUFFERS_H #define _UST_BUFFERS_H -#include #include + +#include + +#include "usterr.h" #include "channels.h" #include "tracerconst.h" #include "tracercore.h" #include "header-inline.h" -#include /***** FIXME: SHOULD BE REMOVED ***** */ @@ -80,7 +96,7 @@ struct ust_buffer { unsigned int cpu; /* commit count per subbuffer; must be at end of struct */ - long commit_seq[0] ____cacheline_aligned; /* ATOMIC */ + long commit_seq[0]; /* ATOMIC */ } ____cacheline_aligned; /* @@ -90,10 +106,12 @@ struct ust_buffer { */ enum force_switch_mode { FORCE_ACTIVE, FORCE_FLUSH }; -extern int ltt_reserve_slot_lockless_slow(struct ust_trace *trace, - struct ust_channel *ltt_channel, void **transport_data, - size_t data_size, size_t *slot_size, long *buf_offset, u64 *tsc, - unsigned int *rflags, int largest_align, int cpu); +extern int ltt_reserve_slot_lockless_slow(struct ust_channel *chan, + struct ust_trace *trace, size_t data_size, + int largest_align, int cpu, + struct ust_buffer **ret_buf, + size_t *slot_size, long *buf_offset, + u64 *tsc, unsigned int *rflags); extern void ltt_force_switch_lockless_slow(struct ust_buffer *buf, enum force_switch_mode mode); @@ -337,19 +355,21 @@ static __inline__ int ltt_relay_try_reserve( return 0; } -static __inline__ int ltt_reserve_slot(struct ust_trace *trace, - struct ust_channel *chan, void **transport_data, - size_t data_size, size_t *slot_size, long *buf_offset, u64 *tsc, - unsigned int *rflags, int largest_align, int cpu) +static __inline__ int ltt_reserve_slot(struct ust_channel *chan, + struct ust_trace *trace, size_t data_size, + int largest_align, int cpu, + struct ust_buffer **ret_buf, + size_t *slot_size, long *buf_offset, u64 *tsc, + unsigned int *rflags) { - struct ust_buffer *buf = chan->buf[cpu]; + struct ust_buffer *buf = *ret_buf = chan->buf[cpu]; long o_begin, o_end, o_old; size_t before_hdr_pad; /* * Perform retryable operations. */ - /* FIXME: make this rellay per cpu? */ + /* FIXME: make this really per cpu? */ if (unlikely(LOAD_SHARED(ltt_nesting) > 4)) { DBG("Dropping event because nesting is too deep."); uatomic_inc(&buf->events_lost); @@ -386,9 +406,10 @@ static __inline__ int ltt_reserve_slot(struct ust_trace *trace, *buf_offset = o_begin + before_hdr_pad; return 0; slow_path: - return ltt_reserve_slot_lockless_slow(trace, chan, - transport_data, data_size, slot_size, buf_offset, tsc, - rflags, largest_align, cpu); + return ltt_reserve_slot_lockless_slow(chan, trace, data_size, + largest_align, cpu, ret_buf, + slot_size, buf_offset, tsc, + rflags); } /* @@ -462,16 +483,8 @@ static __inline__ void ltt_commit_slot( long endidx = SUBBUF_INDEX(offset_end - 1, chan); long commit_count; -#ifdef LTT_NO_IPI_BARRIER smp_wmb(); -#else - /* - * Must write slot data before incrementing commit count. - * This compiler barrier is upgraded into a smp_mb() by the IPI - * sent by get_subbuf(). - */ - barrier(); -#endif + uatomic_add(&buf->commit_count[endidx].cc, slot_size); /* * commit count read can race with concurrent OOO commit count updates. @@ -500,22 +513,92 @@ static __inline__ void ltt_commit_slot( ltt_write_commit_counter(chan, buf, endidx, buf_offset, commit_count, data_size); } -void _ust_buffers_write(struct ust_buffer *buf, size_t offset, - const void *src, size_t len, ssize_t cpy); +void _ust_buffers_strncpy_fixup(struct ust_buffer *buf, size_t offset, + size_t len, size_t copied, int terminated); static __inline__ int ust_buffers_write(struct ust_buffer *buf, size_t offset, const void *src, size_t len) { - size_t cpy; size_t buf_offset = BUFFER_OFFSET(offset, buf->chan); assert(buf_offset < buf->chan->subbuf_size*buf->chan->subbuf_cnt); + assert(buf_offset + len + <= buf->chan->subbuf_size*buf->chan->subbuf_cnt); + + ust_buffers_do_copy(buf->buf_data + buf_offset, src, len); + + return len; +} + +/* + * ust_buffers_do_memset - write character into dest. + * @dest: destination + * @src: source character + * @len: length to write + */ +static __inline__ +void ust_buffers_do_memset(void *dest, char src, size_t len) +{ + /* + * What we really want here is an __inline__ memset, but we + * don't have constants, so gcc generally uses a function call. + */ + for (; len > 0; len--) + *(u8 *)dest++ = src; +} - cpy = min_t(size_t, len, buf->buf_size - buf_offset); - ust_buffers_do_copy(buf->buf_data + buf_offset, src, cpy); +/* + * ust_buffers_do_strncpy - copy a string up to a certain number of bytes + * @dest: destination + * @src: source + * @len: max. length to copy + * @terminated: output string ends with \0 (output) + * + * returns the number of bytes copied. Does not finalize with \0 if len is + * reached. + */ +static __inline__ +size_t ust_buffers_do_strncpy(void *dest, const void *src, size_t len, + int *terminated) +{ + size_t orig_len = len; - if (unlikely(len != cpy)) - _ust_buffers_write(buf, buf_offset, src, len, cpy); + *terminated = 0; + /* + * What we really want here is an __inline__ strncpy, but we + * don't have constants, so gcc generally uses a function call. + */ + for (; len > 0; len--) { + *(u8 *)dest = LOAD_SHARED(*(const u8 *)src); + /* Check with dest, because src may be modified concurrently */ + if (*(const u8 *)dest == '\0') { + len--; + *terminated = 1; + break; + } + dest++; + src++; + } + return orig_len - len; +} + +static __inline__ +int ust_buffers_strncpy(struct ust_buffer *buf, size_t offset, const void *src, + size_t len) +{ + size_t buf_offset = BUFFER_OFFSET(offset, buf->chan); + ssize_t copied; + int terminated; + + assert(buf_offset < buf->chan->subbuf_size*buf->chan->subbuf_cnt); + assert(buf_offset + len + <= buf->chan->subbuf_size*buf->chan->subbuf_cnt); + + copied = ust_buffers_do_strncpy(buf->buf_data + buf_offset, + src, len, &terminated); + if (unlikely(copied < len || !terminated)) + _ust_buffers_strncpy_fixup(buf, offset, len, copied, + terminated); return len; }