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);
}
This code is very broken.
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
ran it and got
you see you got hello2 out twice
and here is valgrinds output