2 * Copyright (c) 2009-2010 The FreeBSD Foundation
5 * This software was developed by Pawel Jakub Dawidek under sponsorship from
6 * the FreeBSD Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/param.h>
44 #define EBUF_MAGIC 0xeb0f41c
46 /* Magic to assert the caller uses valid structure. */
48 /* Address where we did the allocation. */
49 unsigned char *eb_start;
50 /* Allocation end address. */
51 unsigned char *eb_end;
52 /* Start of real data. */
53 unsigned char *eb_used;
54 /* Size of real data. */
58 static int ebuf_head_extend(struct ebuf *eb, size_t size);
59 static int ebuf_tail_extend(struct ebuf *eb, size_t size);
62 ebuf_alloc(size_t size)
67 eb = malloc(sizeof(*eb));
71 eb->eb_start = malloc(size);
72 if (eb->eb_start == NULL) {
78 eb->eb_end = eb->eb_start + size;
80 * We set start address for real data not at the first entry, because
81 * we want to be able to add data at the front.
83 eb->eb_used = eb->eb_start + PAGE_SIZE / 4;
85 eb->eb_magic = EBUF_MAGIC;
91 ebuf_free(struct ebuf *eb)
94 assert(eb != NULL && eb->eb_magic == EBUF_MAGIC);
103 ebuf_add_head(struct ebuf *eb, const void *data, size_t size)
106 assert(eb != NULL && eb->eb_magic == EBUF_MAGIC);
108 if (size > (size_t)(eb->eb_used - eb->eb_start)) {
110 * We can't add more entries at the front, so we have to extend
113 if (ebuf_head_extend(eb, size) < 0)
116 assert(size <= (size_t)(eb->eb_used - eb->eb_start));
121 * If data is NULL the caller just wants to reserve place.
124 bcopy(data, eb->eb_used, size);
130 ebuf_add_tail(struct ebuf *eb, const void *data, size_t size)
133 assert(eb != NULL && eb->eb_magic == EBUF_MAGIC);
135 if (size > (size_t)(eb->eb_end - (eb->eb_used + eb->eb_size))) {
137 * We can't add more entries at the back, so we have to extend
140 if (ebuf_tail_extend(eb, size) < 0)
143 assert(size <= (size_t)(eb->eb_end - (eb->eb_used + eb->eb_size)));
146 * If data is NULL the caller just wants to reserve space.
149 bcopy(data, eb->eb_used + eb->eb_size, size);
156 ebuf_del_head(struct ebuf *eb, size_t size)
159 assert(eb != NULL && eb->eb_magic == EBUF_MAGIC);
160 assert(size <= eb->eb_size);
167 ebuf_del_tail(struct ebuf *eb, size_t size)
170 assert(eb != NULL && eb->eb_magic == EBUF_MAGIC);
171 assert(size <= eb->eb_size);
177 * Return pointer to the data and data size.
180 ebuf_data(struct ebuf *eb, size_t *sizep)
183 assert(eb != NULL && eb->eb_magic == EBUF_MAGIC);
186 *sizep = eb->eb_size;
187 return (eb->eb_size > 0 ? eb->eb_used : NULL);
194 ebuf_size(struct ebuf *eb)
197 assert(eb != NULL && eb->eb_magic == EBUF_MAGIC);
199 return (eb->eb_size);
203 * Function adds size + (PAGE_SIZE / 4) bytes at the front of the buffer..
206 ebuf_head_extend(struct ebuf *eb, size_t size)
208 unsigned char *newstart, *newused;
211 assert(eb != NULL && eb->eb_magic == EBUF_MAGIC);
213 newsize = eb->eb_end - eb->eb_start + (PAGE_SIZE / 4) + size;
215 newstart = malloc(newsize);
216 if (newstart == NULL)
219 newstart + (PAGE_SIZE / 4) + size + (eb->eb_used - eb->eb_start);
221 bcopy(eb->eb_used, newused, eb->eb_size);
223 eb->eb_start = newstart;
224 eb->eb_used = newused;
225 eb->eb_end = newstart + newsize;
231 * Function adds size + ((3 * PAGE_SIZE) / 4) bytes at the back.
234 ebuf_tail_extend(struct ebuf *eb, size_t size)
236 unsigned char *newstart;
239 assert(eb != NULL && eb->eb_magic == EBUF_MAGIC);
241 newsize = eb->eb_end - eb->eb_start + size + ((3 * PAGE_SIZE) / 4);
243 newstart = realloc(eb->eb_start, newsize);
244 if (newstart == NULL)
247 eb->eb_used = newstart + (eb->eb_used - eb->eb_start);
248 eb->eb_start = newstart;
249 eb->eb_end = newstart + newsize;