Annotation of libelwix/src/ring.c, revision 1.5.2.2
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.5.2.2 ! misho 6: * $Id: ring.c,v 1.5.2.1 2026/02/10 18:23:53 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: {
1.5 misho 141: int h, t;
142:
1.2 misho 143: if (!rbuf)
144: return -1;
145: if (!rbuf->rb_bufnum)
146: return 1;
147:
1.5 misho 148: t = atomic_load_explicit((atomic_int*) &rbuf->rb_tail, memory_order_acquire);
149: h = atomic_load_explicit((atomic_int*) &rbuf->rb_head, memory_order_relaxed) + 1;
150: if (h >= rbuf->rb_bufnum)
151: h ^= h;
152:
153: return (h == t);
1.2 misho 154: }
155:
156: /*
157: * rbuf_enqueue() - Enqueue data to buffer
158: *
159: * @rbuf = Ring buffer
160: * @data = Data
161: * @len = Length
162: * return: -1 error, 1 buffer is full or 0 ok
163: */
164: int
165: rbuf_enqueue(ringbuf_t *rbuf, void *data, size_t len)
166: {
167: int h, t, n;
168: struct iovec *iov;
169:
170: if (!rbuf || !rbuf->rb_buffer)
171: return -1;
172: if (!rbuf->rb_bufnum)
173: return 1;
174:
1.3 misho 175: h = atomic_load_explicit((atomic_int*) &rbuf->rb_head, memory_order_relaxed);
176: t = atomic_load_explicit((atomic_int*) &rbuf->rb_tail, memory_order_acquire);
1.2 misho 177: n = (h + 1) % rbuf->rb_bufnum;
178:
179: if (n == t)
180: return 1;
181:
182: iov = rbuf->rb_buffer + h;
183: iov->iov_len = len;
184: iov->iov_base = data;
185:
1.3 misho 186: atomic_store_explicit((atomic_int*) &rbuf->rb_head, n, memory_order_release);
1.2 misho 187: return 0;
188: }
189:
190: /*
191: * rbuf_dequeue() - Dequeue data from buffer
192: *
193: * @rbuf = Ring buffer
194: * @out = Data, if =NULL, just dequeue data
195: * return: -1 error, 1 buffer is empty or 0 ok
196: */
197: int
1.4 misho 198: rbuf_dequeue(ringbuf_t *rbuf, struct iovec **out)
1.2 misho 199: {
200: int h, t, n;
201:
202: if (!rbuf || !rbuf->rb_buffer)
203: return -1;
204: if (!rbuf->rb_bufnum)
205: return 1;
206:
1.3 misho 207: h = atomic_load_explicit((atomic_int*) &rbuf->rb_head, memory_order_acquire);
208: t = atomic_load_explicit((atomic_int*) &rbuf->rb_tail, memory_order_relaxed);
1.2 misho 209: n = (t + 1) % rbuf->rb_bufnum;
210:
211: if (h == t)
212: return 1;
213:
214: if (out)
1.4 misho 215: *out = rbuf->rb_buffer + t;
1.2 misho 216:
1.3 misho 217: atomic_store_explicit((atomic_int*) &rbuf->rb_tail, n, memory_order_release);
1.2 misho 218: return 0;
219: }
1.5 misho 220:
221:
222: /*
223: * lrb_init() - Init linear ring buffer
224: *
225: * @lrb = Linear ring buffer
226: * @size = Size of ring buffer
227: * return: -1 error or 0 ok
228: */
229: int
230: lrb_init(lrbuf_t *lrb, u_int size)
231: {
232: if (!lrb)
233: return -1;
234:
235: atomic_store_explicit((atomic_int*) &lrb->lrb_head, 0, memory_order_relaxed);
236: atomic_store_explicit((atomic_int*) &lrb->lrb_tail, 0, memory_order_relaxed);
237:
238: lrb->lrb_data = e_malloc(size);
239: if (!lrb->lrb_data)
240: return -1;
241: else
242: lrb->lrb_size = size;
243: memset(lrb->lrb_data, 0, lrb->lrb_size);
244:
245: return 0;
246: }
247:
248: /*
249: * lrb_free() - Free linear ring buffer
250: *
251: * @lrb = Linear ring buffer
252: * return: none
253: */
254: void
255: lrb_free(lrbuf_t *lrb)
256: {
257: if (!lrb)
258: return;
259:
260: if (lrb->lrb_data) {
261: e_free(lrb->lrb_data);
262: lrb->lrb_data = NULL;
263: lrb->lrb_size = 0;
264: }
265:
266: atomic_store_explicit((atomic_int*) &lrb->lrb_head, 0, memory_order_relaxed);
267: atomic_store_explicit((atomic_int*) &lrb->lrb_tail, 0, memory_order_relaxed);
268: }
269:
270: /*
271: * lrb_purge() - Purge all buffer
272: *
273: * @lrb = Linear ring buffer
274: * return: none
275: */
276: void
277: lrb_purge(lrbuf_t *lrb)
278: {
279: if (!lrb)
280: return;
281:
282: if (lrb->lrb_data)
283: memset(lrb->lrb_data, 0, lrb->lrb_size);
284:
285: atomic_store_explicit((atomic_int*) &lrb->lrb_head, 0, memory_order_relaxed);
286: atomic_store_explicit((atomic_int*) &lrb->lrb_tail, 0, memory_order_relaxed);
287: atomic_store_explicit((atomic_int*) &lrb->lrb_full, 0, memory_order_relaxed);
288: }
289:
290: /*
291: * lrb_isempty() - Check buffer is empty
292: *
293: * @lrb = Linear ring buffer
294: * return: -1 error, 0 it isn't empty
295: */
296: int
297: lrb_isempty(lrbuf_t *lrb)
298: {
299: if (!lrb)
300: return -1;
301:
302: return (!atomic_load_explicit((atomic_int*) &lrb->lrb_full, memory_order_acquire) &&
303: (atomic_load_explicit((atomic_int*) &lrb->lrb_head, memory_order_acquire) ==
304: atomic_load_explicit((atomic_int*) &lrb->lrb_tail, memory_order_acquire)));
305: }
306:
307: /*
308: * lrb_isfull() - Check buffer is full
309: *
310: * @lrb = Linear ring buffer
311: * return: -1 error or 0 it isn't full
312: */
313: int
314: lrb_isfull(lrbuf_t *lrb)
315: {
316: int h, t;
317:
318: if (!lrb)
319: return -1;
320: if (!lrb->lrb_size)
321: return 1;
322:
323: if (!atomic_load_explicit((atomic_int*) &lrb->lrb_full, memory_order_acquire))
324: return 0;
325:
326: t = atomic_load_explicit((atomic_int*) &lrb->lrb_tail, memory_order_acquire);
327: h = atomic_load_explicit((atomic_int*) &lrb->lrb_head, memory_order_acquire);
328: return (h == t);
329: }
330:
331: /*
1.5.2.2 ! misho 332: * lrb_getw() - Get address for write
! 333: *
! 334: * @lrb = Linear ring buffer
! 335: * @len = Return available buffer length for write
! 336: * return: NULL error or !=NULL pointer for write
! 337: * remark: After use of lrb_getw() and write to pointer.
! 338: * You should update ring buffer with lrb_enqueue(,NULL,wrote_len,)
! 339: */
! 340: void *
! 341: lrb_getw(lrbuf_t *lrb, size_t *len)
! 342: {
! 343: int h;
! 344:
! 345: if (!lrb || !lrb->lrb_data || !lrb->lrb_size)
! 346: return NULL;
! 347:
! 348: h = atomic_load_explicit((atomic_int*) &lrb->lrb_head, memory_order_relaxed);
! 349: if (len)
! 350: *len = lrb->lrb_size - h;
! 351:
! 352: return (lrb->lrb_data + h);
! 353: }
! 354:
! 355: /*
1.5 misho 356: * lrb_enqueue() - Enqueue data to buffer
357: *
358: * @lrb = Linear ring buffer
359: * @data = Data
360: * @len = Length
361: * @lost = Permit to lost data
362: * return: -1 error, 1 buffer is full or 0 ok
363: */
364: int
365: lrb_enqueue(lrbuf_t *lrb, void *data, size_t len, int lost)
366: {
1.5.2.1 misho 367: int h, t = 0, n, t2 = 0, unused, drop = 0;
1.5 misho 368:
369: if (!lrb || !lrb->lrb_data)
370: return -1;
371: if (!lrb->lrb_size || lrb->lrb_size <= len)
372: return 1;
373:
374: lrb_unused(lrb, unused);
375: if (!lost) {
376: if (len > unused)
377: return 1;
378: } else {
379: drop = len - unused;
380: if(drop < 0)
381: drop ^= drop;
382: }
383:
384: if (drop > 0) {
385: t = atomic_load_explicit((atomic_int*) &lrb->lrb_tail, memory_order_acquire);
386: t2 = (t + drop) % lrb->lrb_size;
387: }
388: h = atomic_load_explicit((atomic_int*) &lrb->lrb_head, memory_order_relaxed);
389: n = lrb->lrb_size - h;
390: if (len < n) {
1.5.2.2 ! misho 391: if (data)
! 392: memcpy(lrb->lrb_data + h, data, len);
1.5 misho 393: n = h + len;
394: } else {
1.5.2.2 ! misho 395: if (data) {
! 396: memcpy(lrb->lrb_data + h, data, n);
! 397: memcpy(lrb->lrb_data, data + n, len - n);
! 398: }
1.5 misho 399: n = len - n;
400: }
401:
402: h = n;
403: atomic_store_explicit((atomic_int*) &lrb->lrb_head, h, memory_order_release);
404: if (drop > 0)
405: while (42) {
406: n = t;
407: if (atomic_compare_exchange_weak_explicit((atomic_int*) &lrb->lrb_tail,
408: &n, t2, memory_order_release, memory_order_relaxed))
409: break;
410: t = n;
411: t2 = (t + drop) % lrb->lrb_size;
412: }
413: else
414: t2 = atomic_load_explicit((atomic_int*) &lrb->lrb_tail, memory_order_acquire);
415: atomic_store_explicit((atomic_int*) &lrb->lrb_full, (h == t2), memory_order_release);
416: return 0;
417: }
418:
419: /*
1.5.2.2 ! misho 420: * lrb_getr() - Get address for read
! 421: *
! 422: * @lrb = Linear ring buffer
! 423: * @len = Return available data length for read
! 424: * return: NULL error or !=NULL pointer for read
! 425: * remark: After use of lrb_getr() and read from pointer.
! 426: * You could update ring buffer with lrb_dequeue(,NULL,read_len)
! 427: */
! 428: void *
! 429: lrb_getr(lrbuf_t *lrb, size_t *len)
! 430: {
! 431: int t;
! 432:
! 433: if (!lrb || !lrb->lrb_data || !lrb->lrb_size)
! 434: return NULL;
! 435:
! 436: t = atomic_load_explicit((atomic_int*) &lrb->lrb_tail, memory_order_acquire);
! 437: if (len)
! 438: lrb_queued(lrb, *len);
! 439:
! 440: return (lrb->lrb_data + t);
! 441: }
! 442:
! 443: /*
1.5 misho 444: * lrb_dequeue() - Dequeue data from buffer
445: *
446: * @lrb = Linear ring buffer
447: * @data = Data, if =NULL, just dequeue data
448: * @len = Length of data
449: * return: -1 error, 0 buffer is empty or >0 stored data bytes
450: */
451: int
452: lrb_dequeue(lrbuf_t *lrb, void *data, size_t len)
453: {
454: int h, t, t2, n, l, f;
455:
456: if (!lrb)
457: return -1;
458: if (!lrb->lrb_size || !len || lrb_isempty(lrb))
459: return 0;
460: if (lrb->lrb_size <= len)
461: len = lrb->lrb_size - 1;
462:
463: while (42) {
464: t = atomic_load_explicit((atomic_int*) &lrb->lrb_tail, memory_order_acquire);
465: h = atomic_load_explicit((atomic_int*) &lrb->lrb_head, memory_order_acquire);
466: f = atomic_load_explicit((atomic_int*) &lrb->lrb_full, memory_order_acquire);
467:
468: l = h - t;
469: if (l < 0)
470: l += lrb->lrb_size;
471: if (!l) {
472: if (!f)
473: return 0;
474: l = lrb->lrb_size;
475: }
476: if (l > len)
477: l = len;
478:
479: n = lrb->lrb_size - t;
480: if (l < n) {
481: if (data)
482: memcpy(data, lrb->lrb_data + t, l);
483: t2 = t + l;
484: } else {
485: if (data) {
486: memcpy(data, lrb->lrb_data + t, n);
487: memcpy(data + n, lrb->lrb_data, l - n);
488: }
489: t2 = l - n;
490: }
491:
492: n = t;
493: if (atomic_compare_exchange_weak_explicit((atomic_int*) &lrb->lrb_tail,
494: &n, t2, memory_order_release, memory_order_relaxed)) {
495: atomic_store_explicit((atomic_int*) &lrb->lrb_full, 0, memory_order_release);
496: return l;
497: }
498: }
499:
500: return 0;
501: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>