2 * Copyright 2005-2008, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
7 #include "ring_buffer.h"
9 #include <KernelExport.h>
18 #ifndef HAIKU_TARGET_PLATFORM_HAIKU
19 #define user_memcpy(x...) (memcpy(x), B_OK)
22 /*! This is a light-weight ring_buffer implementation.
23 * It does not provide any locking - you are supposed to ensure thread-safety
24 * with the restrictions you choose. Unless you are passing in unsafe buffers,
25 * the functions are safe to be called with interrupts turned off as well (not
26 * the user functions).
27 * They also don't use malloc() or any kind of locking after initialization.
32 space_left_in_buffer(struct ring_buffer
*buffer
)
34 return buffer
->size
- buffer
->in
;
39 read_from_buffer(struct ring_buffer
*buffer
, uint8
*data
, ssize_t length
,
42 int32 available
= buffer
->in
;
44 if (length
> available
)
50 ssize_t bytesRead
= length
;
52 if (buffer
->first
+ length
<= buffer
->size
) {
55 if (user_memcpy(data
, buffer
->buffer
+ buffer
->first
, length
) < B_OK
)
58 memcpy(data
, buffer
->buffer
+ buffer
->first
, length
);
60 // need to copy both ends
61 size_t upper
= buffer
->size
- buffer
->first
;
62 size_t lower
= length
- upper
;
65 if (user_memcpy(data
, buffer
->buffer
+ buffer
->first
, upper
) < B_OK
66 || user_memcpy(data
+ upper
, buffer
->buffer
, lower
) < B_OK
)
69 memcpy(data
, buffer
->buffer
+ buffer
->first
, upper
);
70 memcpy(data
+ upper
, buffer
->buffer
, lower
);
74 buffer
->first
= (buffer
->first
+ bytesRead
) % buffer
->size
;
75 buffer
->in
-= bytesRead
;
82 write_to_buffer(struct ring_buffer
*buffer
, const uint8
*data
, ssize_t length
,
85 int32 left
= space_left_in_buffer(buffer
);
92 ssize_t bytesWritten
= length
;
93 int32 position
= (buffer
->first
+ buffer
->in
) % buffer
->size
;
95 if (position
+ length
<= buffer
->size
) {
98 if (user_memcpy(buffer
->buffer
+ position
, data
, length
) < B_OK
)
101 memcpy(buffer
->buffer
+ position
, data
, length
);
103 // need to copy both ends
104 size_t upper
= buffer
->size
- position
;
105 size_t lower
= length
- upper
;
108 if (user_memcpy(buffer
->buffer
+ position
, data
, upper
) < B_OK
109 || user_memcpy(buffer
->buffer
, data
+ upper
, lower
) < B_OK
)
110 return B_BAD_ADDRESS
;
112 memcpy(buffer
->buffer
+ position
, data
, upper
);
113 memcpy(buffer
->buffer
, data
+ upper
, lower
);
117 buffer
->in
+= bytesWritten
;
127 create_ring_buffer(size_t size
)
129 return create_ring_buffer_etc(NULL
, size
, 0);
134 create_ring_buffer_etc(void* memory
, size_t size
, uint32 flags
)
136 if (memory
== NULL
) {
137 ring_buffer
* buffer
= (ring_buffer
*)malloc(sizeof(ring_buffer
) + size
);
142 ring_buffer_clear(buffer
);
147 size
-= sizeof(ring_buffer
);
148 ring_buffer
* buffer
= (ring_buffer
*)memory
;
151 if ((flags
& RING_BUFFER_INIT_FROM_BUFFER
) != 0
152 && (size_t)buffer
->size
== size
153 && buffer
->in
>= 0 && (size_t)buffer
->in
<= size
154 && buffer
->first
>= 0 && (size_t)buffer
->first
< size
) {
155 // structure looks valid
157 ring_buffer_clear(buffer
);
164 delete_ring_buffer(struct ring_buffer
*buffer
)
171 ring_buffer_clear(struct ring_buffer
*buffer
)
179 ring_buffer_readable(struct ring_buffer
*buffer
)
186 ring_buffer_writable(struct ring_buffer
*buffer
)
188 return buffer
->size
- buffer
->in
;
193 ring_buffer_flush(struct ring_buffer
*buffer
, size_t length
)
195 // we can't flush more bytes than there are
196 if (length
> (size_t)buffer
->in
)
199 buffer
->in
-= length
;
200 buffer
->first
= (buffer
->first
+ length
) % buffer
->size
;
205 ring_buffer_read(struct ring_buffer
*buffer
, uint8
*data
, ssize_t length
)
207 return read_from_buffer(buffer
, data
, length
, false);
212 ring_buffer_write(struct ring_buffer
*buffer
, const uint8
*data
, ssize_t length
)
214 return write_to_buffer(buffer
, data
, length
, false);
219 ring_buffer_user_read(struct ring_buffer
*buffer
, uint8
*data
, ssize_t length
)
221 return read_from_buffer(buffer
, data
, length
, true);
226 ring_buffer_user_write(struct ring_buffer
*buffer
, const uint8
*data
, ssize_t length
)
228 return write_to_buffer(buffer
, data
, length
, true);
232 /*! Reads data from the ring buffer, but doesn't remove the data from it.
233 \param buffer The ring buffer.
234 \param offset The offset relative to the beginning of the data in the ring
235 buffer at which to start reading.
236 \param data The buffer to which to copy the data.
237 \param length The number of bytes to read at maximum.
238 \return The number of bytes actually read from the buffer.
241 ring_buffer_peek(struct ring_buffer
* buffer
, size_t offset
, void* data
,
244 size_t available
= buffer
->in
;
246 if (offset
>= available
|| length
== 0)
249 if (offset
+ length
> available
)
250 length
= available
- offset
;
252 if ((offset
+= buffer
->first
) >= (size_t)buffer
->size
)
253 offset
-= buffer
->size
;
255 if (offset
+ length
<= (size_t)buffer
->size
) {
257 memcpy(data
, buffer
->buffer
+ offset
, length
);
259 // need to copy both ends
260 size_t upper
= buffer
->size
- offset
;
261 size_t lower
= length
- upper
;
263 memcpy(data
, buffer
->buffer
+ offset
, upper
);
264 memcpy((uint8
*)data
+ upper
, buffer
->buffer
, lower
);
271 /*! Returns iovecs describing the contents of the ring buffer.
273 \param buffer The ring buffer.
274 \param vecs Pointer to an iovec array with at least 2 elements to be filled
276 \return The number of iovecs the function has filled in to describe the
277 contents of the ring buffer. \c 0, if empty, \c 2 at maximum.
280 ring_buffer_get_vecs(struct ring_buffer
* buffer
, struct iovec
* vecs
)
285 if (buffer
->first
+ buffer
->in
<= buffer
->size
) {
287 vecs
[0].iov_base
= buffer
->buffer
+ buffer
->first
;
288 vecs
[0].iov_len
= buffer
->in
;
293 size_t upper
= buffer
->size
- buffer
->first
;
294 size_t lower
= buffer
->in
- upper
;
296 vecs
[0].iov_base
= buffer
->buffer
+ buffer
->first
;
297 vecs
[0].iov_len
= upper
;
298 vecs
[1].iov_base
= buffer
->buffer
;
299 vecs
[1].iov_len
= lower
;
306 /** Sends the contents of the ring buffer to a port.
307 * The buffer will be empty afterwards only if sending the data actually works.
311 ring_buffer_write_to_port(struct ring_buffer
*buffer
, port_id port
, int32 code
,
312 uint32 flags
, bigtime_t timeout
)
314 int32 length
= buffer
->in
;
320 if (buffer
->first
+ length
<= buffer
->size
) {
322 status
= write_port_etc(port
, code
, buffer
->buffer
+ buffer
->first
, length
,
325 // need to write both ends
326 size_t upper
= buffer
->size
- buffer
->first
;
327 size_t lower
= length
- upper
;
330 vecs
[0].iov_base
= buffer
->buffer
+ buffer
->first
;
331 vecs
[0].iov_len
= upper
;
332 vecs
[1].iov_base
= buffer
->buffer
;
333 vecs
[1].iov_len
= lower
;
335 status
= writev_port_etc(port
, code
, vecs
, 2, length
, flags
, timeout
);
341 buffer
->first
= (buffer
->first
+ length
) % buffer
->size
;
342 buffer
->in
-= length
;