Annotation of libelwix/src/ring.c, revision 1.10
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.10 ! misho 6: * $Id: ring.c,v 1.9.4.1 2026/07/27 20:12:35 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.9 misho 62: atomic_store_explicit((atomic_int*) &rbuf->rb_head, 0, memory_order_release);
63: atomic_store_explicit((atomic_int*) &rbuf->rb_tail, 0, memory_order_release);
64: atomic_store_explicit((atomic_int*) &rbuf->rb_full, 0, memory_order_release);
1.2 misho 65:
66: rbuf->rb_buffer = e_calloc(num, sizeof(struct iovec));
67: if (!rbuf->rb_buffer)
68: return -1;
69: else
70: rbuf->rb_bufnum = num;
71: memset(rbuf->rb_buffer, 0, num * sizeof(struct iovec));
72:
73: return 0;
74: }
75:
76: /*
77: * rbuf_free() - Free ring buffer
78: *
79: * @rbuf = Ring buffer
80: * return: none
81: */
82: void
83: rbuf_free(ringbuf_t *rbuf)
84: {
85: if (!rbuf)
86: return;
87:
88: if (rbuf->rb_buffer) {
89: e_free(rbuf->rb_buffer);
90: rbuf->rb_buffer = NULL;
91: rbuf->rb_bufnum = 0;
92: }
93:
1.9 misho 94: atomic_store_explicit((atomic_int*) &rbuf->rb_head, 0, memory_order_release);
95: atomic_store_explicit((atomic_int*) &rbuf->rb_tail, 0, memory_order_release);
96: atomic_store_explicit((atomic_int*) &rbuf->rb_full, 0, memory_order_release);
1.2 misho 97: }
98:
99: /*
100: * rbuf_purge() - Purge all buffer
101: *
102: * @rbuf = Ring buffer
103: * return: none
104: */
105: void
106: rbuf_purge(ringbuf_t *rbuf)
107: {
108: if (!rbuf)
109: return;
110:
111: if (rbuf->rb_buffer)
112: memset(rbuf->rb_buffer, 0, rbuf->rb_bufnum * sizeof(struct iovec));
113:
1.9 misho 114: atomic_store_explicit((atomic_int*) &rbuf->rb_head, 0, memory_order_release);
115: atomic_store_explicit((atomic_int*) &rbuf->rb_tail, 0, memory_order_release);
116: atomic_store_explicit((atomic_int*) &rbuf->rb_full, 0, memory_order_release);
1.2 misho 117: }
118:
119: /*
120: * rbuf_isempty() - Check buffer is empty
121: *
122: * @rbuf = Ring buffer
123: * return: -1 error, 0 it isn't empty
124: */
125: int
126: rbuf_isempty(ringbuf_t *rbuf)
127: {
1.8 misho 128: if (!rbuf || !rbuf->rb_bufnum)
1.2 misho 129: return -1;
130:
1.8 misho 131: if (atomic_load_explicit((atomic_int*) &rbuf->rb_full, memory_order_acquire))
132: return 0;
133:
1.3 misho 134: return (atomic_load_explicit((atomic_int*) &rbuf->rb_head, memory_order_acquire) ==
1.8 misho 135: atomic_load_explicit((atomic_int*) &rbuf->rb_tail, memory_order_acquire));
1.2 misho 136: }
137:
138: /*
139: * rbuf_isfull() - Check buffer is full
140: *
141: * @rbuf = Ring buffer
142: * return: -1 error or 0 it isn't full
143: */
144: int
145: rbuf_isfull(ringbuf_t *rbuf)
146: {
1.8 misho 147: int h, t;
148:
149: if (!rbuf || !rbuf->rb_bufnum)
1.2 misho 150: return -1;
151:
1.8 misho 152: if (!atomic_load_explicit((atomic_int*) &rbuf->rb_full, memory_order_acquire))
153: return 0;
154:
155: t = atomic_load_explicit((atomic_int*) &rbuf->rb_tail, memory_order_acquire);
156: h = atomic_load_explicit((atomic_int*) &rbuf->rb_head, memory_order_acquire);
157: return (h == t);
1.2 misho 158: }
159:
160: /*
161: * rbuf_enqueue() - Enqueue data to buffer
162: *
163: * @rbuf = Ring buffer
164: * @data = Data
165: * @len = Length
1.8 misho 166: * @lost = Permit to lost data
1.2 misho 167: * return: -1 error, 1 buffer is full or 0 ok
168: */
169: int
1.8 misho 170: rbuf_enqueue(ringbuf_t *rbuf, void *data, size_t len, int lost)
1.2 misho 171: {
1.8 misho 172: int h, t, f, n, t2, drop = 0;
1.2 misho 173: struct iovec *iov;
174:
1.8 misho 175: if (!rbuf || !rbuf->rb_buffer || !rbuf->rb_bufnum)
1.2 misho 176: return -1;
177:
1.8 misho 178: f = atomic_load_explicit((atomic_int*) &rbuf->rb_full, memory_order_acquire);
1.3 misho 179: t = atomic_load_explicit((atomic_int*) &rbuf->rb_tail, memory_order_acquire);
1.8 misho 180: h = atomic_load_explicit((atomic_int*) &rbuf->rb_head, memory_order_acquire);
181:
182: if (f && h == t) {
183: if (!lost)
184: return 1;
185: else
186: drop = 1;
187: }
188:
1.2 misho 189: n = (h + 1) % rbuf->rb_bufnum;
190:
191: iov = rbuf->rb_buffer + h;
192: iov->iov_len = len;
193: iov->iov_base = data;
194:
1.3 misho 195: atomic_store_explicit((atomic_int*) &rbuf->rb_head, n, memory_order_release);
1.8 misho 196: if (drop) {
197: t2 = (t + 1) % rbuf->rb_bufnum;
198: while (42) {
199: drop = t;
200: if (atomic_compare_exchange_weak_explicit((atomic_int*) &rbuf->rb_tail,
201: &drop, t2, memory_order_release, memory_order_relaxed))
202: break;
203: t = drop;
204: t2 = (t + 1) % rbuf->rb_bufnum;
205: }
206: } else
207: t2 = atomic_load_explicit((atomic_int*) &rbuf->rb_tail, memory_order_acquire);
208: atomic_store_explicit((atomic_int*) &rbuf->rb_full, (n == t2), memory_order_release);
1.2 misho 209: return 0;
210: }
211:
212: /*
213: * rbuf_dequeue() - Dequeue data from buffer
214: *
215: * @rbuf = Ring buffer
216: * @out = Data, if =NULL, just dequeue data
1.10 ! misho 217: * @peek = Peek only data, keep the same tail position
1.2 misho 218: * return: -1 error, 1 buffer is empty or 0 ok
219: */
220: int
1.10 ! misho 221: rbuf_dequeue(ringbuf_t *rbuf, struct iovec **out, int peek)
1.2 misho 222: {
1.8 misho 223: int h, t, n, f;
1.2 misho 224:
1.8 misho 225: if (!rbuf || !rbuf->rb_buffer || !rbuf->rb_bufnum)
1.2 misho 226: return -1;
227:
1.8 misho 228: while (42) {
229: h = atomic_load_explicit((atomic_int*) &rbuf->rb_head, memory_order_acquire);
230: f = atomic_load_explicit((atomic_int*) &rbuf->rb_full, memory_order_acquire);
231: t = atomic_load_explicit((atomic_int*) &rbuf->rb_tail, memory_order_acquire);
232:
233: if (!f && h == t)
234: return 1;
235:
236: n = (t + 1) % rbuf->rb_bufnum;
1.2 misho 237:
1.10 ! misho 238: if (out)
! 239: *out = rbuf->rb_buffer + t;
! 240:
! 241: if (peek)
! 242: break;
! 243:
1.8 misho 244: f = t;
245: if (atomic_compare_exchange_weak_explicit((atomic_int*) &rbuf->rb_tail,
246: &f, n, memory_order_release, memory_order_relaxed)) {
247: atomic_store_explicit((atomic_int*) &rbuf->rb_full, 0, memory_order_release);
248: break;
249: }
250: }
1.2 misho 251:
252: return 0;
253: }
1.5 misho 254:
255:
256: /*
257: * lrb_init() - Init linear ring buffer
258: *
259: * @lrb = Linear ring buffer
260: * @size = Size of ring buffer
261: * return: -1 error or 0 ok
262: */
263: int
264: lrb_init(lrbuf_t *lrb, u_int size)
265: {
266: if (!lrb)
267: return -1;
268:
1.9 misho 269: atomic_store_explicit((atomic_int*) &lrb->lrb_head, 0, memory_order_release);
270: atomic_store_explicit((atomic_int*) &lrb->lrb_tail, 0, memory_order_release);
271: atomic_store_explicit((atomic_int*) &lrb->lrb_full, 0, memory_order_release);
1.5 misho 272:
273: lrb->lrb_data = e_malloc(size);
274: if (!lrb->lrb_data)
275: return -1;
276: else
277: lrb->lrb_size = size;
278: memset(lrb->lrb_data, 0, lrb->lrb_size);
279:
280: return 0;
281: }
282:
283: /*
284: * lrb_free() - Free linear ring buffer
285: *
286: * @lrb = Linear ring buffer
287: * return: none
288: */
289: void
290: lrb_free(lrbuf_t *lrb)
291: {
292: if (!lrb)
293: return;
294:
295: if (lrb->lrb_data) {
296: e_free(lrb->lrb_data);
297: lrb->lrb_data = NULL;
298: lrb->lrb_size = 0;
299: }
300:
1.9 misho 301: atomic_store_explicit((atomic_int*) &lrb->lrb_head, 0, memory_order_release);
302: atomic_store_explicit((atomic_int*) &lrb->lrb_tail, 0, memory_order_release);
303: atomic_store_explicit((atomic_int*) &lrb->lrb_full, 0, memory_order_release);
1.5 misho 304: }
305:
306: /*
307: * lrb_purge() - Purge all buffer
308: *
309: * @lrb = Linear ring buffer
310: * return: none
311: */
312: void
313: lrb_purge(lrbuf_t *lrb)
314: {
315: if (!lrb)
316: return;
317:
318: if (lrb->lrb_data)
319: memset(lrb->lrb_data, 0, lrb->lrb_size);
320:
1.9 misho 321: atomic_store_explicit((atomic_int*) &lrb->lrb_head, 0, memory_order_release);
322: atomic_store_explicit((atomic_int*) &lrb->lrb_tail, 0, memory_order_release);
323: atomic_store_explicit((atomic_int*) &lrb->lrb_full, 0, memory_order_release);
1.5 misho 324: }
325:
326: /*
327: * lrb_isempty() - Check buffer is empty
328: *
329: * @lrb = Linear ring buffer
330: * return: -1 error, 0 it isn't empty
331: */
332: int
333: lrb_isempty(lrbuf_t *lrb)
334: {
1.8 misho 335: if (!lrb || !lrb->lrb_size)
1.5 misho 336: return -1;
337:
1.8 misho 338: if (atomic_load_explicit((atomic_int*) &lrb->lrb_full, memory_order_acquire))
339: return 0;
340:
341: return (atomic_load_explicit((atomic_int*) &lrb->lrb_head, memory_order_acquire) ==
342: atomic_load_explicit((atomic_int*) &lrb->lrb_tail, memory_order_acquire));
1.5 misho 343: }
344:
345: /*
346: * lrb_isfull() - Check buffer is full
347: *
348: * @lrb = Linear ring buffer
349: * return: -1 error or 0 it isn't full
350: */
351: int
352: lrb_isfull(lrbuf_t *lrb)
353: {
354: int h, t;
355:
1.8 misho 356: if (!lrb || !lrb->lrb_size)
1.5 misho 357: return -1;
358:
359: if (!atomic_load_explicit((atomic_int*) &lrb->lrb_full, memory_order_acquire))
360: return 0;
361:
362: t = atomic_load_explicit((atomic_int*) &lrb->lrb_tail, memory_order_acquire);
363: h = atomic_load_explicit((atomic_int*) &lrb->lrb_head, memory_order_acquire);
364: return (h == t);
365: }
366:
367: /*
1.6 misho 368: * lrb_getw() - Get address for write
369: *
370: * @lrb = Linear ring buffer
371: * @len = Return available buffer length for write
372: * return: NULL error or !=NULL pointer for write
373: * remark: After use of lrb_getw() and write to pointer.
374: * You should update ring buffer with lrb_enqueue(,NULL,wrote_len,)
375: */
376: void *
377: lrb_getw(lrbuf_t *lrb, size_t *len)
378: {
379: int h;
380:
381: if (!lrb || !lrb->lrb_data || !lrb->lrb_size)
382: return NULL;
383:
1.9 misho 384: h = atomic_load_explicit((atomic_int*) &lrb->lrb_head, memory_order_acquire);
1.6 misho 385: if (len)
386: *len = lrb->lrb_size - h;
387:
388: return (lrb->lrb_data + h);
389: }
390:
391: /*
1.5 misho 392: * lrb_enqueue() - Enqueue data to buffer
393: *
394: * @lrb = Linear ring buffer
395: * @data = Data
396: * @len = Length
397: * @lost = Permit to lost data
398: * return: -1 error, 1 buffer is full or 0 ok
399: */
400: int
401: lrb_enqueue(lrbuf_t *lrb, void *data, size_t len, int lost)
402: {
1.6 misho 403: int h, t = 0, n, t2 = 0, unused, drop = 0;
1.5 misho 404:
1.8 misho 405: if (!lrb || !lrb->lrb_data || !lrb->lrb_size)
1.5 misho 406: return -1;
1.8 misho 407: if (lrb->lrb_size <= len)
1.5 misho 408: return 1;
409:
410: lrb_unused(lrb, unused);
411: if (!lost) {
412: if (len > unused)
413: return 1;
414: } else {
415: drop = len - unused;
416: if(drop < 0)
417: drop ^= drop;
418: }
419:
420: if (drop > 0) {
421: t = atomic_load_explicit((atomic_int*) &lrb->lrb_tail, memory_order_acquire);
422: t2 = (t + drop) % lrb->lrb_size;
423: }
1.9 misho 424: h = atomic_load_explicit((atomic_int*) &lrb->lrb_head, memory_order_acquire);
1.5 misho 425: n = lrb->lrb_size - h;
426: if (len < n) {
1.6 misho 427: if (data)
428: memcpy(lrb->lrb_data + h, data, len);
1.5 misho 429: n = h + len;
430: } else {
1.6 misho 431: if (data) {
432: memcpy(lrb->lrb_data + h, data, n);
433: memcpy(lrb->lrb_data, data + n, len - n);
434: }
1.5 misho 435: n = len - n;
436: }
437:
438: h = n;
439: atomic_store_explicit((atomic_int*) &lrb->lrb_head, h, memory_order_release);
440: if (drop > 0)
441: while (42) {
442: n = t;
443: if (atomic_compare_exchange_weak_explicit((atomic_int*) &lrb->lrb_tail,
444: &n, t2, memory_order_release, memory_order_relaxed))
445: break;
446: t = n;
447: t2 = (t + drop) % lrb->lrb_size;
448: }
449: else
450: t2 = atomic_load_explicit((atomic_int*) &lrb->lrb_tail, memory_order_acquire);
451: atomic_store_explicit((atomic_int*) &lrb->lrb_full, (h == t2), memory_order_release);
452: return 0;
453: }
454:
455: /*
1.6 misho 456: * lrb_getr() - Get address for read
457: *
458: * @lrb = Linear ring buffer
459: * @len = Return available data length for read
460: * return: NULL error or !=NULL pointer for read
461: * remark: After use of lrb_getr() and read from pointer.
462: * You could update ring buffer with lrb_dequeue(,NULL,read_len)
463: */
464: void *
465: lrb_getr(lrbuf_t *lrb, size_t *len)
466: {
467: int t;
468:
469: if (!lrb || !lrb->lrb_data || !lrb->lrb_size)
470: return NULL;
471:
472: t = atomic_load_explicit((atomic_int*) &lrb->lrb_tail, memory_order_acquire);
473: if (len)
474: lrb_queued(lrb, *len);
475:
476: return (lrb->lrb_data + t);
477: }
478:
479: /*
1.5 misho 480: * lrb_dequeue() - Dequeue data from buffer
481: *
482: * @lrb = Linear ring buffer
483: * @data = Data, if =NULL, just dequeue data
484: * @len = Length of data
1.10 ! misho 485: * @peek = Peek only data, keep the same tail position
1.5 misho 486: * return: -1 error, 0 buffer is empty or >0 stored data bytes
487: */
488: int
1.10 ! misho 489: lrb_dequeue(lrbuf_t *lrb, void *data, size_t len, int peek)
1.5 misho 490: {
491: int h, t, t2, n, l, f;
492:
1.8 misho 493: if (!lrb || !lrb->lrb_size)
1.5 misho 494: return -1;
1.8 misho 495: if (!len || lrb_isempty(lrb))
1.5 misho 496: return 0;
497: if (lrb->lrb_size <= len)
498: len = lrb->lrb_size - 1;
499:
500: while (42) {
501: t = atomic_load_explicit((atomic_int*) &lrb->lrb_tail, memory_order_acquire);
502: h = atomic_load_explicit((atomic_int*) &lrb->lrb_head, memory_order_acquire);
503: f = atomic_load_explicit((atomic_int*) &lrb->lrb_full, memory_order_acquire);
504:
505: l = h - t;
506: if (l < 0)
507: l += lrb->lrb_size;
508: if (!l) {
509: if (!f)
510: return 0;
511: l = lrb->lrb_size;
512: }
513: if (l > len)
514: l = len;
515:
516: n = lrb->lrb_size - t;
517: if (l < n) {
518: if (data)
519: memcpy(data, lrb->lrb_data + t, l);
520: t2 = t + l;
521: } else {
522: if (data) {
523: memcpy(data, lrb->lrb_data + t, n);
1.8 misho 524: memcpy(((u_char*) data) + n, lrb->lrb_data, l - n);
1.5 misho 525: }
526: t2 = l - n;
527: }
528:
1.10 ! misho 529: if (peek)
! 530: return l;
! 531:
1.5 misho 532: n = t;
533: if (atomic_compare_exchange_weak_explicit((atomic_int*) &lrb->lrb_tail,
534: &n, t2, memory_order_release, memory_order_relaxed)) {
535: atomic_store_explicit((atomic_int*) &lrb->lrb_full, 0, memory_order_release);
536: return l;
537: }
538: }
539:
540: return 0;
541: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>