Annotation of libelwix/src/ring.c, revision 1.7
1.2 misho 1: /*************************************************************************
2: * (C) 2025 AITNET ltd - Sofia/Bulgaria - <misho@aitnet.org>
3: * by Michael Pounov <misho@elwix.org>
4: *
5: * $Author: misho $
1.7 ! misho 6: * $Id: ring.c,v 1.6.4.1 2026/02/18 01:23:04 misho Exp $
1.2 misho 7: *
8: **************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
1.5 misho 15: Copyright 2004 - 2026
1.2 misho 16: by Michael Pounov <misho@elwix.org>. All rights reserved.
17:
18: Redistribution and use in source and binary forms, with or without
19: modification, are permitted provided that the following conditions
20: are met:
21: 1. Redistributions of source code must retain the above copyright
22: notice, this list of conditions and the following disclaimer.
23: 2. Redistributions in binary form must reproduce the above copyright
24: notice, this list of conditions and the following disclaimer in the
25: documentation and/or other materials provided with the distribution.
26: 3. All advertising materials mentioning features or use of this software
27: must display the following acknowledgement:
28: This product includes software developed by Michael Pounov <misho@elwix.org>
29: ELWIX - Embedded LightWeight unIX and its contributors.
30: 4. Neither the name of AITNET nor the names of its contributors
31: may be used to endorse or promote products derived from this software
32: without specific prior written permission.
33:
34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: SUCH DAMAGE.
45: */
46: #include "global.h"
47:
48:
49: /*
50: * rbuf_init() - Init ring buffer
51: *
52: * @rbuf = Ring buffer
53: * @num = Number of elements in buffer
54: * return: -1 error or 0 ok
55: */
56: int
57: rbuf_init(ringbuf_t *rbuf, int num)
58: {
59: if (!rbuf)
60: return -1;
61:
1.3 misho 62: atomic_store_explicit((atomic_int*) &rbuf->rb_head, 0, memory_order_relaxed);
63: atomic_store_explicit((atomic_int*) &rbuf->rb_tail, 0, memory_order_relaxed);
1.2 misho 64:
65: rbuf->rb_buffer = e_calloc(num, sizeof(struct iovec));
66: if (!rbuf->rb_buffer)
67: return -1;
68: else
69: rbuf->rb_bufnum = num;
70: memset(rbuf->rb_buffer, 0, num * sizeof(struct iovec));
71:
72: return 0;
73: }
74:
75: /*
76: * rbuf_free() - Free ring buffer
77: *
78: * @rbuf = Ring buffer
79: * return: none
80: */
81: void
82: rbuf_free(ringbuf_t *rbuf)
83: {
84: if (!rbuf)
85: return;
86:
87: if (rbuf->rb_buffer) {
88: e_free(rbuf->rb_buffer);
89: rbuf->rb_buffer = NULL;
90: rbuf->rb_bufnum = 0;
91: }
92:
1.3 misho 93: atomic_store_explicit((atomic_int*) &rbuf->rb_head, 0, memory_order_relaxed);
94: atomic_store_explicit((atomic_int*) &rbuf->rb_tail, 0, memory_order_relaxed);
1.2 misho 95: }
96:
97: /*
98: * rbuf_purge() - Purge all buffer
99: *
100: * @rbuf = Ring buffer
101: * return: none
102: */
103: void
104: rbuf_purge(ringbuf_t *rbuf)
105: {
106: if (!rbuf)
107: return;
108:
109: if (rbuf->rb_buffer)
110: memset(rbuf->rb_buffer, 0, rbuf->rb_bufnum * sizeof(struct iovec));
111:
1.3 misho 112: atomic_store_explicit((atomic_int*) &rbuf->rb_head, 0, memory_order_relaxed);
113: atomic_store_explicit((atomic_int*) &rbuf->rb_tail, 0, memory_order_relaxed);
1.2 misho 114: }
115:
116: /*
117: * rbuf_isempty() - Check buffer is empty
118: *
119: * @rbuf = Ring buffer
120: * return: -1 error, 0 it isn't empty
121: */
122: int
123: rbuf_isempty(ringbuf_t *rbuf)
124: {
125: if (!rbuf)
126: return -1;
127:
1.3 misho 128: return (atomic_load_explicit((atomic_int*) &rbuf->rb_head, memory_order_acquire) ==
129: atomic_load_explicit((atomic_int*) &rbuf->rb_tail, memory_order_acquire));
1.2 misho 130: }
131:
132: /*
133: * rbuf_isfull() - Check buffer is full
134: *
135: * @rbuf = Ring buffer
136: * return: -1 error or 0 it isn't full
137: */
138: int
139: rbuf_isfull(ringbuf_t *rbuf)
140: {
141: if (!rbuf)
142: return -1;
143: if (!rbuf->rb_bufnum)
144: return 1;
145:
1.7 ! misho 146: return (((atomic_load_explicit((atomic_int*) &rbuf->rb_head, memory_order_relaxed) + 1) % rbuf->rb_bufnum) ==
! 147: atomic_load_explicit((atomic_int*) &rbuf->rb_tail, memory_order_acquire));
1.2 misho 148: }
149:
150: /*
151: * rbuf_enqueue() - Enqueue data to buffer
152: *
153: * @rbuf = Ring buffer
154: * @data = Data
155: * @len = Length
156: * return: -1 error, 1 buffer is full or 0 ok
157: */
158: int
159: rbuf_enqueue(ringbuf_t *rbuf, void *data, size_t len)
160: {
161: int h, t, n;
162: struct iovec *iov;
163:
164: if (!rbuf || !rbuf->rb_buffer)
165: return -1;
166: if (!rbuf->rb_bufnum)
167: return 1;
168:
1.3 misho 169: h = atomic_load_explicit((atomic_int*) &rbuf->rb_head, memory_order_relaxed);
170: t = atomic_load_explicit((atomic_int*) &rbuf->rb_tail, memory_order_acquire);
1.2 misho 171: n = (h + 1) % rbuf->rb_bufnum;
172:
173: if (n == t)
174: return 1;
175:
176: iov = rbuf->rb_buffer + h;
177: iov->iov_len = len;
178: iov->iov_base = data;
179:
1.3 misho 180: atomic_store_explicit((atomic_int*) &rbuf->rb_head, n, memory_order_release);
1.2 misho 181: return 0;
182: }
183:
184: /*
185: * rbuf_dequeue() - Dequeue data from buffer
186: *
187: * @rbuf = Ring buffer
188: * @out = Data, if =NULL, just dequeue data
189: * return: -1 error, 1 buffer is empty or 0 ok
190: */
191: int
1.4 misho 192: rbuf_dequeue(ringbuf_t *rbuf, struct iovec **out)
1.2 misho 193: {
194: int h, t, n;
195:
196: if (!rbuf || !rbuf->rb_buffer)
197: return -1;
198: if (!rbuf->rb_bufnum)
199: return 1;
200:
1.3 misho 201: h = atomic_load_explicit((atomic_int*) &rbuf->rb_head, memory_order_acquire);
202: t = atomic_load_explicit((atomic_int*) &rbuf->rb_tail, memory_order_relaxed);
1.2 misho 203: n = (t + 1) % rbuf->rb_bufnum;
204:
205: if (h == t)
206: return 1;
207:
208: if (out)
1.4 misho 209: *out = rbuf->rb_buffer + t;
1.2 misho 210:
1.3 misho 211: atomic_store_explicit((atomic_int*) &rbuf->rb_tail, n, memory_order_release);
1.2 misho 212: return 0;
213: }
1.5 misho 214:
215:
216: /*
217: * lrb_init() - Init linear ring buffer
218: *
219: * @lrb = Linear ring buffer
220: * @size = Size of ring buffer
221: * return: -1 error or 0 ok
222: */
223: int
224: lrb_init(lrbuf_t *lrb, u_int size)
225: {
226: if (!lrb)
227: return -1;
228:
229: atomic_store_explicit((atomic_int*) &lrb->lrb_head, 0, memory_order_relaxed);
230: atomic_store_explicit((atomic_int*) &lrb->lrb_tail, 0, memory_order_relaxed);
231:
232: lrb->lrb_data = e_malloc(size);
233: if (!lrb->lrb_data)
234: return -1;
235: else
236: lrb->lrb_size = size;
237: memset(lrb->lrb_data, 0, lrb->lrb_size);
238:
239: return 0;
240: }
241:
242: /*
243: * lrb_free() - Free linear ring buffer
244: *
245: * @lrb = Linear ring buffer
246: * return: none
247: */
248: void
249: lrb_free(lrbuf_t *lrb)
250: {
251: if (!lrb)
252: return;
253:
254: if (lrb->lrb_data) {
255: e_free(lrb->lrb_data);
256: lrb->lrb_data = NULL;
257: lrb->lrb_size = 0;
258: }
259:
260: atomic_store_explicit((atomic_int*) &lrb->lrb_head, 0, memory_order_relaxed);
261: atomic_store_explicit((atomic_int*) &lrb->lrb_tail, 0, memory_order_relaxed);
262: }
263:
264: /*
265: * lrb_purge() - Purge all buffer
266: *
267: * @lrb = Linear ring buffer
268: * return: none
269: */
270: void
271: lrb_purge(lrbuf_t *lrb)
272: {
273: if (!lrb)
274: return;
275:
276: if (lrb->lrb_data)
277: memset(lrb->lrb_data, 0, lrb->lrb_size);
278:
279: atomic_store_explicit((atomic_int*) &lrb->lrb_head, 0, memory_order_relaxed);
280: atomic_store_explicit((atomic_int*) &lrb->lrb_tail, 0, memory_order_relaxed);
281: atomic_store_explicit((atomic_int*) &lrb->lrb_full, 0, memory_order_relaxed);
282: }
283:
284: /*
285: * lrb_isempty() - Check buffer is empty
286: *
287: * @lrb = Linear ring buffer
288: * return: -1 error, 0 it isn't empty
289: */
290: int
291: lrb_isempty(lrbuf_t *lrb)
292: {
293: if (!lrb)
294: return -1;
295:
296: return (!atomic_load_explicit((atomic_int*) &lrb->lrb_full, memory_order_acquire) &&
297: (atomic_load_explicit((atomic_int*) &lrb->lrb_head, memory_order_acquire) ==
298: atomic_load_explicit((atomic_int*) &lrb->lrb_tail, memory_order_acquire)));
299: }
300:
301: /*
302: * lrb_isfull() - Check buffer is full
303: *
304: * @lrb = Linear ring buffer
305: * return: -1 error or 0 it isn't full
306: */
307: int
308: lrb_isfull(lrbuf_t *lrb)
309: {
310: int h, t;
311:
312: if (!lrb)
313: return -1;
314: if (!lrb->lrb_size)
315: return 1;
316:
317: if (!atomic_load_explicit((atomic_int*) &lrb->lrb_full, memory_order_acquire))
318: return 0;
319:
320: t = atomic_load_explicit((atomic_int*) &lrb->lrb_tail, memory_order_acquire);
321: h = atomic_load_explicit((atomic_int*) &lrb->lrb_head, memory_order_acquire);
322: return (h == t);
323: }
324:
325: /*
1.6 misho 326: * lrb_getw() - Get address for write
327: *
328: * @lrb = Linear ring buffer
329: * @len = Return available buffer length for write
330: * return: NULL error or !=NULL pointer for write
331: * remark: After use of lrb_getw() and write to pointer.
332: * You should update ring buffer with lrb_enqueue(,NULL,wrote_len,)
333: */
334: void *
335: lrb_getw(lrbuf_t *lrb, size_t *len)
336: {
337: int h;
338:
339: if (!lrb || !lrb->lrb_data || !lrb->lrb_size)
340: return NULL;
341:
342: h = atomic_load_explicit((atomic_int*) &lrb->lrb_head, memory_order_relaxed);
343: if (len)
344: *len = lrb->lrb_size - h;
345:
346: return (lrb->lrb_data + h);
347: }
348:
349: /*
1.5 misho 350: * lrb_enqueue() - Enqueue data to buffer
351: *
352: * @lrb = Linear ring buffer
353: * @data = Data
354: * @len = Length
355: * @lost = Permit to lost data
356: * return: -1 error, 1 buffer is full or 0 ok
357: */
358: int
359: lrb_enqueue(lrbuf_t *lrb, void *data, size_t len, int lost)
360: {
1.6 misho 361: int h, t = 0, n, t2 = 0, unused, drop = 0;
1.5 misho 362:
363: if (!lrb || !lrb->lrb_data)
364: return -1;
365: if (!lrb->lrb_size || lrb->lrb_size <= len)
366: return 1;
367:
368: lrb_unused(lrb, unused);
369: if (!lost) {
370: if (len > unused)
371: return 1;
372: } else {
373: drop = len - unused;
374: if(drop < 0)
375: drop ^= drop;
376: }
377:
378: if (drop > 0) {
379: t = atomic_load_explicit((atomic_int*) &lrb->lrb_tail, memory_order_acquire);
380: t2 = (t + drop) % lrb->lrb_size;
381: }
382: h = atomic_load_explicit((atomic_int*) &lrb->lrb_head, memory_order_relaxed);
383: n = lrb->lrb_size - h;
384: if (len < n) {
1.6 misho 385: if (data)
386: memcpy(lrb->lrb_data + h, data, len);
1.5 misho 387: n = h + len;
388: } else {
1.6 misho 389: if (data) {
390: memcpy(lrb->lrb_data + h, data, n);
391: memcpy(lrb->lrb_data, data + n, len - n);
392: }
1.5 misho 393: n = len - n;
394: }
395:
396: h = n;
397: atomic_store_explicit((atomic_int*) &lrb->lrb_head, h, memory_order_release);
398: if (drop > 0)
399: while (42) {
400: n = t;
401: if (atomic_compare_exchange_weak_explicit((atomic_int*) &lrb->lrb_tail,
402: &n, t2, memory_order_release, memory_order_relaxed))
403: break;
404: t = n;
405: t2 = (t + drop) % lrb->lrb_size;
406: }
407: else
408: t2 = atomic_load_explicit((atomic_int*) &lrb->lrb_tail, memory_order_acquire);
409: atomic_store_explicit((atomic_int*) &lrb->lrb_full, (h == t2), memory_order_release);
410: return 0;
411: }
412:
413: /*
1.6 misho 414: * lrb_getr() - Get address for read
415: *
416: * @lrb = Linear ring buffer
417: * @len = Return available data length for read
418: * return: NULL error or !=NULL pointer for read
419: * remark: After use of lrb_getr() and read from pointer.
420: * You could update ring buffer with lrb_dequeue(,NULL,read_len)
421: */
422: void *
423: lrb_getr(lrbuf_t *lrb, size_t *len)
424: {
425: int t;
426:
427: if (!lrb || !lrb->lrb_data || !lrb->lrb_size)
428: return NULL;
429:
430: t = atomic_load_explicit((atomic_int*) &lrb->lrb_tail, memory_order_acquire);
431: if (len)
432: lrb_queued(lrb, *len);
433:
434: return (lrb->lrb_data + t);
435: }
436:
437: /*
1.5 misho 438: * lrb_dequeue() - Dequeue data from buffer
439: *
440: * @lrb = Linear ring buffer
441: * @data = Data, if =NULL, just dequeue data
442: * @len = Length of data
443: * return: -1 error, 0 buffer is empty or >0 stored data bytes
444: */
445: int
446: lrb_dequeue(lrbuf_t *lrb, void *data, size_t len)
447: {
448: int h, t, t2, n, l, f;
449:
450: if (!lrb)
451: return -1;
452: if (!lrb->lrb_size || !len || lrb_isempty(lrb))
453: return 0;
454: if (lrb->lrb_size <= len)
455: len = lrb->lrb_size - 1;
456:
457: while (42) {
458: t = atomic_load_explicit((atomic_int*) &lrb->lrb_tail, memory_order_acquire);
459: h = atomic_load_explicit((atomic_int*) &lrb->lrb_head, memory_order_acquire);
460: f = atomic_load_explicit((atomic_int*) &lrb->lrb_full, memory_order_acquire);
461:
462: l = h - t;
463: if (l < 0)
464: l += lrb->lrb_size;
465: if (!l) {
466: if (!f)
467: return 0;
468: l = lrb->lrb_size;
469: }
470: if (l > len)
471: l = len;
472:
473: n = lrb->lrb_size - t;
474: if (l < n) {
475: if (data)
476: memcpy(data, lrb->lrb_data + t, l);
477: t2 = t + l;
478: } else {
479: if (data) {
480: memcpy(data, lrb->lrb_data + t, n);
481: memcpy(data + n, lrb->lrb_data, l - n);
482: }
483: t2 = l - n;
484: }
485:
486: n = t;
487: if (atomic_compare_exchange_weak_explicit((atomic_int*) &lrb->lrb_tail,
488: &n, t2, memory_order_release, memory_order_relaxed)) {
489: atomic_store_explicit((atomic_int*) &lrb->lrb_full, 0, memory_order_release);
490: return l;
491: }
492: }
493:
494: return 0;
495: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>