Blame src/libout123/sfifo.c

Packit c32a2d
/*
Packit c32a2d
	SFIFO 1.3 Simple portable lock-free FIFO
Packit c32a2d
Packit c32a2d
	(c) 2000-2002, David Olofson - free software under the terms of the LGPL 2.1
Packit c32a2d
*/
Packit c32a2d
Packit c32a2d
Packit c32a2d
/*
Packit c32a2d
-----------------------------------------------------------
Packit c32a2d
TODO:
Packit c32a2d
	* Is there a way to avoid losing one byte of buffer
Packit c32a2d
	  space to avoid extra variables or locking?
Packit c32a2d
Packit c32a2d
	* Test more compilers and environments.
Packit c32a2d
-----------------------------------------------------------
Packit c32a2d
 */
Packit c32a2d
Packit c32a2d
#include	<string.h>
Packit c32a2d
#include	<stdlib.h>
Packit c32a2d
Packit c32a2d
#include "sfifo.h"
Packit c32a2d
#include "debug.h"
Packit c32a2d
Packit c32a2d
/*
Packit c32a2d
 * Alloc buffer, init FIFO etc...
Packit c32a2d
 */
Packit c32a2d
SFIFO_SCOPE int sfifo_init(sfifo_t *f, int size)
Packit c32a2d
{
Packit c32a2d
	memset(f, 0, sizeof(sfifo_t));
Packit c32a2d
Packit c32a2d
	if(size > SFIFO_MAX_BUFFER_SIZE)
Packit c32a2d
		return -EINVAL;
Packit c32a2d
Packit c32a2d
	/*
Packit c32a2d
	 * Set sufficient power-of-2 size.
Packit c32a2d
	 *
Packit c32a2d
	 * No, there's no bug. If you need
Packit c32a2d
	 * room for N bytes, the buffer must
Packit c32a2d
	 * be at least N+1 bytes. (The fifo
Packit c32a2d
	 * can't tell 'empty' from 'full'
Packit c32a2d
	 * without unsafe index manipulations
Packit c32a2d
	 * otherwise.)
Packit c32a2d
	 */
Packit c32a2d
	f->size = 1;
Packit c32a2d
	for(; f->size <= size; f->size <<= 1)
Packit c32a2d
		;
Packit c32a2d
Packit c32a2d
	/* Get buffer */
Packit c32a2d
	if( 0 == (f->buffer = (void *)malloc(f->size)) )
Packit c32a2d
		return -ENOMEM;
Packit c32a2d
Packit c32a2d
	return 0;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/*
Packit c32a2d
 * Dealloc buffer etc...
Packit c32a2d
 */
Packit c32a2d
SFIFO_SCOPE void sfifo_close(sfifo_t *f)
Packit c32a2d
{
Packit c32a2d
	if(f->buffer) {
Packit c32a2d
		free(f->buffer);
Packit c32a2d
		f->buffer = NULL;	/* Prevent double free */
Packit c32a2d
	}
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/*
Packit c32a2d
 * Empty FIFO buffer
Packit c32a2d
 */
Packit c32a2d
SFIFO_SCOPE void sfifo_flush(sfifo_t *f)
Packit c32a2d
{
Packit c32a2d
	debug("sfifo_flush()");
Packit c32a2d
	/* Reset positions */
Packit c32a2d
	f->readpos = 0;
Packit c32a2d
	f->writepos = 0;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/*
Packit c32a2d
 * Write bytes to a FIFO
Packit c32a2d
 * Return number of bytes written, or an error code
Packit c32a2d
 */
Packit c32a2d
SFIFO_SCOPE int sfifo_write(sfifo_t *f, const void *_buf, int len)
Packit c32a2d
{
Packit c32a2d
	int total;
Packit c32a2d
	int i;
Packit c32a2d
	const char *buf = (const char *)_buf;
Packit c32a2d
Packit c32a2d
	if(!f->buffer)
Packit c32a2d
		return -ENODEV;	/* No buffer! */
Packit c32a2d
Packit c32a2d
	/* total = len = min(space, len) */
Packit c32a2d
	total = sfifo_space(f);
Packit c32a2d
	debug1("sfifo_space() = %d",total);
Packit c32a2d
	if(len > total)
Packit c32a2d
		len = total;
Packit c32a2d
	else
Packit c32a2d
		total = len;
Packit c32a2d
	debug1("sfifo_write() = %d", total);
Packit c32a2d
Packit c32a2d
	i = f->writepos;
Packit c32a2d
	if(i + len > f->size)
Packit c32a2d
	{
Packit c32a2d
		memcpy(f->buffer + i, buf, f->size - i);
Packit c32a2d
		buf += f->size - i;
Packit c32a2d
		len -= f->size - i;
Packit c32a2d
		i = 0;
Packit c32a2d
	}
Packit c32a2d
	memcpy(f->buffer + i, buf, len);
Packit c32a2d
	f->writepos = i + len;
Packit c32a2d
Packit c32a2d
	return total;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
Packit c32a2d
/*
Packit c32a2d
 * Read bytes from a FIFO
Packit c32a2d
 * Return number of bytes read, or an error code
Packit c32a2d
 */
Packit c32a2d
SFIFO_SCOPE int sfifo_read(sfifo_t *f, void *_buf, int len)
Packit c32a2d
{
Packit c32a2d
	int total;
Packit c32a2d
	int i;
Packit c32a2d
	char *buf = (char *)_buf;
Packit c32a2d
Packit c32a2d
	if(!f->buffer)
Packit c32a2d
		return -ENODEV;	/* No buffer! */
Packit c32a2d
Packit c32a2d
	/* total = len = min(used, len) */
Packit c32a2d
	total = sfifo_used(f);
Packit c32a2d
	debug1("sfifo_used() = %d",total);
Packit c32a2d
	if(len > total)
Packit c32a2d
		len = total;
Packit c32a2d
	else
Packit c32a2d
		total = len;
Packit c32a2d
	debug1("sfifo_read() = %d", total);
Packit c32a2d
Packit c32a2d
	i = f->readpos;
Packit c32a2d
	if(i + len > f->size)
Packit c32a2d
	{
Packit c32a2d
		memcpy(buf, f->buffer + i, f->size - i);
Packit c32a2d
		buf += f->size - i;
Packit c32a2d
		len -= f->size - i;
Packit c32a2d
		i = 0;
Packit c32a2d
	}
Packit c32a2d
	memcpy(buf, f->buffer + i, len);
Packit c32a2d
	f->readpos = i + len;
Packit c32a2d
Packit c32a2d
	return total;
Packit c32a2d
}
Packit c32a2d