AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
ringbuf.h
Go to the documentation of this file.
1#ifndef _DS_RINGBUF_H
2#define _DS_RINGBUF_H
3
4#include <core/system.h>
5#include <mm/mm.h>
6#include <fs/iobuf.h>
7
8/*
9 * Ring buffers: a fixed-size buffer of bytes, written at its tail and read
10 * at its head, both wrapping around. A terminal's input and output, a
11 * pipe's data and the kernel's messages are kept in one.
12 */
13
14/* An index wrapped around into the ring. */
15#define RING_INDEX(ring, i) ((i) % ((ring)->size))
16
18struct ringbuf {
19 char *buf;
20 size_t size;
21 size_t head;
22 size_t tail;
23};
24
25/* A new static ring buffer of `sz` bytes. */
26#define RINGBUF_NEW(sz) (&(struct ringbuf){.buf = (char[sz]){0}, .size = sz, .head = 0, .tail = 0})
27
30static inline struct ringbuf *ringbuf_new(size_t size)
31{
32 struct ringbuf *ring = kmalloc(sizeof(struct ringbuf), &M_BUFFER, 0);
33
34 if (!ring)
35 return NULL;
36
37 ring->buf = kmalloc(size, &M_BUFFER, 0);
38
39 if (!ring->buf) {
40 kfree(ring);
41 return NULL;
42 }
43
44 ring->size = size;
45 ring->head = 0;
46 ring->tail = 0;
47
48 return ring;
49}
50
52static inline void ringbuf_free(struct ringbuf *r)
53{
54 if (!r)
55 return;
56
57 kfree(r->buf);
58 kfree(r);
59}
60
61/*
62 * The head and the tail are always in [0, size). The ring is empty when
63 * head == tail, and full when the tail is right behind the head, so a
64 * ring can hold at most size - 1 bytes.
65 */
66
68static inline size_t ringbuf_available(struct ringbuf *ring)
69{
70 return RING_INDEX(ring, ring->tail + ring->size - ring->head);
71}
72
75static inline size_t ringbuf_read(struct ringbuf *ring, size_t n, char *buf)
76{
77 size_t size = n;
78
79 while (n) {
80 if (ring->head == ring->tail) /* the ring is empty */
81 break;
82 *buf++ = ring->buf[ring->head];
83 ring->head = RING_INDEX(ring, ring->head + 1);
84 n--;
85 }
86
87 return size - n;
88}
89
92static inline size_t ringbuf_read_noconsume(struct ringbuf *ring, off_t off, size_t n, char *buf)
93{
94 size_t available = ringbuf_available(ring);
95
96 if (off < 0 || (size_t) off >= available)
97 return 0;
98
99 n = MIN(n, available - (size_t) off);
100
101 size_t head = RING_INDEX(ring, ring->head + (size_t) off);
102
103 for (size_t i = 0; i < n; ++i) {
104 *buf++ = ring->buf[head];
105 head = RING_INDEX(ring, head + 1);
106 }
107
108 return n;
109}
110
113static inline void ringbuf_discard(struct ringbuf *ring, size_t n)
114{
115 n = MIN(n, ringbuf_available(ring));
116 ring->head = RING_INDEX(ring, ring->head + n);
117}
118
121static inline size_t ringbuf_write(struct ringbuf *ring, size_t n, char *buf)
122{
123 size_t size = n;
124
125 while (n) {
126 if (RING_INDEX(ring, ring->tail + 1) == ring->head) /* the ring is full */
127 break;
128
129 ring->buf[ring->tail] = *buf++;
130 ring->tail = RING_INDEX(ring, ring->tail + 1);
131 n--;
132 }
133
134 return size - n;
135}
136
137/*
138 * Copying between a ring and an iobuf (a read()'s or a write()'s buffer
139 * in user memory): up to n bytes, one contiguous piece of the ring at a
140 * time. A piece is taken off (or added to) the ring only once it has been
141 * copied, so a bad address loses nothing. They return how many bytes were
142 * copied, or -EFAULT if none could be.
143 */
144
146static inline ssize_t ringbuf_read_iobuf(struct ringbuf *ring, size_t n, struct iobuf *io)
147{
148 size_t done = 0;
149
150 n = MIN(n, io->resid);
151
152 while (done < n && ring->head != ring->tail) {
153 /* up to the tail, or the end of the ring */
154 size_t end = ring->tail > ring->head ? ring->tail : ring->size;
155 ssize_t r = iobuf_out(io, ring->buf + ring->head, MIN(n - done, end - ring->head));
156
157 if (r < 0)
158 return done ? (ssize_t) done : r;
159
160 ring->head = RING_INDEX(ring, ring->head + r);
161 done += r;
162 }
163
164 return done;
165}
166
168static inline ssize_t ringbuf_write_iobuf(struct ringbuf *ring, size_t n, struct iobuf *io)
169{
170 size_t done = 0;
171
172 n = MIN(n, io->resid);
173
174 while (done < n && RING_INDEX(ring, ring->tail + 1) != ring->head) {
175 /* up to the slot before the head, or the end of the ring */
176 size_t end = ring->head > ring->tail ? ring->head - 1 :
177 ring->head ? ring->size : ring->size - 1;
178 ssize_t r = iobuf_in(io, ring->buf + ring->tail, MIN(n - done, end - ring->tail));
179
180 if (r < 0)
181 return done ? (ssize_t) done : r;
182
183 ring->tail = RING_INDEX(ring, ring->tail + r);
184 done += r;
185 }
186
187 return done;
188}
189
192static inline size_t ringbuf_write_overwrite(struct ringbuf *ring, size_t n, char *buf)
193{
194 size_t size = n;
195
196 while (n) {
197 if (RING_INDEX(ring, ring->tail + 1) == ring->head) {
198 /* the ring is full: drop the oldest byte */
199 ring->head = RING_INDEX(ring, ring->head + 1);
200 }
201
202 ring->buf[ring->tail] = *buf++;
203 ring->tail = RING_INDEX(ring, ring->tail + 1);
204 n--;
205 }
206
207 return size - n;
208}
209
210#endif /* ! _DS_RINGBUF_H */
#define MIN(a, b)
Definition system.h:11
ssize_t iobuf_out(struct iobuf *io, const void *src, size_t n)
Copies bytes from the kernel into the iobuf's buffer, and moves past them.
Definition iobuf.c:115
ssize_t iobuf_in(struct iobuf *io, void *dst, size_t n)
Copies bytes from the iobuf's buffer into the kernel, and moves past them.
Definition iobuf.c:135
void * kmalloc(size_t size, struct malloc_type *type, int flags)
Allocates memory for one of the kernel's structures.
Definition kvmem.c:123
void kfree(void *)
Frees an object that kmalloc() gave.
Definition kvmem.c:146
static size_t ringbuf_read(struct ringbuf *ring, size_t n, char *buf)
Reads up to n bytes from the ring into buf, and returns how many there were.
Definition ringbuf.h:75
#define RING_INDEX(ring, i)
Definition ringbuf.h:15
static size_t ringbuf_write_overwrite(struct ringbuf *ring, size_t n, char *buf)
Writes n bytes into the ring, throwing away its oldest bytes if it is full (the kernel's messages).
Definition ringbuf.h:192
static size_t ringbuf_available(struct ringbuf *ring)
Returns how many bytes the ring holds.
Definition ringbuf.h:68
static void ringbuf_discard(struct ringbuf *ring, size_t n)
Throws away the first n bytes of the ring, unread (at most what it holds).
Definition ringbuf.h:113
static size_t ringbuf_read_noconsume(struct ringbuf *ring, off_t off, size_t n, char *buf)
Copies up to n bytes from the ring, starting off bytes from its head, without taking them off it.
Definition ringbuf.h:92
static size_t ringbuf_write(struct ringbuf *ring, size_t n, char *buf)
Writes up to n bytes from buf into the ring, as many as there is room for, and returns how many.
Definition ringbuf.h:121
static ssize_t ringbuf_write_iobuf(struct ringbuf *ring, size_t n, struct iobuf *io)
Writes up to n bytes from an iobuf into the ring.
Definition ringbuf.h:168
static void ringbuf_free(struct ringbuf *r)
Frees a ring buffer that ringbuf_new() made (NULL does nothing).
Definition ringbuf.h:52
static ssize_t ringbuf_read_iobuf(struct ringbuf *ring, size_t n, struct iobuf *io)
Reads up to n bytes from the ring into an iobuf.
Definition ringbuf.h:146
static struct ringbuf * ringbuf_new(size_t size)
Returns a new ring buffer of size bytes, from kmalloc(), or NULL if there was no memory for it.
Definition ringbuf.h:30
#define NULL
Definition stddef.h:27
An iobuf.
Definition iobuf.h:35
size_t resid
Definition iobuf.h:38
A ring buffer.
Definition ringbuf.h:18
size_t head
Definition ringbuf.h:21
size_t tail
Definition ringbuf.h:22
char * buf
Definition ringbuf.h:19
size_t size
Definition ringbuf.h:20
long int ssize_t
Definition types.h:12
long int off_t
Definition types.h:10