1204076Spjd/*- 2204076Spjd * Copyright (c) 2009-2010 The FreeBSD Foundation 3204076Spjd * All rights reserved. 4204076Spjd * 5204076Spjd * This software was developed by Pawel Jakub Dawidek under sponsorship from 6204076Spjd * the FreeBSD Foundation. 7204076Spjd * 8204076Spjd * Redistribution and use in source and binary forms, with or without 9204076Spjd * modification, are permitted provided that the following conditions 10204076Spjd * are met: 11204076Spjd * 1. Redistributions of source code must retain the above copyright 12204076Spjd * notice, this list of conditions and the following disclaimer. 13204076Spjd * 2. Redistributions in binary form must reproduce the above copyright 14204076Spjd * notice, this list of conditions and the following disclaimer in the 15204076Spjd * documentation and/or other materials provided with the distribution. 16204076Spjd * 17204076Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 18204076Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19204076Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20204076Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 21204076Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22204076Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23204076Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24204076Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25204076Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26204076Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27204076Spjd * SUCH DAMAGE. 28204076Spjd */ 29204076Spjd 30204076Spjd#include <sys/cdefs.h> 31204076Spjd__FBSDID("$FreeBSD$"); 32204076Spjd 33204076Spjd#include <sys/param.h> 34204076Spjd 35204076Spjd#include <errno.h> 36204076Spjd#include <stdbool.h> 37204076Spjd#include <stdint.h> 38204076Spjd#include <strings.h> 39204076Spjd#include <unistd.h> 40204076Spjd 41229509Strociny#include <pjdlog.h> 42229509Strociny 43204076Spjd#include "ebuf.h" 44204076Spjd 45229509Strociny#ifndef PJDLOG_ASSERT 46229509Strociny#include <assert.h> 47229509Strociny#define PJDLOG_ASSERT(...) assert(__VA_ARGS__) 48229509Strociny#endif 49229509Strociny 50204076Spjd#define EBUF_MAGIC 0xeb0f41c 51204076Spjdstruct ebuf { 52204076Spjd /* Magic to assert the caller uses valid structure. */ 53204076Spjd int eb_magic; 54204076Spjd /* Address where we did the allocation. */ 55204076Spjd unsigned char *eb_start; 56204076Spjd /* Allocation end address. */ 57204076Spjd unsigned char *eb_end; 58204076Spjd /* Start of real data. */ 59204076Spjd unsigned char *eb_used; 60204076Spjd /* Size of real data. */ 61204076Spjd size_t eb_size; 62204076Spjd}; 63204076Spjd 64209184Spjdstatic int ebuf_head_extend(struct ebuf *eb, size_t size); 65209184Spjdstatic int ebuf_tail_extend(struct ebuf *eb, size_t size); 66204076Spjd 67204076Spjdstruct ebuf * 68204076Spjdebuf_alloc(size_t size) 69204076Spjd{ 70204076Spjd struct ebuf *eb; 71204076Spjd int rerrno; 72204076Spjd 73204076Spjd eb = malloc(sizeof(*eb)); 74204076Spjd if (eb == NULL) 75204076Spjd return (NULL); 76204076Spjd size += PAGE_SIZE; 77204076Spjd eb->eb_start = malloc(size); 78204076Spjd if (eb->eb_start == NULL) { 79204076Spjd rerrno = errno; 80204076Spjd free(eb); 81204076Spjd errno = rerrno; 82204076Spjd return (NULL); 83204076Spjd } 84204076Spjd eb->eb_end = eb->eb_start + size; 85204076Spjd /* 86204076Spjd * We set start address for real data not at the first entry, because 87204076Spjd * we want to be able to add data at the front. 88204076Spjd */ 89204076Spjd eb->eb_used = eb->eb_start + PAGE_SIZE / 4; 90204076Spjd eb->eb_size = 0; 91204076Spjd eb->eb_magic = EBUF_MAGIC; 92204076Spjd 93204076Spjd return (eb); 94204076Spjd} 95204076Spjd 96204076Spjdvoid 97204076Spjdebuf_free(struct ebuf *eb) 98204076Spjd{ 99204076Spjd 100229509Strociny PJDLOG_ASSERT(eb != NULL && eb->eb_magic == EBUF_MAGIC); 101204076Spjd 102204076Spjd eb->eb_magic = 0; 103204076Spjd 104204076Spjd free(eb->eb_start); 105204076Spjd free(eb); 106204076Spjd} 107204076Spjd 108204076Spjdint 109204076Spjdebuf_add_head(struct ebuf *eb, const void *data, size_t size) 110204076Spjd{ 111204076Spjd 112229509Strociny PJDLOG_ASSERT(eb != NULL && eb->eb_magic == EBUF_MAGIC); 113204076Spjd 114204076Spjd if (size > (size_t)(eb->eb_used - eb->eb_start)) { 115204076Spjd /* 116204076Spjd * We can't add more entries at the front, so we have to extend 117204076Spjd * our buffer. 118204076Spjd */ 119231017Strociny if (ebuf_head_extend(eb, size) == -1) 120204076Spjd return (-1); 121204076Spjd } 122229509Strociny PJDLOG_ASSERT(size <= (size_t)(eb->eb_used - eb->eb_start)); 123204076Spjd 124204076Spjd eb->eb_size += size; 125204076Spjd eb->eb_used -= size; 126204076Spjd /* 127204076Spjd * If data is NULL the caller just wants to reserve place. 128204076Spjd */ 129204076Spjd if (data != NULL) 130204076Spjd bcopy(data, eb->eb_used, size); 131204076Spjd 132204076Spjd return (0); 133204076Spjd} 134204076Spjd 135204076Spjdint 136204076Spjdebuf_add_tail(struct ebuf *eb, const void *data, size_t size) 137204076Spjd{ 138204076Spjd 139229509Strociny PJDLOG_ASSERT(eb != NULL && eb->eb_magic == EBUF_MAGIC); 140204076Spjd 141204076Spjd if (size > (size_t)(eb->eb_end - (eb->eb_used + eb->eb_size))) { 142204076Spjd /* 143204076Spjd * We can't add more entries at the back, so we have to extend 144204076Spjd * our buffer. 145204076Spjd */ 146231017Strociny if (ebuf_tail_extend(eb, size) == -1) 147204076Spjd return (-1); 148204076Spjd } 149229509Strociny PJDLOG_ASSERT(size <= 150229509Strociny (size_t)(eb->eb_end - (eb->eb_used + eb->eb_size))); 151204076Spjd 152204076Spjd /* 153209184Spjd * If data is NULL the caller just wants to reserve space. 154204076Spjd */ 155204076Spjd if (data != NULL) 156204076Spjd bcopy(data, eb->eb_used + eb->eb_size, size); 157204076Spjd eb->eb_size += size; 158204076Spjd 159204076Spjd return (0); 160204076Spjd} 161204076Spjd 162204076Spjdvoid 163204076Spjdebuf_del_head(struct ebuf *eb, size_t size) 164204076Spjd{ 165204076Spjd 166229509Strociny PJDLOG_ASSERT(eb != NULL && eb->eb_magic == EBUF_MAGIC); 167229509Strociny PJDLOG_ASSERT(size <= eb->eb_size); 168204076Spjd 169204076Spjd eb->eb_used += size; 170204076Spjd eb->eb_size -= size; 171204076Spjd} 172204076Spjd 173204076Spjdvoid 174204076Spjdebuf_del_tail(struct ebuf *eb, size_t size) 175204076Spjd{ 176204076Spjd 177229509Strociny PJDLOG_ASSERT(eb != NULL && eb->eb_magic == EBUF_MAGIC); 178229509Strociny PJDLOG_ASSERT(size <= eb->eb_size); 179204076Spjd 180204076Spjd eb->eb_size -= size; 181204076Spjd} 182204076Spjd 183204076Spjd/* 184204076Spjd * Return pointer to the data and data size. 185204076Spjd */ 186204076Spjdvoid * 187204076Spjdebuf_data(struct ebuf *eb, size_t *sizep) 188204076Spjd{ 189204076Spjd 190229509Strociny PJDLOG_ASSERT(eb != NULL && eb->eb_magic == EBUF_MAGIC); 191204076Spjd 192204076Spjd if (sizep != NULL) 193204076Spjd *sizep = eb->eb_size; 194204076Spjd return (eb->eb_size > 0 ? eb->eb_used : NULL); 195204076Spjd} 196204076Spjd 197204076Spjd/* 198204076Spjd * Return data size. 199204076Spjd */ 200204076Spjdsize_t 201204076Spjdebuf_size(struct ebuf *eb) 202204076Spjd{ 203204076Spjd 204229509Strociny PJDLOG_ASSERT(eb != NULL && eb->eb_magic == EBUF_MAGIC); 205204076Spjd 206204076Spjd return (eb->eb_size); 207204076Spjd} 208204076Spjd 209204076Spjd/* 210204076Spjd * Function adds size + (PAGE_SIZE / 4) bytes at the front of the buffer.. 211204076Spjd */ 212204076Spjdstatic int 213209184Spjdebuf_head_extend(struct ebuf *eb, size_t size) 214204076Spjd{ 215204076Spjd unsigned char *newstart, *newused; 216204076Spjd size_t newsize; 217204076Spjd 218229509Strociny PJDLOG_ASSERT(eb != NULL && eb->eb_magic == EBUF_MAGIC); 219204076Spjd 220204076Spjd newsize = eb->eb_end - eb->eb_start + (PAGE_SIZE / 4) + size; 221204076Spjd 222204076Spjd newstart = malloc(newsize); 223204076Spjd if (newstart == NULL) 224204076Spjd return (-1); 225204076Spjd newused = 226204076Spjd newstart + (PAGE_SIZE / 4) + size + (eb->eb_used - eb->eb_start); 227204076Spjd 228204076Spjd bcopy(eb->eb_used, newused, eb->eb_size); 229204076Spjd 230204076Spjd eb->eb_start = newstart; 231204076Spjd eb->eb_used = newused; 232204076Spjd eb->eb_end = newstart + newsize; 233204076Spjd 234204076Spjd return (0); 235204076Spjd} 236204076Spjd 237204076Spjd/* 238204076Spjd * Function adds size + ((3 * PAGE_SIZE) / 4) bytes at the back. 239204076Spjd */ 240204076Spjdstatic int 241209184Spjdebuf_tail_extend(struct ebuf *eb, size_t size) 242204076Spjd{ 243204076Spjd unsigned char *newstart; 244204076Spjd size_t newsize; 245204076Spjd 246229509Strociny PJDLOG_ASSERT(eb != NULL && eb->eb_magic == EBUF_MAGIC); 247204076Spjd 248204076Spjd newsize = eb->eb_end - eb->eb_start + size + ((3 * PAGE_SIZE) / 4); 249204076Spjd 250204076Spjd newstart = realloc(eb->eb_start, newsize); 251204076Spjd if (newstart == NULL) 252204076Spjd return (-1); 253204076Spjd 254204076Spjd eb->eb_used = newstart + (eb->eb_used - eb->eb_start); 255204076Spjd eb->eb_start = newstart; 256204076Spjd eb->eb_end = newstart + newsize; 257204076Spjd 258204076Spjd return (0); 259204076Spjd} 260