Tail pointer for overwrite functionality in circular buffer implementation

230 views Asked by At

I am trying to implement a circular buffer for logging messages. I have implemented a fairly basic solution which seems to work but I am confused about how push should work in real case scenario. Should head overwrite the tail? if yes do we modify the tail to reflect it to point to next oldest log?

/******************************************************************************

                        Online C Compiler.
            Code, Compile, Run and Debug C program online.

Write your code in this editor and press "Run" button to compile and execute it.

*******************************************************************************/

/******************************************************************************

                        Online C Compiler.
            Code, Compile, Run and Debug C program online.

Write your code in this editor and press "Run" button to compile and execute it.

*******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <stdbool.h>
#include <string.h>
#define LOG_SIZE 10
typedef struct{
  char *buffer[LOG_SIZE];
  int16_t head;
  int16_t tail;
  int16_t count;
  volatile bool full_status;
  volatile bool empty_status;
}circbuff;

pthread_mutex_t circMutex;
void circbuff_reset(circbuff *circ_b)
{
  circ_b->head = 0;
  circ_b->tail =0;
  circ_b->full_status =  false;
  circ_b->count =0;
  circ_b->empty_status =  false;
}
circbuff * circbuff_init ()
{
  circbuff *my_circ_buff = (circbuff *) malloc(sizeof(circbuff));
  circbuff_reset(my_circ_buff);
  return (my_circ_buff);
}

void push(circbuff *circ_b, char* message)
{

  pthread_mutex_lock(&circMutex);
  if (!circ_b->full_status)
  {
    //circ_b->buffer[circ_b->head] =  (char*)malloc(strlen(message)+1);
    circ_b->buffer[circ_b->head] = strdup(message);
    //printf ("Value inserted at position %d is %s and count %d\r\n", circ_b->head, circ_b->buffer[circ_b->head],circ_b->count);
    circ_b->head = (circ_b->head + 1) % LOG_SIZE;
    if(circ_b->head==circ_b->tail)
        circ_b->full_status=true;
    circ_b->empty_status=false;
    circ_b->count++ ; 
  }
  else //can be changed to overwrite
  {

    free(circ_b->buffer[circ_b->head]);
    circ_b->buffer[circ_b->head] = strdup(message);
    //printf ("Value inserted at position %d is %s and count %d\r\n", circ_b->head, circ_b->buffer[circ_b->head],circ_b->count);
    circ_b->head = (circ_b->head + 1) % LOG_SIZE;
     circ_b->tail = (circ_b->tail + 1) % LOG_SIZE;
    if(circ_b->head==circ_b->tail)
        circ_b->full_status=true;
    circ_b->empty_status=false;
     
      //printf("Cant push logs\n");
  }
  pthread_mutex_unlock(&circMutex);
}

char* pop(circbuff *circ_b)
{

  pthread_mutex_lock(&circMutex);
  if (!circ_b->empty_status)
  {
    //printf ("Value read at position %d is %s and count %d\r\n", circ_b->tail, circ_b->buffer[circ_b->tail],circ_b->count);
    char* pop_value = circ_b->buffer[circ_b->tail]; //-->free after this? 
   
    circ_b->tail = (circ_b->tail + 1) % LOG_SIZE;
    if(circ_b->head==circ_b->tail)
        circ_b->empty_status=true;
    circ_b->count--;
     circ_b->full_status=false;
    return pop_value;
  }
  else
  return "Empty Buffer";
  pthread_mutex_unlock(&circMutex);
}


int main()
{
    pthread_mutex_init(&circMutex,NULL);
    circbuff* myBuffer = circbuff_init();
    char buff[20];
    scanf("%s", buff);
    push(myBuffer, buff);
    scanf("%s", buff);
    push(myBuffer, buff);

    char *tmp;
    for(int i = 0 ;i < 2; i++)
    {
        tmp = pop(myBuffer);
        printf("%s-popped\n",tmp);
        free(tmp);
    }
    pthread_mutex_destroy(&circMutex);

}
1

There are 1 answers

12
pm100 On

This code is very broken.

circ_b->buffer[circ_b->head] = (char*)malloc(strlen(message)+1);
circ_b->buffer[circ_b->head] = message;

You seem to think that the second line will copy the message into the space you just malloced. It will not; all you did was leak the memory you just allocated. You simply replace the pointer returned by malloc with the message pointer.

Use strdup it will malloc and copy for you.

Second, when the circle is full you need to free up the old node's message as well as allocate a new one.

Can you run this code on a Linux desktop? If so, run it under Valgrind, it will reveal all your leaks.

Those 'volatiles' are meaningless too.

To show that the current code is not working I made a different main

int main(){

      circbuff* myBuffer = circbuff_init(10);
      char buff[20];
      scanf("%s", buff);
      push(myBuffer, buff);
      scanf("%s", buff);
      push(myBuffer, buff);


    for(int i = 0 ;i < 2; i++)
    printf("%s-popped\n",pop(myBuffer));

}

ran it and got

hello1
Value inserted at position 0 is hello1
hello2
Value inserted at position 1 is hello2
Value read at position 0 is hello2  <<<<======
hello2-popped
Value read at position 1 is hello2
hello2-popped

you see you got hello2 out twice

and here is valgrinds output

==4752== HEAP SUMMARY:
==4752==     in use at exit: 94 bytes in 3 blocks
==4752==   total heap usage: 5 allocs, 2 frees, 2,142 bytes allocated
==4752==
==4752== 3 bytes in 1 blocks are definitely lost in loss record 1 of 3
==4752==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==4752==    by 0x109282: push (in /home/pm100/ut/a.out)
==4752==    by 0x10971B: main (in /home/pm100/ut/a.out)
==4752==
==4752== 3 bytes in 1 blocks are definitely lost in loss record 2 of 3
==4752==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==4752==    by 0x109282: push (in /home/pm100/ut/a.out)
==4752==    by 0x109746: main (in /home/pm100/ut/a.out)
==4752==
==4752== 88 bytes in 1 blocks are definitely lost in loss record 3 of 3
==4752==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==4752==    by 0x109221: circbuff_init (in /home/pm100/ut/a.out)
==4752==    by 0x1096EC: main (in /home/pm100/ut/a.out)
==4752==
==4752== LEAK SUMMARY:
==4752==    definitely lost: 94 bytes in 3 blocks
==4752==    indirectly lost: 0 bytes in 0 blocks
==4752==      possibly lost: 0 bytes in 0 blocks
==4752==    still reachable: 0 bytes in 0 blocks
==4752==         suppressed: 0 bytes in 0 blocks
==4752==
==4752== For lists of detected and suppressed errors, rerun with: -s