]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
5318d896 QY |
2 | /* |
3 | * Circular buffer implementation. | |
4 | * Copyright (C) 2017 Cumulus Networks | |
5 | * Quentin Young | |
5318d896 QY |
6 | */ |
7 | #include <zebra.h> | |
8 | ||
9 | #include "ringbuf.h" | |
10 | #include "memory.h" | |
11 | ||
bf8d3d6a | 12 | DEFINE_MTYPE_STATIC(LIB, RINGBUFFER, "Ring buffer"); |
5318d896 QY |
13 | |
14 | struct ringbuf *ringbuf_new(size_t size) | |
15 | { | |
16 | struct ringbuf *buf = XCALLOC(MTYPE_RINGBUFFER, sizeof(struct ringbuf)); | |
17 | buf->data = XCALLOC(MTYPE_RINGBUFFER, size); | |
18 | buf->size = size; | |
19 | buf->empty = true; | |
20 | return buf; | |
21 | } | |
22 | ||
23 | void ringbuf_del(struct ringbuf *buf) | |
24 | { | |
25 | XFREE(MTYPE_RINGBUFFER, buf->data); | |
26 | XFREE(MTYPE_RINGBUFFER, buf); | |
27 | } | |
28 | ||
29 | size_t ringbuf_remain(struct ringbuf *buf) | |
30 | { | |
31 | ssize_t diff = buf->end - buf->start; | |
32 | diff += ((diff == 0) && !buf->empty) ? buf->size : 0; | |
33 | diff += (diff < 0) ? buf->size : 0; | |
34 | return (size_t)diff; | |
35 | } | |
36 | ||
37 | size_t ringbuf_space(struct ringbuf *buf) | |
38 | { | |
39 | return buf->size - ringbuf_remain(buf); | |
40 | } | |
41 | ||
42 | size_t ringbuf_put(struct ringbuf *buf, const void *data, size_t size) | |
43 | { | |
44 | const uint8_t *dp = data; | |
45 | size_t space = ringbuf_space(buf); | |
46 | size_t copysize = MIN(size, space); | |
47 | size_t tocopy = copysize; | |
74e4a329 | 48 | if (tocopy >= buf->size - buf->end) { |
5318d896 QY |
49 | size_t ts = buf->size - buf->end; |
50 | memcpy(buf->data + buf->end, dp, ts); | |
51 | buf->end = 0; | |
52 | tocopy -= ts; | |
53 | dp += ts; | |
54 | } | |
55 | memcpy(buf->data + buf->end, dp, tocopy); | |
56 | buf->end += tocopy; | |
57 | buf->empty = (buf->start == buf->end) && (buf->empty && !copysize); | |
58 | return copysize; | |
59 | } | |
60 | ||
61 | size_t ringbuf_get(struct ringbuf *buf, void *data, size_t size) | |
62 | { | |
63 | uint8_t *dp = data; | |
64 | size_t remain = ringbuf_remain(buf); | |
65 | size_t copysize = MIN(remain, size); | |
66 | size_t tocopy = copysize; | |
a5080622 | 67 | if (tocopy >= buf->size - buf->start) { |
5318d896 QY |
68 | size_t ts = buf->size - buf->start; |
69 | memcpy(dp, buf->data + buf->start, ts); | |
70 | buf->start = 0; | |
71 | tocopy -= ts; | |
72 | dp += ts; | |
73 | } | |
74 | memcpy(dp, buf->data + buf->start, tocopy); | |
75 | buf->start = buf->start + tocopy; | |
76 | buf->empty = (buf->start == buf->end) && (buf->empty || copysize); | |
77 | return copysize; | |
78 | } | |
79 | ||
a5080622 QY |
80 | size_t ringbuf_peek(struct ringbuf *buf, size_t offset, void *data, size_t size) |
81 | { | |
82 | uint8_t *dp = data; | |
83 | size_t remain = ringbuf_remain(buf); | |
84 | if (offset >= remain) | |
85 | return 0; | |
996c9314 | 86 | size_t copysize = MAX(MIN(remain - offset, size), (size_t)0); |
a5080622 QY |
87 | size_t tocopy = copysize; |
88 | size_t cstart = (buf->start + offset) % buf->size; | |
89 | if (tocopy >= buf->size - cstart) { | |
90 | size_t ts = buf->size - cstart; | |
91 | memcpy(dp, buf->data + cstart, ts); | |
74e4a329 | 92 | cstart = 0; |
a5080622 QY |
93 | tocopy -= ts; |
94 | dp += ts; | |
95 | } | |
96 | memcpy(dp, buf->data + cstart, tocopy); | |
97 | return copysize; | |
98 | } | |
99 | ||
cb94eaeb QY |
100 | size_t ringbuf_copy(struct ringbuf *to, struct ringbuf *from, size_t size) |
101 | { | |
102 | size_t tocopy = MIN(ringbuf_space(to), size); | |
103 | uint8_t *cbuf = XCALLOC(MTYPE_TMP, tocopy); | |
104 | tocopy = ringbuf_peek(from, 0, cbuf, tocopy); | |
74e4a329 | 105 | size_t put = ringbuf_put(to, cbuf, tocopy); |
cb94eaeb | 106 | XFREE(MTYPE_TMP, cbuf); |
74e4a329 | 107 | return put; |
cb94eaeb QY |
108 | } |
109 | ||
5318d896 QY |
110 | void ringbuf_reset(struct ringbuf *buf) |
111 | { | |
112 | buf->start = buf->end = 0; | |
113 | buf->empty = true; | |
114 | } | |
115 | ||
116 | void ringbuf_wipe(struct ringbuf *buf) | |
117 | { | |
118 | memset(buf->data, 0x00, buf->size); | |
119 | ringbuf_reset(buf); | |
5318d896 | 120 | } |