LCOV - code coverage report
Current view: top level - basic - ring.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 65 90 72.2 %
Date: 2015-07-29 18:47:03 Functions: 6 8 75.0 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :   This file is part of systemd.
       5             : 
       6             :   Copyright 2014 David Herrmann <dh.herrmann@gmail.com>
       7             : 
       8             :   systemd is free software; you can redistribute it and/or modify it
       9             :   under the terms of the GNU Lesser General Public License as published by
      10             :   the Free Software Foundation; either version 2.1 of the License, or
      11             :   (at your option) any later version.
      12             : 
      13             :   systemd is distributed in the hope that it will be useful, but
      14             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      16             :   Lesser General Public License for more details.
      17             : 
      18             :   You should have received a copy of the GNU Lesser General Public License
      19             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      20             : ***/
      21             : 
      22             : #include <errno.h>
      23             : #include <stdlib.h>
      24             : #include <string.h>
      25             : #include <sys/uio.h>
      26             : #include "macro.h"
      27             : #include "ring.h"
      28             : 
      29             : #define RING_MASK(_r, _v) ((_v) & ((_r)->size - 1))
      30             : 
      31           0 : void ring_flush(Ring *r) {
      32           0 :         assert(r);
      33             : 
      34           0 :         r->start = 0;
      35           0 :         r->used = 0;
      36           0 : }
      37             : 
      38        1001 : void ring_clear(Ring *r) {
      39        1001 :         assert(r);
      40             : 
      41        1001 :         free(r->buf);
      42        1001 :         zero(*r);
      43        1001 : }
      44             : 
      45             : /*
      46             :  * Get data pointers for current ring-buffer data. @vec must be an array of 2
      47             :  * iovec objects. They are filled according to the data available in the
      48             :  * ring-buffer. 0, 1 or 2 is returned according to the number of iovec objects
      49             :  * that were filled (0 meaning buffer is empty).
      50             :  *
      51             :  * Hint: "struct iovec" is defined in <sys/uio.h> and looks like this:
      52             :  *     struct iovec {
      53             :  *         void *iov_base;
      54             :  *         size_t iov_len;
      55             :  *     };
      56             :  */
      57        5182 : size_t ring_peek(Ring *r, struct iovec *vec) {
      58        5182 :         assert(r);
      59             : 
      60        5182 :         if (r->used == 0) {
      61        4176 :                 return 0;
      62        1006 :         } else if (r->start + r->used <= r->size) {
      63        1004 :                 if (vec) {
      64        1004 :                         vec[0].iov_base = &r->buf[r->start];
      65        1004 :                         vec[0].iov_len = r->used;
      66             :                 }
      67        1004 :                 return 1;
      68             :         } else {
      69           2 :                 if (vec) {
      70           2 :                         vec[0].iov_base = &r->buf[r->start];
      71           2 :                         vec[0].iov_len = r->size - r->start;
      72           2 :                         vec[1].iov_base = r->buf;
      73           2 :                         vec[1].iov_len = r->used - (r->size - r->start);
      74             :                 }
      75           2 :                 return 2;
      76             :         }
      77             : }
      78             : 
      79             : /*
      80             :  * Copy data from the ring buffer into the linear external buffer @buf. Copy
      81             :  * at most @size bytes. If the ring buffer size is smaller, copy less bytes and
      82             :  * return the number of bytes copied.
      83             :  */
      84           0 : size_t ring_copy(Ring *r, void *buf, size_t size) {
      85             :         size_t l;
      86             : 
      87           0 :         assert(r);
      88           0 :         assert(buf);
      89             : 
      90           0 :         if (size > r->used)
      91           0 :                 size = r->used;
      92             : 
      93           0 :         if (size > 0) {
      94           0 :                 l = r->size - r->start;
      95           0 :                 if (size <= l) {
      96           0 :                         memcpy(buf, &r->buf[r->start], size);
      97             :                 } else {
      98           0 :                         memcpy(buf, &r->buf[r->start], l);
      99           0 :                         memcpy((uint8_t*)buf + l, r->buf, size - l);
     100             :                 }
     101             :         }
     102             : 
     103           0 :         return size;
     104             : }
     105             : 
     106             : /*
     107             :  * Resize ring-buffer to size @nsize. @nsize must be a power-of-2, otherwise
     108             :  * ring operations will behave incorrectly.
     109             :  */
     110        1002 : static int ring_resize(Ring *r, size_t nsize) {
     111             :         uint8_t *buf;
     112             :         size_t l;
     113             : 
     114        1002 :         assert(r);
     115        1002 :         assert(nsize > 0);
     116             : 
     117        1002 :         buf = malloc(nsize);
     118        1002 :         if (!buf)
     119           0 :                 return -ENOMEM;
     120             : 
     121        1002 :         if (r->used > 0) {
     122           1 :                 l = r->size - r->start;
     123           1 :                 if (r->used <= l) {
     124           1 :                         memcpy(buf, &r->buf[r->start], r->used);
     125             :                 } else {
     126           0 :                         memcpy(buf, &r->buf[r->start], l);
     127           0 :                         memcpy(&buf[l], r->buf, r->used - l);
     128             :                 }
     129             :         }
     130             : 
     131        1002 :         free(r->buf);
     132        1002 :         r->buf = buf;
     133        1002 :         r->size = nsize;
     134        1002 :         r->start = 0;
     135             : 
     136        1002 :         return 0;
     137             : }
     138             : 
     139             : /*
     140             :  * Resize ring-buffer to provide enough room for @add bytes of new data. This
     141             :  * resizes the buffer if it is too small. It returns -ENOMEM on OOM and 0 on
     142             :  * success.
     143             :  */
     144        1006 : static int ring_grow(Ring *r, size_t add) {
     145             :         size_t need;
     146             : 
     147        1006 :         assert(r);
     148             : 
     149        1006 :         if (r->size - r->used >= add)
     150           4 :                 return 0;
     151             : 
     152        1002 :         need = r->used + add;
     153        1002 :         if (need <= r->used)
     154           0 :                 return -ENOMEM;
     155        1002 :         else if (need < 4096)
     156        1001 :                 need = 4096;
     157             : 
     158        1002 :         need = ALIGN_POWER2(need);
     159        1002 :         if (need == 0)
     160           0 :                 return -ENOMEM;
     161             : 
     162        1002 :         return ring_resize(r, need);
     163             : }
     164             : 
     165             : /*
     166             :  * Push @len bytes from @u8 into the ring buffer. The buffer is resized if it
     167             :  * is too small. -ENOMEM is returned on OOM, 0 on success.
     168             :  */
     169        1006 : int ring_push(Ring *r, const void *u8, size_t size) {
     170             :         int err;
     171             :         size_t pos, l;
     172             : 
     173        1006 :         assert(r);
     174        1006 :         assert(u8);
     175             : 
     176        1006 :         if (size == 0)
     177           0 :                 return 0;
     178             : 
     179        1006 :         err = ring_grow(r, size);
     180        1006 :         if (err < 0)
     181           0 :                 return err;
     182             : 
     183        1006 :         pos = RING_MASK(r, r->start + r->used);
     184        1006 :         l = r->size - pos;
     185        1006 :         if (l >= size) {
     186        1005 :                 memcpy(&r->buf[pos], u8, size);
     187             :         } else {
     188           1 :                 memcpy(&r->buf[pos], u8, l);
     189           1 :                 memcpy(r->buf, (const uint8_t*)u8 + l, size - l);
     190             :         }
     191             : 
     192        1006 :         r->used += size;
     193             : 
     194        1006 :         return 0;
     195             : }
     196             : 
     197             : /*
     198             :  * Remove @len bytes from the start of the ring-buffer. Note that we protect
     199             :  * against overflows so removing more bytes than available is safe.
     200             :  */
     201        1004 : void ring_pull(Ring *r, size_t size) {
     202        1004 :         assert(r);
     203             : 
     204        1004 :         if (size > r->used)
     205           0 :                 size = r->used;
     206             : 
     207        1004 :         r->start = RING_MASK(r, r->start + size);
     208        1004 :         r->used -= size;
     209        1004 : }

Generated by: LCOV version 1.11