This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

nrf_ringbuf_alloc , nrf_ringbuf_put overwrite issue

Hello, 

I am running such code deliberately, it is allocating the buffer flawlessly until the 10th run (102*10 = 1020). After that, it gives 4 from the allocation function.

and as I am still filling 102 bytes by nrf_ringbuf_put function it is overflowing but not gives any error, yet it is starting to allocate 102 bytes after the 12nd cycle until the 21st cycle. 

My expectation is it should run till the 10th cycle, then it should give memory full error continuously.

NRF_RINGBUF_DEF(testRingbuf,1024);
void testfunc(){
    nrf_ringbuf_init(&testRingbuf);
    len =102;
    for(int i=0;i<20;i++){
        nrf_ringbuf_alloc(&testRingbuf,&bufferAllocChunk,&len, true);
        fillbuffer(bufferAllocChunk,len);
        err_code = nrf_ringbuf_put(&ppgRingbuf, PPG_WATERMARK_BUFFER_SIZE);
    }
}

One more detail ;

If I allocate and put bytes amount of two's power (ex:128,256,...) it works as intended(it gives "no-mem" error until freeing some space)

But if I allocate /put a number of bytes such as 102 or any other number other than two's power, the library gives a "no-mem" error once and it is overwriting. I don't know if we are able to allocate/put an arbitrary number of bytes or we need to put/allocate only two's power.

