~ubuntu-branches/ubuntu/utopic/xen/utopic

« back to all changes in this revision

Viewing changes to tools/vnet/libxutil/mem_stream.c

  • Committer: Bazaar Package Importer
  • Author(s): Bastian Blank
  • Date: 2010-05-06 15:47:38 UTC
  • mto: (1.3.1) (15.1.1 sid) (4.1.1 experimental)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20100506154738-agoz0rlafrh1fnq7
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 */
 
44
typedef 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
 */
 
64
static 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
 */
 
73
static 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
 */
 
82
static 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
 */
 
91
static 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
 */
 
100
static inline char * mem_end(struct MemData *data){
 
101
    return data->buf + data->buf_n;
 
102
}
 
103
 
 
104
static int mem_error(IOStream *io);
 
105
static int mem_close(IOStream *io);
 
106
static void mem_free(IOStream *io);
 
107
static int mem_write(IOStream *io, const void *msg, size_t n);
 
108
static int mem_read(IOStream *io, void *buf, size_t n);
 
109
 
 
110
/** Minimum delta used to increment the buffer. */
 
111
static int delta_min = 256;
 
112
 
 
113
/** Methods for a memory stream. */
 
114
static 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
 */
 
127
static 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
 */
 
136
int 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
 */
 
147
static 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
 */
 
165
static 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
 */
 
183
static 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
 */
 
222
static 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
 */
 
243
static 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
 */
 
261
static 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
 */
 
271
static 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
 */
 
283
static 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
 */
 
296
IOStream *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
}