source: trunk/packages/xen-common/xen-common/tools/vnet/libxutil/mem_stream.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 17 years ago

Add xen and xen-common

File size: 8.3 KB
Line 
1/*
2 * Copyright (C) 2005 Mike Wray <mike.wray@hp.com>
3 *
4 * This library is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; either version 2.1 of the License, or
7 * (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 */
18
19/** @file
20 * IOStream subtype for input and output to memory.
21 * Usable from user or kernel code (with __KERNEL__ defined).
22 */
23
24#include "sys_string.h"
25#include "mem_stream.h"
26#include "allocate.h"
27
28/** Internal state for a memory stream.
29 *
30 * The memory stream buffer is treated as a circular buffer.
31 * The lo and hi markers indicate positions in the buffer, but
32 * are not reduced modulo the buffer size. This avoids the ambiguity
33 * between a full and empty buffer when using reduced values.
34 *
35 * If x is a marker, then buf + (x % buf_n) is the corresponding
36 * pointer into the buffer. When the buffer is empty, lo == hi,
37 * and the corresponding pointers are equal. When the buffer is
38 * full, hi == lo + buf_n, and the corresponding pointers
39 * are also equal.
40 *
41 * Data is written after the high pointer and read from the lo pointer.
42 * The value hi - lo is the number of bytes in the buffer.
43 */
44typedef struct MemData {
45    /** Data buffer. */
46    char *buf;
47    /** Low marker - start of readable area. */
48    unsigned long lo;
49    /** High marker - end of readable area, start of writeable area. */
50    unsigned long hi;
51    /** Size of the buffer. */
52    unsigned int buf_n;
53    /** Maximum size the buffer can grow to. */
54    unsigned int buf_max;
55    /** Error code. */
56    int err;
57} MemData;
58
59/** Get number of bytes available to read.
60 *
61 * @param data mem stream
62 * @return bytes
63 */
64static inline int mem_len(struct MemData *data){
65    return data->hi - data->lo;
66}
67
68/** Get available space left in the buffer.
69 *
70 * @param data mem stream
71 * @return bytes
72 */
73static inline int mem_room(struct MemData *data){
74    return data->buf_n - mem_len(data);
75}
76
77/** Get a pointer to the start of the data in the buffer.
78 *
79 * @param data mem stream
80 * @return lo pointer
81 */
82static inline char * mem_lo(struct MemData *data){
83    return data->buf + (data->lo % data->buf_n);
84}
85
86/** Get a pointer to the end of the data in the buffer.
87 *
88 * @param data mem stream
89 * @return hi pointer
90 */
91static inline char * mem_hi(struct MemData *data){
92    return data->buf + (data->hi % data->buf_n);
93}
94
95/** Get a pointer to the end of the buffer.
96 *
97 * @param data mem stream
98 * @return end pointer
99 */
100static inline char * mem_end(struct MemData *data){
101    return data->buf + data->buf_n;
102}
103
104static int mem_error(IOStream *io);
105static int mem_close(IOStream *io);
106static void mem_free(IOStream *io);
107static int mem_write(IOStream *io, const void *msg, size_t n);
108static int mem_read(IOStream *io, void *buf, size_t n);
109
110/** Minimum delta used to increment the buffer. */
111static int delta_min = 256;
112
113/** Methods for a memory stream. */
114static IOMethods mem_methods = {
115    read:  mem_read,
116    write: mem_write,
117    error: mem_error,
118    close: mem_close,
119    free:  mem_free,
120};
121
122/** Get the memory stream state.
123 *
124 * @param io memory stream
125 * @return state
126 */
127static inline MemData *get_mem_data(IOStream *io){
128    return (MemData*)io->data;
129}
130
131/** Get the number of bytes available to read.
132 *
133 * @param io memory stream
134 * @return number of bytes
135 */
136int mem_stream_avail(IOStream *io){
137    MemData *data = get_mem_data(io);
138    return (data->err ? -data->err : mem_len(data));
139}
140
141/** Copy bytes from a memory stream into a buffer.
142 *
143 * @param data mem stream
144 * @param buf buffer
145 * @param n number of bytes to copy
146 */
147static void mem_get(MemData *data, char *buf, size_t n){
148    char *start = mem_lo(data);
149    char *end = mem_end(data);
150    if (start + n < end) {
151        memcpy(buf, start, n);
152    } else {
153        int k = end - start;
154        memcpy(buf, start, k);
155        memcpy(buf + k, data->buf, n - k);
156    }
157}
158
159/** Copy bytes from a buffer into a memory stream.
160 *
161 * @param data mem stream
162 * @param buf buffer
163 * @param n number of bytes to copy
164 */
165static void mem_put(MemData *data, const char *buf, size_t n){
166    char *start = mem_hi(data);
167    char *end = mem_end(data);
168    if(start + n < end){
169        memcpy(start, buf, n);
170    } else {
171        int k = end - start;
172        memcpy(start, buf, k);
173        memcpy(data->buf, buf + k, n - k);
174    }
175}
176
177/** Expand the buffer used by a memory stream.
178 *
179 * @param data mem stream
180 * @param extra number of bytes to expand by
181 * @return 0 on success, negative error otherwise
182 */
183static int mem_expand(MemData *data, size_t extra){
184    int err = -ENOMEM;
185    int delta = (extra < delta_min ? delta_min : extra);
186    int buf_n;
187    char *buf;
188    if(data->buf_max > 0){
189        int delta_max = data->buf_max - data->buf_n;
190        if(delta > delta_max){
191            delta = extra;
192            if(delta > delta_max) goto exit;
193        }
194    }
195    buf_n = data->buf_n + delta;
196    buf = allocate(buf_n);
197    if(!buf) goto exit;
198    mem_get(data, buf, mem_len(data));
199    data->hi = mem_len(data);
200    data->lo = 0;
201    deallocate(data->buf);
202    data->buf = buf;
203    data->buf_n = buf_n;
204    err = 0;
205  exit:
206    if(err){
207        data->err = -err;
208    }
209    return err;
210}
211
212/** Write bytes from a buffer into a memory stream.
213 * The internal buffer is expanded as needed to hold the data,
214 * up to the stream maximum (if specified). If the buffer cannot
215 * be expanded -ENOMEM is returned.
216 *
217 * @param io mem stream
218 * @param buf buffer
219 * @param n number of bytes to write
220 * @return number of bytes written on success, negative error code otherwise
221 */
222static int mem_write(IOStream *io, const void *msg, size_t n){
223    int room;
224    MemData *data = get_mem_data(io);
225    if(data->err) return -data->err;
226    room = mem_room(data);
227    if(n > room){
228        int err = mem_expand(data, n - room);
229        if(err) return err;
230    }
231    mem_put(data, msg, n);
232    data->hi += n;
233    return n;
234}
235
236/** Read bytes from a memory stream into a buffer.
237 *
238 * @param io mem stream
239 * @param buf buffer
240 * @param n maximum number of bytes to read
241 * @return number of bytes read on success, negative error code otherwise
242 */
243static int mem_read(IOStream *io, void *buf, size_t n){
244    int k;
245    MemData *data = get_mem_data(io);
246    if(data->err) return -data->err;
247    k = mem_len(data);
248    if(n > k){
249        n = k;
250    }
251    mem_get(data, buf, n);
252    data->lo += n;
253    return n;
254}
255
256/** Test if a memory stream has an error.
257 *
258 * @param io mem stream
259 * @return 0 if ok, error code otherwise
260 */
261static int mem_error(IOStream *io){
262    MemData *data = get_mem_data(io);
263    return data->err;
264}
265
266/** Close a memory stream.
267 *
268 * @param io mem stream
269 * @return 0
270 */
271static int mem_close(IOStream *io){
272    MemData *data = get_mem_data(io);
273    if(!data->err){
274        data->err = ENOTCONN;
275    }
276    return 0;
277}
278
279/** Free a memory stream.
280 *
281 * @param io mem stream
282 */
283static void mem_free(IOStream *io){
284    MemData *data = get_mem_data(io);
285    deallocate(data->buf);
286    memzero(data, sizeof(*data));
287    deallocate(data);
288}
289
290/** Allocate and initialise a memory stream.
291 *
292 * @param buf_n initial buffer size (0 means default)
293 * @param buf_max maximum buffer size (0 means no max)
294 * @return new stream (free using IOStream_close)
295 */
296IOStream *mem_stream_new_size(size_t buf_n, size_t buf_max){
297    int err = -ENOMEM;
298    MemData *data = ALLOCATE(MemData);
299    IOStream *io = NULL;
300    if(!data) goto exit;
301    io = ALLOCATE(IOStream);
302    if(!io) goto exit;
303    if(buf_n <= delta_min){
304        buf_n = delta_min;
305    }
306    if(buf_max > 0 && buf_max < buf_n){
307        buf_max = buf_n;
308    }
309    data->buf = allocate(buf_n);
310    if(!data->buf) goto exit;
311    data->buf_n = buf_n;
312    data->buf_max = buf_max;
313    io->methods = &mem_methods;
314    io->data = data;
315    io->nofree = 0;
316    err = 0;
317  exit:
318    if(err){
319        deallocate(data);
320        deallocate(io);
321        io = NULL;
322    }
323    return io;
324}
Note: See TracBrowser for help on using the repository browser.