File:  [ELWIX - Embedded LightWeight unIX -] / libelwix / src / ring.c
Revision 1.8: download - view: text, annotated - select for diffs - revision graph
Wed Feb 18 11:41:47 2026 UTC (2 days, 5 hours ago) by misho
Branches: MAIN
CVS tags: elwix6_18, HEAD, ELWIX6_17
Version 6.17

    1: /*************************************************************************
    2: * (C) 2025 AITNET ltd - Sofia/Bulgaria - <misho@aitnet.org>
    3: *  by Michael Pounov <misho@elwix.org>
    4: *
    5: * $Author: misho $
    6: * $Id: ring.c,v 1.8 2026/02/18 11:41:47 misho Exp $
    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: 
   15: Copyright 2004 - 2026
   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: 
   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);
   64: 	atomic_store_explicit((atomic_int*) &rbuf->rb_full, 0, memory_order_relaxed);
   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: 
   94: 	atomic_store_explicit((atomic_int*) &rbuf->rb_head, 0, memory_order_relaxed);
   95: 	atomic_store_explicit((atomic_int*) &rbuf->rb_tail, 0, memory_order_relaxed);
   96: 	atomic_store_explicit((atomic_int*) &rbuf->rb_full, 0, memory_order_relaxed);
   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: 
  114: 	atomic_store_explicit((atomic_int*) &rbuf->rb_head, 0, memory_order_relaxed);
  115: 	atomic_store_explicit((atomic_int*) &rbuf->rb_tail, 0, memory_order_relaxed);
  116: 	atomic_store_explicit((atomic_int*) &rbuf->rb_full, 0, memory_order_relaxed);
  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: {
  128: 	if (!rbuf || !rbuf->rb_bufnum)
  129: 		return -1;
  130: 
  131: 	if (atomic_load_explicit((atomic_int*) &rbuf->rb_full, memory_order_acquire))
  132: 		return 0;
  133: 
  134: 	return (atomic_load_explicit((atomic_int*) &rbuf->rb_head, memory_order_acquire) ==
  135: 			atomic_load_explicit((atomic_int*) &rbuf->rb_tail, memory_order_acquire));
  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: {
  147: 	int h, t;
  148: 
  149: 	if (!rbuf || !rbuf->rb_bufnum)
  150: 		return -1;
  151: 
  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);
  158: }
  159: 
  160: /*
  161:  * rbuf_enqueue() - Enqueue data to buffer
  162:  *
  163:  * @rbuf = Ring buffer
  164:  * @data = Data
  165:  * @len = Length
  166:  * @lost = Permit to lost data
  167:  * return: -1 error, 1 buffer is full or 0 ok
  168:  */
  169: int
  170: rbuf_enqueue(ringbuf_t *rbuf, void *data, size_t len, int lost)
  171: {
  172: 	int h, t, f, n, t2, drop = 0;
  173: 	struct iovec *iov;
  174: 
  175: 	if (!rbuf || !rbuf->rb_buffer || !rbuf->rb_bufnum)
  176: 		return -1;
  177: 
  178: 	f = atomic_load_explicit((atomic_int*) &rbuf->rb_full, memory_order_acquire);
  179: 	t = atomic_load_explicit((atomic_int*) &rbuf->rb_tail, memory_order_acquire);
  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: 
  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: 
  195: 	atomic_store_explicit((atomic_int*) &rbuf->rb_head, n, memory_order_release);
  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);
  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
  217:  * return: -1 error, 1 buffer is empty or 0 ok
  218:  */
  219: int
  220: rbuf_dequeue(ringbuf_t *rbuf, struct iovec **out)
  221: {
  222: 	int h, t, n, f;
  223: 
  224: 	if (!rbuf || !rbuf->rb_buffer || !rbuf->rb_bufnum)
  225: 		return -1;
  226: 
  227: 	while (42) {
  228: 		h = atomic_load_explicit((atomic_int*) &rbuf->rb_head, memory_order_acquire);
  229: 		f = atomic_load_explicit((atomic_int*) &rbuf->rb_full, memory_order_acquire);
  230: 		t = atomic_load_explicit((atomic_int*) &rbuf->rb_tail, memory_order_acquire);
  231: 
  232: 		if (!f && h == t)
  233: 			return 1;
  234: 
  235: 		n = (t + 1) % rbuf->rb_bufnum;
  236: 
  237: 		f = t;
  238: 		if (atomic_compare_exchange_weak_explicit((atomic_int*) &rbuf->rb_tail,
  239: 					&f, n, memory_order_release, memory_order_relaxed)) {
  240: 			if (out)
  241: 				*out = rbuf->rb_buffer + t;
  242: 
  243: 			atomic_store_explicit((atomic_int*) &rbuf->rb_full, 0, memory_order_release);
  244: 			break;
  245: 		}
  246: 	}
  247: 
  248: 	return 0;
  249: }
  250: 
  251: 
  252: /*
  253:  * lrb_init() - Init linear ring buffer
  254:  *
  255:  * @lrb = Linear ring buffer
  256:  * @size = Size of ring buffer
  257:  * return: -1 error or 0 ok
  258:  */
  259: int
  260: lrb_init(lrbuf_t *lrb, u_int size)
  261: {
  262: 	if (!lrb)
  263: 		return -1;
  264: 
  265: 	atomic_store_explicit((atomic_int*) &lrb->lrb_head, 0, memory_order_relaxed);
  266: 	atomic_store_explicit((atomic_int*) &lrb->lrb_tail, 0, memory_order_relaxed);
  267: 	atomic_store_explicit((atomic_int*) &lrb->lrb_full, 0, memory_order_relaxed);
  268: 
  269: 	lrb->lrb_data = e_malloc(size);
  270: 	if (!lrb->lrb_data)
  271: 		return -1;
  272: 	else
  273: 		lrb->lrb_size = size;
  274: 	memset(lrb->lrb_data, 0, lrb->lrb_size);
  275: 
  276: 	return 0;
  277: }
  278: 
  279: /*
  280:  * lrb_free() - Free linear ring buffer
  281:  *
  282:  * @lrb = Linear ring buffer
  283:  * return: none
  284:  */
  285: void
  286: lrb_free(lrbuf_t *lrb)
  287: {
  288: 	if (!lrb)
  289: 		return;
  290: 
  291: 	if (lrb->lrb_data) {
  292: 		e_free(lrb->lrb_data);
  293: 		lrb->lrb_data = NULL;
  294: 		lrb->lrb_size = 0;
  295: 	}
  296: 
  297: 	atomic_store_explicit((atomic_int*) &lrb->lrb_head, 0, memory_order_relaxed);
  298: 	atomic_store_explicit((atomic_int*) &lrb->lrb_tail, 0, memory_order_relaxed);
  299: 	atomic_store_explicit((atomic_int*) &lrb->lrb_full, 0, memory_order_relaxed);
  300: }
  301: 
  302: /*
  303:  * lrb_purge() - Purge all buffer
  304:  *
  305:  * @lrb = Linear ring buffer
  306:  * return: none
  307:  */
  308: void
  309: lrb_purge(lrbuf_t *lrb)
  310: {
  311: 	if (!lrb)
  312: 		return;
  313: 
  314: 	if (lrb->lrb_data)
  315: 		memset(lrb->lrb_data, 0, lrb->lrb_size);
  316: 
  317: 	atomic_store_explicit((atomic_int*) &lrb->lrb_head, 0, memory_order_relaxed);
  318: 	atomic_store_explicit((atomic_int*) &lrb->lrb_tail, 0, memory_order_relaxed);
  319: 	atomic_store_explicit((atomic_int*) &lrb->lrb_full, 0, memory_order_relaxed);
  320: }
  321: 
  322: /*
  323:  * lrb_isempty() - Check buffer is empty
  324:  *
  325:  * @lrb = Linear ring buffer
  326:  * return: -1 error, 0 it isn't empty
  327:  */
  328: int
  329: lrb_isempty(lrbuf_t *lrb)
  330: {
  331: 	if (!lrb || !lrb->lrb_size)
  332: 		return -1;
  333: 
  334: 	if (atomic_load_explicit((atomic_int*) &lrb->lrb_full, memory_order_acquire))
  335: 		return 0;
  336: 
  337: 	return (atomic_load_explicit((atomic_int*) &lrb->lrb_head, memory_order_acquire) ==
  338: 			atomic_load_explicit((atomic_int*) &lrb->lrb_tail, memory_order_acquire));
  339: }
  340: 
  341: /*
  342:  * lrb_isfull() - Check buffer is full
  343:  *
  344:  * @lrb = Linear ring buffer
  345:  * return: -1 error or 0 it isn't full
  346:  */
  347: int
  348: lrb_isfull(lrbuf_t *lrb)
  349: {
  350: 	int h, t;
  351: 
  352: 	if (!lrb || !lrb->lrb_size)
  353: 		return -1;
  354: 
  355: 	if (!atomic_load_explicit((atomic_int*) &lrb->lrb_full, memory_order_acquire))
  356: 		return 0;
  357: 
  358: 	t = atomic_load_explicit((atomic_int*) &lrb->lrb_tail, memory_order_acquire);
  359: 	h = atomic_load_explicit((atomic_int*) &lrb->lrb_head, memory_order_acquire);
  360: 	return (h == t);
  361: }
  362: 
  363: /*
  364:  * lrb_getw() - Get address for write
  365:  *
  366:  * @lrb = Linear ring buffer
  367:  * @len = Return available buffer length for write
  368:  * return: NULL error or !=NULL pointer for write
  369:  * remark: After use of lrb_getw() and write to pointer.
  370:  * 		You should update ring buffer with lrb_enqueue(,NULL,wrote_len,)
  371:  */
  372: void *
  373: lrb_getw(lrbuf_t *lrb, size_t *len)
  374: {
  375: 	int h;
  376: 
  377: 	if (!lrb || !lrb->lrb_data || !lrb->lrb_size)
  378: 		return NULL;
  379: 
  380: 	h = atomic_load_explicit((atomic_int*) &lrb->lrb_head, memory_order_relaxed);
  381: 	if (len)
  382: 		*len = lrb->lrb_size - h;
  383: 
  384: 	return (lrb->lrb_data + h);
  385: }
  386: 
  387: /*
  388:  * lrb_enqueue() - Enqueue data to buffer
  389:  *
  390:  * @lrb = Linear ring buffer
  391:  * @data = Data
  392:  * @len = Length
  393:  * @lost = Permit to lost data
  394:  * return: -1 error, 1 buffer is full or 0 ok
  395:  */
  396: int
  397: lrb_enqueue(lrbuf_t *lrb, void *data, size_t len, int lost)
  398: {
  399: 	int h, t = 0, n, t2 = 0, unused, drop = 0;
  400: 
  401: 	if (!lrb || !lrb->lrb_data || !lrb->lrb_size)
  402: 		return -1;
  403: 	if (lrb->lrb_size <= len)
  404: 		return 1;
  405: 
  406: 	lrb_unused(lrb, unused);
  407: 	if (!lost) {
  408: 		if (len > unused)
  409: 			return 1;
  410: 	} else {
  411: 		drop = len - unused;
  412: 		if(drop < 0)
  413: 			drop ^= drop;
  414: 	}
  415: 
  416: 	if (drop > 0) {
  417: 		t = atomic_load_explicit((atomic_int*) &lrb->lrb_tail, memory_order_acquire);
  418: 		t2 = (t + drop) % lrb->lrb_size;
  419: 	}
  420: 	h = atomic_load_explicit((atomic_int*) &lrb->lrb_head, memory_order_relaxed);
  421: 	n = lrb->lrb_size - h;
  422: 	if (len < n) {
  423: 		if (data)
  424: 			memcpy(lrb->lrb_data + h, data, len);
  425: 		n = h + len;
  426: 	} else {
  427: 		if (data) {
  428: 			memcpy(lrb->lrb_data + h, data, n);
  429: 			memcpy(lrb->lrb_data, data + n, len - n);
  430: 		}
  431: 		n = len - n;
  432: 	}
  433: 
  434: 	h = n;
  435: 	atomic_store_explicit((atomic_int*) &lrb->lrb_head, h, memory_order_release);
  436: 	if (drop > 0)
  437: 		while (42) {
  438: 			n = t;
  439: 			if (atomic_compare_exchange_weak_explicit((atomic_int*) &lrb->lrb_tail,
  440: 						&n, t2, memory_order_release, memory_order_relaxed))
  441: 				break;
  442: 			t = n;
  443: 			t2 = (t + drop) % lrb->lrb_size;
  444: 		}
  445: 	else
  446: 		t2 = atomic_load_explicit((atomic_int*) &lrb->lrb_tail, memory_order_acquire);
  447: 	atomic_store_explicit((atomic_int*) &lrb->lrb_full, (h == t2), memory_order_release);
  448: 	return 0;
  449: }
  450: 
  451: /*
  452:  * lrb_getr() - Get address for read
  453:  *
  454:  * @lrb = Linear ring buffer
  455:  * @len = Return available data length for read
  456:  * return: NULL error or !=NULL pointer for read
  457:  * remark: After use of lrb_getr() and read from pointer.
  458:  * 		You could update ring buffer with lrb_dequeue(,NULL,read_len)
  459:  */
  460: void *
  461: lrb_getr(lrbuf_t *lrb, size_t *len)
  462: {
  463: 	int t;
  464: 
  465: 	if (!lrb || !lrb->lrb_data || !lrb->lrb_size)
  466: 		return NULL;
  467: 
  468: 	t = atomic_load_explicit((atomic_int*) &lrb->lrb_tail, memory_order_acquire);
  469: 	if (len)
  470: 		lrb_queued(lrb, *len);
  471: 
  472: 	return (lrb->lrb_data + t);
  473: }
  474: 
  475: /*
  476:  * lrb_dequeue() - Dequeue data from buffer
  477:  *
  478:  * @lrb = Linear ring buffer
  479:  * @data = Data, if =NULL, just dequeue data
  480:  * @len = Length of data
  481:  * return: -1 error, 0 buffer is empty or >0 stored data bytes
  482:  */
  483: int
  484: lrb_dequeue(lrbuf_t *lrb, void *data, size_t len)
  485: {
  486: 	int h, t, t2, n, l, f;
  487: 
  488: 	if (!lrb || !lrb->lrb_size)
  489: 		return -1;
  490: 	if (!len || lrb_isempty(lrb))
  491: 		return 0;
  492: 	if (lrb->lrb_size <= len)
  493: 		len = lrb->lrb_size - 1;
  494: 
  495: 	while (42) {
  496: 		t = atomic_load_explicit((atomic_int*) &lrb->lrb_tail, memory_order_acquire);
  497: 		h = atomic_load_explicit((atomic_int*) &lrb->lrb_head, memory_order_acquire);
  498: 		f = atomic_load_explicit((atomic_int*) &lrb->lrb_full, memory_order_acquire);
  499: 
  500: 		l = h - t;
  501: 		if (l < 0)
  502: 			l += lrb->lrb_size;
  503: 		if (!l) {
  504: 			if (!f)
  505: 				return 0;
  506: 			l = lrb->lrb_size;
  507: 		}
  508: 		if (l > len)
  509: 			l = len;
  510: 
  511: 		n = lrb->lrb_size - t;
  512: 		if (l < n) {
  513: 			if (data)
  514: 				memcpy(data, lrb->lrb_data + t, l);
  515: 			t2 = t + l;
  516: 		} else {
  517: 			if (data) {
  518: 				memcpy(data, lrb->lrb_data + t, n);
  519: 				memcpy(((u_char*) data) + n, lrb->lrb_data, l - n);
  520: 			}
  521: 			t2 = l - n;
  522: 		}
  523: 
  524: 		n = t;
  525: 		if (atomic_compare_exchange_weak_explicit((atomic_int*) &lrb->lrb_tail,
  526: 					&n, t2, memory_order_release, memory_order_relaxed)) {
  527: 			atomic_store_explicit((atomic_int*) &lrb->lrb_full, 0, memory_order_release);
  528: 			return l;
  529: 		}
  530: 	}
  531: 
  532: 	return 0;
  533: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>