On Thu, 2003-04-03 at 21:14, rm wrote:

> below is what i use (i think it works). the primary thing to notice
> is that readers and writers are kept in line by the atomicity of
> integer assignment (though in general, we should probably declare them
> atomic_t or something).

Attached is the fifo I've had banging about.  It uses atomic_t.

-- 
Bob Ham <[EMAIL PROTECTED]>
/*
 *   Lock free FIFO
 *    
 *   Copyright (C) Robert Ham 2002, 2003 ([EMAIL PROTECTED])
 *    
 *   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 <stdlib.h>
#include <string.h>

#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 */


/*
 *   Lock free FIFO
 *    
 *   Copyright (C) Robert Ham 2002, 2003 ([EMAIL PROTECTED])
 *    
 *   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.
 */

#ifndef __LOCK_FREE_FIFO_H__
#define __LOCK_FREE_FIFO_H__

#include <asm/atomic.h>

typedef struct _lff lff_t;

/** lock free fifo ring buffer structure */
struct _lff {

  /** Size of the ringbuffer (in elements) */
  unsigned int size;

  /** the memory containing the ringbuffer */
  void * data;

  /** the size of an element */
  size_t object_size;

  /** the current position of the reader */
  atomic_t read_index;

  /** the current position of the writer */
  atomic_t write_index;
};

void lff_init (lff_t * lff, unsigned int size, size_t object_size);
void lff_free (lff_t * lff);

lff_t * lff_new     (unsigned int size, size_t object_size);
void    lff_destroy (lff_t * lock_free_fifo);
               
int lff_read (lff_t * lock_free_fifo, void * data);
int lff_write (lff_t * lock_free_fifo, const void * data);

#endif /* __LOCK_FREE_FIFO_H__ */

Attachment: signature.asc
Description: This is a digitally signed message part

Reply via email to