/* $begin sbufc */
#include "csapp.h"
#include "sbuf.h"

/* Create an empty, bounded, shared FIFO buffer with n slots */
/* $begin sbuf_init */
void sbuf_init(sbuf_t *sp, int n)
{
    sp->buf = Calloc(n, sizeof(int)); 
    sp->n = n;                       /* Buffer holds max of n items        */
    sp->front = sp->rear = 0;        /* Empty buffer iff front == rear     */
    Sem_init(&sp->mutex, 0, 1);      /* Binary semaphore for locking       */
    Sem_init(&sp->slots, 0, n);      /* Initially, buf has n empty slots   */
    Sem_init(&sp->items, 0, 0);      /* Initially, buf has zero data items */
}
/* $end sbuf_init */

/* Clean up buffer sp */
/* $begin sbuf_deinit */
void sbuf_deinit(sbuf_t *sp)
{
    Free(sp->buf);
}
/* $end sbuf_deinit */

/* Insert item onto the rear of shared buffer sp */
/* $begin sbuf_insert */
void sbuf_insert(sbuf_t *sp, int item)
{
    P(&sp->slots);               /* Wait for available slot */
    P(&sp->mutex);               /* Lock the buffer         */
    if (++sp->rear >= sp->n)     /* Increment index (mod n) */
	sp->rear = 0;
    sp->buf[sp->rear] = item;    /* Insert the item         */
    V(&sp->mutex);               /* Unlock the buffer       */
    V(&sp->items);               /* Announce available item */
}
/* $end sbuf_insert */

/* Remove and return the first item from buffer sp */
/* $begin sbuf_remove */
int sbuf_remove(sbuf_t *sp)
{
    int item;
    P(&sp->items);               /* Wait for available item */
    P(&sp->mutex);               /* Lock the buffer         */
    if (++sp->front >= sp->n)    /* Increment index (mod n) */
	sp->front = 0;
    item = sp->buf[sp->front];   /* Remove the item         */
    V(&sp->mutex);               /* Unlock the buffer       */
    V(&sp->slots);               /* Announce available slot */
    return item;
}
/* $end sbuf_remove */
/* $end sbufc */

