[systemd-devel] [RFC 02/12] ring: add basic ring-buffer helper

David Herrmann dh.herrmann at gmail.com
Thu Nov 28 00:19:44 PST 2013


Hi

On Thu, Nov 28, 2013 at 1:27 AM, Lucas De Marchi
<lucas.de.marchi at gmail.com> wrote:
> On Wed, Nov 27, 2013 at 4:48 PM, David Herrmann <dh.herrmann at gmail.com> wrote:
>> This adds a very straightforward ring-buffer implementation to
>> libsystemd-shared. Ring-buffers allow pushing data to, and pulling data
>> from, both ends of a buffer without modifying existing/remaining buffer
>> content. This is very useful for network buffers and asynchronous writes.
>>
>> This implementation only contains the most basic functions to push data
>> onto the end of the buffer and pull data from the front. More helpers may
>> be added once needed.
>> ---
>>  Makefile.am       |   2 +
>>  src/shared/ring.c | 213 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  src/shared/ring.h |  54 ++++++++++++++
>>  3 files changed, 269 insertions(+)
>>  create mode 100644 src/shared/ring.c
>>  create mode 100644 src/shared/ring.h
>>
>> diff --git a/Makefile.am b/Makefile.am
>> index 0119751..4aa2bdf 100644
>> --- a/Makefile.am
>> +++ b/Makefile.am
>> @@ -768,6 +768,8 @@ libsystemd_shared_la_SOURCES = \
>>         src/shared/net-util.h \
>>         src/shared/errno-list.c \
>>         src/shared/errno-list.h \
>> +       src/shared/ring.h \
>> +       src/shared/ring.c \
>>         src/shared/syscall-list.c \
>>         src/shared/syscall-list.h
>>
>> diff --git a/src/shared/ring.c b/src/shared/ring.c
>> new file mode 100644
>> index 0000000..f60f098
>> --- /dev/null
>> +++ b/src/shared/ring.c
>> @@ -0,0 +1,213 @@
>> +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
>> +
>> +/***
>> +  This file is part of systemd.
>> +
>> +  Copyright 2013 David Herrmann <dh.herrmann at gmail.com>
>> +
>> +  systemd 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.
>> +
>> +  systemd 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 systemd; If not, see <http://www.gnu.org/licenses/>.
>> +***/
>> +
>> +#include <errno.h>
>> +#include <stdlib.h>
>> +#include <string.h>
>> +#include <sys/uio.h>
>> +
>> +#include "ring.h"
>> +#include "util.h"
>> +
>> +#define RING_MASK(_r, _v) ((_v) & ((_r)->size - 1))
>> +
>> +void ring_flush(Ring *r) {
>> +        r->start = 0;
>> +        r->end = 0;
>> +}
>> +
>> +void ring_clear(Ring *r) {
>> +        free(r->buf);
>> +        memset(r, 0, sizeof(*r));
>> +}
>> +
>> +/*
>> + * Resize ring-buffer to size @nsize. @nsize must be a power-of-2, otherwise
>> + * ring operations will behave incorrectly.
>> + */
>> +static int ring_resize(Ring *r, size_t nsize) {
>> +        char *buf;
>> +
>> +        buf = malloc(nsize);
>> +        if (!buf)
>> +                return -ENOMEM;
>> +
>> +        if (r->end == r->start) {
>> +                r->end = 0;
>> +                r->start = 0;
>> +        } else if (r->end > r->start) {
>> +                memcpy(buf, &r->buf[r->start], r->end - r->start);
>> +
>> +                r->end -= r->start;
>> +                r->start = 0;
>> +        } else {
>> +                memcpy(buf, &r->buf[r->start], r->size - r->start);
>> +                memcpy(&buf[r->size - r->start], r->buf, r->end);
>> +
>> +                r->end += r->size - r->start;
>> +                r->start = 0;
>> +        }
>> +
>> +        free(r->buf);
>> +        r->buf = buf;
>> +        r->size = nsize;
>> +
>> +        return 0;
>> +}
>> +
>> +/* Compute next higher power-of-2 of @v. Returns 4096 in case v is 0. */
>> +static size_t ring_pow2(size_t v) {
>> +        size_t i;
>> +
>> +        if (!v)
>> +                return 4096;
>> +
>> +        --v;
>> +
>> +        for (i = 1; i < 8 * sizeof(size_t); i *= 2)
>> +                v |= v >> i;
>> +
>> +        return ++v;
>
> If you are interested, take a look in
> https://git.kernel.org/cgit/utils/kernel/kmod/kmod.git/commit/?id=3ba7f59e84857eb4dbe56a68fc7a3ffe8a650393
> for a shorter and faster version of this.

Yepp, that one looks good. Didn't know there was a builtin to count
leading zeros.

Thanks
David


More information about the systemd-devel mailing list