Parents
  • Hi,

    It should work for putting any amount of data into the ring buffer, not only power-of-two length amounts of data. However, when the data is a power of two you will always align to the "wraparound" point of the ring buffer, and the amount that you try to allocate will always either fit entirely or no bytes will fit at all.

    For the code example that you provided, you do not check the error value returned from nrf_ringbuf_alloc(), and the call to nrf_ringbuf_put() is to a different buffer than the one you allocate to.

    Note that len, on iteration 11 (when only 4 bytes are available in the ring buffer) will get set to 4 (the actual amount of bytes available in the buffer), and so for consequent iterations 4 bytes will be attempted allocated in each instance and not 102 bytes. (The p_length argument of nrf_ringbuf_alloc() is both in and out.)

    The call to nrf_ringbuf_put() should use the value pointed to by p_length after the call to nrf_ringbuf_alloc() for its length argument (or a smaller value). In your example code you use PPG_WATERMARK_BUFFER_SIZE, which I assume is larger than 4.

    Regards,
    Terje

  • I think there is still some kind of bug in this library especially for the arbitrary numbers, i have prepared a very basic and simple example which is not working properly.

    NRF_RINGBUF_DEF(ppgRingbuf,1024);
    
      nrf_ringbuf_init(&ppgRingbuf);
      
      len=1020;
      
      err_code = nrf_ringbuf_alloc(&ppgRingbuf,&ppgBufferAllocChunk,&len,true);
      printf("allc len:%03d,allc rtrn:%1d- rd:%04d,wr:%04d\r\n",len,err_code,ppgRingbuf.p_cb->rd_idx,ppgRingbuf.p_cb->wr_idx);
      
      err_code = nrf_ringbuf_put(&ppgRingbuf,len);
      printf("put  len:%03d,put  rtrn:%1d- rd:%04d,wr:%04d\r\n",len,err_code,ppgRingbuf.p_cb->rd_idx,ppgRingbuf.p_cb->wr_idx);
      
      get_len = 870;
      
      err_code = nrf_ringbuf_get(&ppgRingbuf, &(p_buffer), &get_len, true);
      printf("get  len:%03d,get  rtrn:%1d- rd:%04d,wr:%04d\r\n",get_len,err_code,ppgRingbuf.p_cb->rd_idx,ppgRingbuf.p_cb->wr_idx);
      
      err_code = nrf_ringbuf_free(&ppgRingbuf,get_len);
      printf("free len:%03d,free rtrn:%1d- rd:%04d,wr:%04d\r\n",get_len,err_code,ppgRingbuf.p_cb->rd_idx,ppgRingbuf.p_cb->wr_idx);
      
      len = 102;
      
      err_code = nrf_ringbuf_alloc(&ppgRingbuf,&ppgBufferAllocChunk,&len,true);
      printf("allc len:%03d,allc rtrn:%1d- rd:%04d,wr:%04d\r\n",len,err_code,ppgRingbuf.p_cb->rd_idx,ppgRingbuf.p_cb->wr_idx);
        


    The result is  ; Why the second allocation returns only 4 ? Buffer has been freed already so it should return more than 4 .

    allc len:1020,allc rtrn:0- rd:0000,wr:0000
    put  len:1020,put  rtrn:0- rd:0000,wr:1020
    get  len:870,get  rtrn:0- rd:0000,wr:1020
    free len:870,free rtrn:0- rd:0870,wr:1020
    allc len:004,allc rtrn:0- rd:0870,wr:1020
    

    Here are more details about the problem, I think there is a bug in the nrf_ringbuf_alloc() function 

    I have created Available function from the nrf_ringbuf_alloc() function's availability check .

    And the results are not expected as usual.

      nrf_ringbuf_init(&ppgRingbuf);
      printf("Avail : %d\r\n",nrf_ringbuf_avail(&ppgRingbuf));
    
      len=1020;
    
      err_code = nrf_ringbuf_alloc(&ppgRingbuf,&ppgBufferAllocChunk,&len,true);
      printf("allc len:%03d,allc rtrn:%1d- rd:%04d,wr:%04d\r\n",len,err_code,ppgRingbuf.p_cb->rd_idx,ppgRingbuf.p_cb->wr_idx);
      printf("Avail : %d\r\n",nrf_ringbuf_avail(&ppgRingbuf));
      
      err_code = nrf_ringbuf_put(&ppgRingbuf,len);
      printf("put  len:%03d,put  rtrn:%1d- rd:%04d,wr:%04d\r\n",len,err_code,ppgRingbuf.p_cb->rd_idx,ppgRingbuf.p_cb->wr_idx);
      printf("Avail : %d\r\n",nrf_ringbuf_avail(&ppgRingbuf));
    
      get_len = 870;
      
      err_code = nrf_ringbuf_get(&ppgRingbuf, &(p_buffer), &get_len, true);
      printf("get  len:%03d,get  rtrn:%1d- rd:%04d,wr:%04d\r\n",get_len,err_code,ppgRingbuf.p_cb->rd_idx,ppgRingbuf.p_cb->wr_idx);
      printf("Avail : %d\r\n",nrf_ringbuf_avail(&ppgRingbuf));
    
      err_code = nrf_ringbuf_free(&ppgRingbuf,get_len);
      printf("free len:%03d,free rtrn:%1d- rd:%04d,wr:%04d\r\n",get_len,err_code,ppgRingbuf.p_cb->rd_idx,ppgRingbuf.p_cb->wr_idx);
      printf("Avail : %d\r\n",nrf_ringbuf_avail(&ppgRingbuf));
      len = 102;
      
      err_code = nrf_ringbuf_alloc(&ppgRingbuf,&ppgBufferAllocChunk,&len,true);
      printf("allc len:%03d,allc rtrn:%1d- rd:%04d,wr:%04d\r\n",len,err_code,ppgRingbuf.p_cb->rd_idx,ppgRingbuf.p_cb->wr_idx);
      printf("Avail : %d\r\n",nrf_ringbuf_avail(&ppgRingbuf));  

    Results ; As you can see it shows 4 available byte after the nrf_ringbuf_free() , but whenever i consume the last 4 bytes it can calculate available bytes correctly.

    Avail : 1024
    allc len:1020,allc rtrn:0- rd:0000,wr:0000
    Avail : 4
    put  len:1020,put  rtrn:0- rd:0000,wr:1020
    Avail : 4
    get  len:870,get  rtrn:0- rd:0000,wr:1020
    Avail : 4
    free len:870,free rtrn:0- rd:0870,wr:1020
    Avail : 4
    allc len:004,allc rtrn:0- rd:0870,wr:1020
    Avail : 870
    

    Here is the available function that i copied from the  nrf_ringbuf_alloc() function ;

    uint32_t nrf_ringbuf_avail(nrf_ringbuf_t const * p_ringbuf)
    {
        uint32_t wr_idx = p_ringbuf->p_cb->tmp_wr_idx & p_ringbuf->bufsize_mask;
        uint32_t rd_idx = p_ringbuf->p_cb->rd_idx & p_ringbuf->bufsize_mask;
        uint32_t available = (wr_idx >= rd_idx) ? p_ringbuf->bufsize_mask + 1 - wr_idx :
                p_ringbuf->p_cb->rd_idx -  (p_ringbuf->p_cb->tmp_wr_idx - (p_ringbuf->bufsize_mask + 1));
    
        return available;
    }

