You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
137 lines
4.2 KiB
137 lines
4.2 KiB
3 years ago
|
/*
|
||
|
Calf Box, an open source musical instrument.
|
||
|
Copyright (C) 2010-2013 Krzysztof Foltman
|
||
|
|
||
|
This program is free software: you can redistribute it and/or modify
|
||
|
it under the terms of the GNU General Public License as published by
|
||
|
the Free Software Foundation, either version 3 of the License, or
|
||
|
(at your option) any later version.
|
||
|
|
||
|
This program is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
#ifndef CBOX_FIFO_H
|
||
|
#define CBOX_FIFO_H
|
||
|
|
||
|
#include <assert.h>
|
||
|
#include <stdint.h>
|
||
|
#include <glib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
struct cbox_fifo
|
||
|
{
|
||
|
uint8_t *data;
|
||
|
uint32_t size;
|
||
|
uint64_t pad; // ensure the write-related and read-related structs are on 64 bit boundary
|
||
|
uint32_t write_count;
|
||
|
uint32_t write_offset;
|
||
|
uint32_t read_count;
|
||
|
uint32_t read_offset;
|
||
|
};
|
||
|
|
||
|
extern struct cbox_fifo *cbox_fifo_new(uint32_t size);
|
||
|
|
||
|
static inline uint32_t cbox_fifo_readsize(struct cbox_fifo *fifo);
|
||
|
static inline uint32_t cbox_fifo_writespace(struct cbox_fifo *fifo);
|
||
|
static inline gboolean cbox_fifo_read_atomic(struct cbox_fifo *fifo, void *dest, uint32_t bytes);
|
||
|
static inline gboolean cbox_fifo_write_atomic(struct cbox_fifo *fifo, const void *src, uint32_t bytes);
|
||
|
static inline gboolean cbox_fifo_peek(struct cbox_fifo *fifo, void *dest, uint32_t bytes);
|
||
|
static inline gboolean cbox_fifo_consume(struct cbox_fifo *fifo, uint32_t bytes);
|
||
|
|
||
|
extern void cbox_fifo_destroy(struct cbox_fifo *fifo);
|
||
|
|
||
|
|
||
|
static inline uint32_t cbox_fifo_readsize(struct cbox_fifo *fifo)
|
||
|
{
|
||
|
return fifo->write_count - fifo->read_count;
|
||
|
}
|
||
|
|
||
|
static inline uint32_t cbox_fifo_writespace(struct cbox_fifo *fifo)
|
||
|
{
|
||
|
return fifo->size - (fifo->write_count - fifo->read_count);
|
||
|
}
|
||
|
|
||
|
static inline gboolean cbox_fifo_read_impl(struct cbox_fifo *fifo, void *dest, uint32_t bytes, gboolean advance)
|
||
|
{
|
||
|
__sync_synchronize();
|
||
|
if (fifo->write_count - fifo->read_count < bytes)
|
||
|
return FALSE;
|
||
|
|
||
|
if (dest)
|
||
|
{
|
||
|
uint32_t ofs = fifo->read_count - fifo->read_offset;
|
||
|
assert(ofs >= 0 && ofs < fifo->size);
|
||
|
if (ofs + bytes > fifo->size)
|
||
|
{
|
||
|
uint8_t *dstb = dest;
|
||
|
uint32_t firstpart = fifo->size - ofs;
|
||
|
memcpy(dstb, fifo->data + ofs, firstpart);
|
||
|
memcpy(dstb + firstpart, fifo->data, bytes - firstpart);
|
||
|
}
|
||
|
else
|
||
|
memcpy(dest, fifo->data + ofs, bytes);
|
||
|
}
|
||
|
|
||
|
if (advance)
|
||
|
{
|
||
|
__sync_synchronize();
|
||
|
// Make sure data are copied before signalling that they can be overwritten
|
||
|
fifo->read_count += bytes;
|
||
|
if (fifo->read_count - fifo->read_offset >= fifo->size)
|
||
|
fifo->read_offset += fifo->size;
|
||
|
}
|
||
|
__sync_synchronize();
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static inline gboolean cbox_fifo_read_atomic(struct cbox_fifo *fifo, void *dest, uint32_t bytes)
|
||
|
{
|
||
|
return cbox_fifo_read_impl(fifo, dest, bytes, TRUE);
|
||
|
}
|
||
|
|
||
|
static inline gboolean cbox_fifo_peek(struct cbox_fifo *fifo, void *dest, uint32_t bytes)
|
||
|
{
|
||
|
return cbox_fifo_read_impl(fifo, dest, bytes, FALSE);
|
||
|
}
|
||
|
|
||
|
static inline gboolean cbox_fifo_consume(struct cbox_fifo *fifo, uint32_t bytes)
|
||
|
{
|
||
|
return cbox_fifo_read_impl(fifo, NULL, bytes, TRUE);
|
||
|
}
|
||
|
|
||
|
static inline gboolean cbox_fifo_write_atomic(struct cbox_fifo *fifo, const void *src, uint32_t bytes)
|
||
|
{
|
||
|
if (fifo->size - (fifo->write_count - fifo->read_count) < bytes)
|
||
|
return FALSE;
|
||
|
|
||
|
uint32_t ofs = fifo->write_count - fifo->write_offset;
|
||
|
assert(ofs >= 0 && ofs < fifo->size);
|
||
|
if (ofs + bytes > fifo->size)
|
||
|
{
|
||
|
const uint8_t *srcb = src;
|
||
|
uint32_t firstpart = fifo->size - ofs;
|
||
|
memcpy(fifo->data + ofs, srcb, firstpart);
|
||
|
memcpy(fifo->data, srcb + firstpart, bytes - firstpart);
|
||
|
}
|
||
|
else
|
||
|
memcpy(fifo->data + ofs, src, bytes);
|
||
|
|
||
|
// Make sure data are in the buffer before announcing the availability
|
||
|
__sync_synchronize();
|
||
|
fifo->write_count += bytes;
|
||
|
if (fifo->write_count - fifo->write_offset >= fifo->size)
|
||
|
fifo->write_offset += fifo->size;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
#endif
|