/* 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 . */ #ifndef CBOX_FIFO_H #define CBOX_FIFO_H #include #include #include #include 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