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

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     ! misho       6: * $Id: ring.c,v 1.4.4.3 2026/02/10 17:43:15 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: /*
        !           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: 
        !           375:        h = n;
        !           376:        atomic_store_explicit((atomic_int*) &lrb->lrb_head, h, memory_order_release);
        !           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:                }
        !           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);
        !           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: {
        !           403:        int h, t, t2, n, l, f;
        !           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);
        !           415:                f = atomic_load_explicit((atomic_int*) &lrb->lrb_full, memory_order_acquire);
        !           416: 
        !           417:                l = h - t;
        !           418:                if (l < 0)
        !           419:                        l += lrb->lrb_size;
        !           420:                if (!l) {
        !           421:                        if (!f)
        !           422:                                return 0;
        !           423:                        l = lrb->lrb_size;
        !           424:                }
        !           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,
        !           443:                                        &n, t2, memory_order_release, memory_order_relaxed)) {
        !           444:                        atomic_store_explicit((atomic_int*) &lrb->lrb_full, 0, memory_order_release);
        !           445:                        return l;
        !           446:                }
        !           447:        }
        !           448: 
        !           449:        return 0;
        !           450: }

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