/* * Lock free FIFO * * Copyright (C) Robert Ham 2002, 2003 (node_AT_users.sourceforge.net) * * 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 2 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, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include "lff.h" void lff_init (lff_t * lff, unsigned int size, size_t object_size) { // this is +1 becase we need to have an empty element when the buffer is // full otherwise there's no way to know if it's full or empty lff->size = size + 1; lff->object_size = object_size; lff->data = malloc (object_size * lff->size); atomic_set (&lff->read_index, 0); atomic_set (&lff->write_index, 0); } void lff_free (lff_t * lff) { free (lff->data); } lff_t * lff_new (unsigned int size, size_t object_size) { lff_t * lff; lff = malloc (sizeof (lff_t)); lff_init (lff, size, object_size); return lff; } void lff_destroy (lff_t * lff) { lff_free (lff); free (lff); } /** read an element from the fifo into data. returns 0 on success, non-zero if there were no elements to read */ int lff_read (lff_t * lff, void * data) { if (atomic_read (&lff->read_index) == atomic_read (&lff->write_index)) return -1; else { memcpy (data, ((char *)lff->data) + (atomic_read (&lff->read_index) * lff->object_size), lff->object_size); atomic_inc (&lff->read_index); if (atomic_read (&lff->read_index) >= lff->size) atomic_set (&lff->read_index, 0); return 0; } } /** write an element from data to the fifo. returns 0 on success, non-zero if there was no space */ int lff_write (lff_t * lff, const void * data) { int read_index; /* got to read read_index only once for safety */ read_index = atomic_read (&lff->read_index); /* lots of logic for when we're allowed to write to the fifo which basically boils down to "don't write if we're one element behind the read index" */ if ((read_index > atomic_read (&lff->write_index) && read_index - atomic_read (&lff->write_index) > 1) || (atomic_read (&lff->write_index) >= read_index && atomic_read (&lff->write_index) != lff->size - 1) || (atomic_read (&lff->write_index) >= read_index && atomic_read (&lff->write_index) == lff->size - 1 && read_index != 0)) { memcpy (((char *)lff->data) + (atomic_read (&lff->write_index) * lff->object_size), data, lff->object_size); atomic_inc (&lff->write_index); if (atomic_read (&lff->write_index) >= lff->size) atomic_set (&lff->write_index, -1); } else return -1; return 0; } /* EOF */