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>