Reply
  • I think there is still some kind of bug in this library especially for the arbitrary numbers, i have prepared a very basic and simple example which is not working properly.

    NRF_RINGBUF_DEF(ppgRingbuf,1024);
    
      nrf_ringbuf_init(&ppgRingbuf);
      
      len=1020;
      
      err_code = nrf_ringbuf_alloc(&ppgRingbuf,&ppgBufferAllocChunk,&len,true);
      printf("allc len:%03d,allc rtrn:%1d- rd:%04d,wr:%04d\r\n",len,err_code,ppgRingbuf.p_cb->rd_idx,ppgRingbuf.p_cb->wr_idx);
      
      err_code = nrf_ringbuf_put(&ppgRingbuf,len);
      printf("put  len:%03d,put  rtrn:%1d- rd:%04d,wr:%04d\r\n",len,err_code,ppgRingbuf.p_cb->rd_idx,ppgRingbuf.p_cb->wr_idx);
      
      get_len = 870;
      
      err_code = nrf_ringbuf_get(&ppgRingbuf, &(p_buffer), &get_len, true);
      printf("get  len:%03d,get  rtrn:%1d- rd:%04d,wr:%04d\r\n",get_len,err_code,ppgRingbuf.p_cb->rd_idx,ppgRingbuf.p_cb->wr_idx);
      
      err_code = nrf_ringbuf_free(&ppgRingbuf,get_len);
      printf("free len:%03d,free rtrn:%1d- rd:%04d,wr:%04d\r\n",get_len,err_code,ppgRingbuf.p_cb->rd_idx,ppgRingbuf.p_cb->wr_idx);
      
      len = 102;
      
      err_code = nrf_ringbuf_alloc(&ppgRingbuf,&ppgBufferAllocChunk,&len,true);
      printf("allc len:%03d,allc rtrn:%1d- rd:%04d,wr:%04d\r\n",len,err_code,ppgRingbuf.p_cb->rd_idx,ppgRingbuf.p_cb->wr_idx);
        


    The result is  ; Why the second allocation returns only 4 ? Buffer has been freed already so it should return more than 4 .

    allc len:1020,allc rtrn:0- rd:0000,wr:0000
    put  len:1020,put  rtrn:0- rd:0000,wr:1020
    get  len:870,get  rtrn:0- rd:0000,wr:1020
    free len:870,free rtrn:0- rd:0870,wr:1020
    allc len:004,allc rtrn:0- rd:0870,wr:1020
    

    Here are more details about the problem, I think there is a bug in the nrf_ringbuf_alloc() function 

    I have created Available function from the nrf_ringbuf_alloc() function's availability check .

    And the results are not expected as usual.

      nrf_ringbuf_init(&ppgRingbuf);
      printf("Avail : %d\r\n",nrf_ringbuf_avail(&ppgRingbuf));
    
      len=1020;
    
      err_code = nrf_ringbuf_alloc(&ppgRingbuf,&ppgBufferAllocChunk,&len,true);
      printf("allc len:%03d,allc rtrn:%1d- rd:%04d,wr:%04d\r\n",len,err_code,ppgRingbuf.p_cb->rd_idx,ppgRingbuf.p_cb->wr_idx);
      printf("Avail : %d\r\n",nrf_ringbuf_avail(&ppgRingbuf));
      
      err_code = nrf_ringbuf_put(&ppgRingbuf,len);
      printf("put  len:%03d,put  rtrn:%1d- rd:%04d,wr:%04d\r\n",len,err_code,ppgRingbuf.p_cb->rd_idx,ppgRingbuf.p_cb->wr_idx);
      printf("Avail : %d\r\n",nrf_ringbuf_avail(&ppgRingbuf));
    
      get_len = 870;
      
      err_code = nrf_ringbuf_get(&ppgRingbuf, &(p_buffer), &get_len, true);
      printf("get  len:%03d,get  rtrn:%1d- rd:%04d,wr:%04d\r\n",get_len,err_code,ppgRingbuf.p_cb->rd_idx,ppgRingbuf.p_cb->wr_idx);
      printf("Avail : %d\r\n",nrf_ringbuf_avail(&ppgRingbuf));
    
      err_code = nrf_ringbuf_free(&ppgRingbuf,get_len);
      printf("free len:%03d,free rtrn:%1d- rd:%04d,wr:%04d\r\n",get_len,err_code,ppgRingbuf.p_cb->rd_idx,ppgRingbuf.p_cb->wr_idx);
      printf("Avail : %d\r\n",nrf_ringbuf_avail(&ppgRingbuf));
      len = 102;
      
      err_code = nrf_ringbuf_alloc(&ppgRingbuf,&ppgBufferAllocChunk,&len,true);
      printf("allc len:%03d,allc rtrn:%1d- rd:%04d,wr:%04d\r\n",len,err_code,ppgRingbuf.p_cb->rd_idx,ppgRingbuf.p_cb->wr_idx);
      printf("Avail : %d\r\n",nrf_ringbuf_avail(&ppgRingbuf));  

    Results ; As you can see it shows 4 available byte after the nrf_ringbuf_free() , but whenever i consume the last 4 bytes it can calculate available bytes correctly.

    Avail : 1024
    allc len:1020,allc rtrn:0- rd:0000,wr:0000
    Avail : 4
    put  len:1020,put  rtrn:0- rd:0000,wr:1020
    Avail : 4
    get  len:870,get  rtrn:0- rd:0000,wr:1020
    Avail : 4
    free len:870,free rtrn:0- rd:0870,wr:1020
    Avail : 4
    allc len:004,allc rtrn:0- rd:0870,wr:1020
    Avail : 870
    

    Here is the available function that i copied from the  nrf_ringbuf_alloc() function ;

    uint32_t nrf_ringbuf_avail(nrf_ringbuf_t const * p_ringbuf)
    {
        uint32_t wr_idx = p_ringbuf->p_cb->tmp_wr_idx & p_ringbuf->bufsize_mask;
        uint32_t rd_idx = p_ringbuf->p_cb->rd_idx & p_ringbuf->bufsize_mask;
        uint32_t available = (wr_idx >= rd_idx) ? p_ringbuf->bufsize_mask + 1 - wr_idx :
                p_ringbuf->p_cb->rd_idx -  (p_ringbuf->p_cb->tmp_wr_idx - (p_ringbuf->bufsize_mask + 1));
    
        return available;
    }

Children
  • Hi,

    This has to do with how ring buffers are implemented. Under the hood it is a normal linear buffer, but when you write or read "off the end" then instead you continue from the beginning again. This has implications for how you can use the ring buffer, and there are basically two ways to access it:

    One is to get a pointer to the buffer data directly, and do the copying of data from your code.

    Another is to use the API functions that do the copying for you, and use a separate buffer (that you control) for copying data to or from.

    For the first option, which you use, the pointer into the ring buffer points to a contiguous memory area, and so it can only reach to the end of the underlying "real" buffer of the ring buffer. Therefore you get only 4 bytes. When those bytes are written, you will get the next allocation from the beginning of the real buffer again.

    If, on the other hand, you use nrf_ringbuf_cpy_put() and nrf_ringbuf_cpy_get(), then handling of the wraparound point of the underlying buffer is done by those API functions, and so you do not need to do writes to (or reads from) the ring buffer in two operations when you happen to cross the wraparound point of the underlying linear buffer.

    Regards,
    Terje

Related