Annotation of libelwix/src/ring.c, revision 1.4.4.3

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.4.4.3 ! misho       6: * $Id: ring.c,v 1.4.4.2 2026/02/10 17:24:39 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.4.4.1   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.4.4.1   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.4.4.1   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.4.4.1   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);
1.4.4.3 ! misho     287:        atomic_store_explicit((atomic_int*) &lrb->lrb_full, 0, memory_order_relaxed);
1.4.4.1   misho     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: 
1.4.4.2   misho     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)));
1.4.4.1   misho     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: 
1.4.4.2   misho     323:        if (!atomic_load_explicit((atomic_int*) &lrb->lrb_full, memory_order_acquire))
                    324:                return 0;
                    325: 
1.4.4.1   misho     326:        t = atomic_load_explicit((atomic_int*) &lrb->lrb_tail, memory_order_acquire);
1.4.4.3 ! misho     327:        h = atomic_load_explicit((atomic_int*) &lrb->lrb_head, memory_order_acquire);
1.4.4.1   misho     328:        return (h == t);
                    329: }
                    330: 
                    331: /*
                    332:  * lrb_enqueue() - Enqueue data to buffer
                    333:  *
                    334:  * @lrb = Linear ring buffer
                    335:  * @data = Data
                    336:  * @len = Length
                    337:  * @lost = Permit to lost data
                    338:  * return: -1 error, 1 buffer is full or 0 ok
                    339:  */
                    340: int
                    341: lrb_enqueue(lrbuf_t *lrb, void *data, size_t len, int lost)
                    342: {
                    343:        int h, t, n, t2, unused, drop = 0;
                    344: 
                    345:        if (!lrb || !lrb->lrb_data)
                    346:                return -1;
                    347:        if (!lrb->lrb_size || lrb->lrb_size <= len)
                    348:                return 1;
                    349: 
                    350:        lrb_unused(lrb, unused);
                    351:        if (!lost) {
                    352:                if (len > unused)
                    353:                        return 1;
                    354:        } else {
                    355:                drop = len - unused;
                    356:                if(drop < 0)
                    357:                        drop ^= drop;
                    358:        }
                    359: 
                    360:        if (drop > 0) {
                    361:                t = atomic_load_explicit((atomic_int*) &lrb->lrb_tail, memory_order_acquire);
                    362:                t2 = (t + drop) % lrb->lrb_size;
                    363:        }
                    364:        h = atomic_load_explicit((atomic_int*) &lrb->lrb_head, memory_order_relaxed);
                    365:        n = lrb->lrb_size - h;
                    366:        if (len < n) {
                    367:                memcpy(lrb->lrb_data + h, data, len);
                    368:                n = h + len;
                    369:        } else {
                    370:                memcpy(lrb->lrb_data + h, data, n);
                    371:                memcpy(lrb->lrb_data, data + n, len - n);
                    372:                n = len - n;
                    373:        }
                    374: 
1.4.4.2   misho     375:        h = n;
                    376:        atomic_store_explicit((atomic_int*) &lrb->lrb_head, h, memory_order_release);
1.4.4.1   misho     377:        if (drop > 0)
                    378:                while (42) {
                    379:                        n = t;
                    380:                        if (atomic_compare_exchange_weak_explicit((atomic_int*) &lrb->lrb_tail,
                    381:                                                &n, t2, memory_order_release, memory_order_relaxed))
                    382:                                break;
                    383:                        t = n;
                    384:                        t2 = (t + drop) % lrb->lrb_size;
                    385:                }
1.4.4.2   misho     386:        else
                    387:                t2 = atomic_load_explicit((atomic_int*) &lrb->lrb_tail, memory_order_acquire);
                    388:        atomic_store_explicit((atomic_int*) &lrb->lrb_full, (h == t2), memory_order_release);
1.4.4.1   misho     389:        return 0;
                    390: }
                    391: 
                    392: /*
                    393:  * lrb_dequeue() - Dequeue data from buffer
                    394:  *
                    395:  * @lrb = Linear ring buffer
                    396:  * @data = Data, if =NULL, just dequeue data
                    397:  * @len = Length of data
                    398:  * return: -1 error, 0 buffer is empty or >0 stored data bytes
                    399:  */
                    400: int
                    401: lrb_dequeue(lrbuf_t *lrb, void *data, size_t len)
                    402: {
1.4.4.3 ! misho     403:        int h, t, t2, n, l, f;
1.4.4.1   misho     404: 
                    405:        if (!lrb)
                    406:                return -1;
                    407:        if (!lrb->lrb_size || !len || lrb_isempty(lrb))
                    408:                return 0;
                    409:        if (lrb->lrb_size <= len)
                    410:                len = lrb->lrb_size - 1;
                    411: 
                    412:        while (42) {
                    413:                t = atomic_load_explicit((atomic_int*) &lrb->lrb_tail, memory_order_acquire);
                    414:                h = atomic_load_explicit((atomic_int*) &lrb->lrb_head, memory_order_acquire);
1.4.4.3 ! misho     415:                f = atomic_load_explicit((atomic_int*) &lrb->lrb_full, memory_order_acquire);
1.4.4.1   misho     416: 
                    417:                l = h - t;
                    418:                if (l < 0)
                    419:                        l += lrb->lrb_size;
1.4.4.3 ! misho     420:                if (!l) {
        !           421:                        if (!f)
        !           422:                                return 0;
        !           423:                        l = lrb->lrb_size;
        !           424:                }
1.4.4.1   misho     425:                if (l > len)
                    426:                        l = len;
                    427: 
                    428:                n = lrb->lrb_size - t;
                    429:                if (l < n) {
                    430:                        if (data)
                    431:                                memcpy(data, lrb->lrb_data + t, l);
                    432:                        t2 = t + l;
                    433:                } else {
                    434:                        if (data) {
                    435:                                memcpy(data, lrb->lrb_data + t, n);
                    436:                                memcpy(data + n, lrb->lrb_data, l - n);
                    437:                        }
                    438:                        t2 = l - n;
                    439:                }
                    440: 
                    441:                n = t;
                    442:                if (atomic_compare_exchange_weak_explicit((atomic_int*) &lrb->lrb_tail,
1.4.4.2   misho     443:                                        &n, t2, memory_order_release, memory_order_relaxed)) {
                    444:                        atomic_store_explicit((atomic_int*) &lrb->lrb_full, 0, memory_order_release);
1.4.4.1   misho     445:                        return l;
1.4.4.2   misho     446:                }
1.4.4.1   misho     447:        }
                    448: 
                    449:        return 0;
                    450: }

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