1 /*
2 * Copyright (c) 2015 Machine Zone, Inc.
3 *
4 * Original author: Lev Walkin <lwalkin@machinezone.com>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27 #ifndef TCPKALI_RING_H
28 #define TCPKALI_RING_H
29
30 struct ring_buffer {
31 void *ptr;
32 void *left;
33 void *right;
34 size_t size; /* Buffer size, bytes */
35 size_t unit_size; /* Single unit size, bytes */
36 };
37
38 struct ring_buffer *ring_buffer_new(size_t unit_size);
39 void ring_buffer_init(struct ring_buffer *, size_t unit_size);
40
41 #define ring_buffer_free(rb) \
42 do { \
43 if(rb) { \
44 free(rb->ptr); \
45 free(rb); \
46 } \
47 } while(0)
48
49 /*
50 * Add a specified element to the ring.
51 * Returns non-zero value if the ring has grown because of it.
52 */
53 #define ring_buffer_add(rb, datum) \
54 ({ \
55 typeof(datum) d = datum; \
56 void *np = ring_buffer_next_right(rb); \
57 int grown = 0; \
58 if(!np) { \
59 ring_buffer_grow(rb); \
60 grown = 1; \
61 np = ring_buffer_next_right(rb); \
62 assert(np); \
63 } \
64 assert(rb->unit_size == sizeof(d)); \
65 typeof(d) *p = rb->right; \
66 rb->right = np; \
67 *p = d; \
68 grown; \
69 })
70
71 #define ring_buffer_get(rb, datump) \
72 ({ \
73 typeof(datump) p = rb->ptr; \
74 typeof(datump) l = rb->left; \
75 typeof(datump) r = rb->right; \
76 assert(rb->unit_size == sizeof(*p)); \
77 int got; \
78 if(l < r) { \
79 *(datump) = *l; \
80 rb->left = ++l; \
81 got = 1; \
82 } else if(l == r) { \
83 got = 0; \
84 } else { \
85 if((((char *)l - (char *)p)) < (ssize_t)rb->size) { \
86 *(datump) = *l; \
87 rb->left = ++l; \
88 got = 1; \
89 } else { \
90 l = p; \
91 if(l < r) { \
92 *(datump) = *l; \
93 rb->left = ++l; \
94 got = 1; \
95 } else { \
96 got = 0; \
97 } \
98 } \
99 } \
100 got; \
101 })
102
103 static inline void *__attribute__((unused))
ring_buffer_next_right(struct ring_buffer * rb)104 ring_buffer_next_right(struct ring_buffer *rb) {
105 char *p = rb->ptr, *l = rb->left, *r = rb->right;
106 if(r < l) {
107 r += rb->unit_size;
108 if(r >= l)
109 return 0;
110 else
111 return r;
112 } else {
113 if((r - p) < (ssize_t)(rb->size - rb->unit_size)) {
114 r += rb->unit_size;
115 assert((r - p) <= (ssize_t)rb->size);
116 return r;
117 } else {
118 if((l - p) <= (ssize_t)rb->unit_size)
119 return 0;
120 else
121 return p;
122 }
123 }
124 }
125
126
127 void ring_buffer_grow(struct ring_buffer *);
128
129 #endif /* TCPKALI_RING_H */
130