[PD-cvs] pd/src m_fifo.h,NONE,1.1.2.1 m_fifo.c,NONE,1.1.2.1
Tim Blechmann
timblech at users.sourceforge.net
Thu Dec 2 16:17:53 CET 2004
Update of /cvsroot/pure-data/pd/src
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10276
Added Files:
Tag: devel_0_38
m_fifo.h m_fifo.c
Log Message:
added fifo api ... lockfree at least on gcc / x86
--- NEW FILE: m_fifo.h ---
/* Copyright (c) 2004, Tim Blechmann
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt" in this distribution. */
#include "m_pd.h"
/* possibly this can go to m_pd.h */
/* used data structures */
EXTERN_STRUCT _fifo;
#define t_fifo struct _fifo
/* function prototypes */
t_fifo * fifo_init();
void fifo_destroy(t_fifo*);
/* fifo_put() and fifo_get are the only threadsafe functions!!! */
void fifo_put(t_fifo*, void*);
void* fifo_get(t_fifo*);
--- NEW FILE: m_fifo.c ---
/* Copyright (c) 2004, Tim Blechmann
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt" in this distribution. */
#include "stddef.h"
#include "m_pd.h"
#include "m_fifo.h"
typedef struct _fifocell
{
void* data; /* pointer to our data */
struct _fifocell* next;
} t_fifocell;
#ifdef LOCKFREE
/* lock-free fifo implementation adapted from:
* Dominique Fober, Yann Orlarey, Stephane Letz
* Lock-Free Techniques for Concurrent Access to Shared Objects
*/
/* for gcc on i386 */
#if defined(__GNUC__) && (defined(_X86_) || defined(__i386__) || defined(__i586__) || defined(__i686__))
#define CAS(mem, old, new) \
({ __asm__ __volatile__( \
"lock cmpxchg %2,%0 \n" \
: : \
"m" (mem), "a" (old), "r" (new) ); \
old != (__typeof__(old))(mem); \
})
#define CAS2(mem, old1, old2, new1, new2) \
({ __asm__ __volatile__( \
"lock cmpxchg8b %0 \n" \
: : \
"m" (mem), "a" (old1), "d" (old2), \
"b" (new1), "c"(new2)); \
old1 != (__typeof__(old1)) (mem); \
})
#else
#error Lockfree Fifo not yet implemented on this platform
#endif
struct _fifo
{
t_fifocell* head;
unsigned long ocount; /* operation counter */
t_fifocell* tail;
unsigned long icount; /* operation counter */
};
t_fifo* fifo_init()
{
t_fifo* ret = (t_fifo*) getbytes(sizeof(t_fifo));
t_fifocell * fifo_begin = (t_fifocell*) getbytes (sizeof (t_fifocell) );
fifo_begin->data = NULL;
fifo_begin->next = NULL;
ret->head = fifo_begin;
ret->tail = fifo_begin;
ret->icount = 0;
ret->ocount = 0;
return ret;
}
void fifo_destroy(t_fifo* fifo)
{
void * data;
do
{
data = fifo_get(fifo);
}
while (data != NULL);
freebytes(fifo->head, sizeof(t_fifocell));
freebytes(fifo, sizeof(t_fifo));
return;
}
void fifo_put(t_fifo* fifo, void* data)
{
if (data != NULL)
{
t_fifocell * cell = (t_fifocell*) getbytes(sizeof(t_fifocell));
t_fifocell * tail;
unsigned long icount;
cell->data = data;
cell->next = NULL;
while(1)
{
icount = fifo->icount;
tail = fifo->tail;
if (CAS(tail->next, NULL, cell))
break;
else
CAS2(fifo->tail, tail, icount, tail->next, icount + 1);
}
CAS2(fifo->tail, tail, icount, cell, icount +1);
return;
}
else
error("invalid data: NULL");
}
void* fifo_get(t_fifo* fifo)
{
t_fifocell * head;
void* data;
while (1)
{
unsigned long ocount = fifo->ocount;
unsigned long icount = fifo->icount;
t_fifocell * next;
head = fifo->head;
next = head->next;
if (ocount == fifo->ocount)
{
if (head == fifo->tail)
{
if (next == NULL)
return NULL;
CAS2(fifo->tail, head, icount, next, icount + 1);
}
else
{
data = next->data;
if (CAS2(fifo->head, head, ocount, next, ocount+1))
break;
}
}
}
freebytes(head, sizeof(t_fifocell));
return data;
}
#else
/* we always have the implementation for posix systems with threadlocks */
#include "pthread.h"
#include "errno.h"
struct _fifo
{
t_fifocell * head;
t_fifocell * tail;
pthread_mutex_t mutex;
};
t_fifo * fifo_init()
{
t_fifo* ret = (t_fifo*) getbytes(sizeof (t_fifo));
t_fifocell * fifo_begin = (t_fifocell*) getbytes (sizeof (t_fifocell) );
fifo_begin->data = NULL;
fifo_begin->next = NULL;
ret->head = fifo_begin;
ret->tail = fifo_begin;
pthread_mutex_init(&ret->mutex, NULL);
pthread_mutex_unlock(&ret->mutex);
return ret;
}
void fifo_destroy(t_fifo* fifo)
{
void * data;
do
{
data = fifo_get(fifo);
}
while (data != NULL);
pthread_mutex_lock(&fifo->mutex);
pthread_mutex_destroy(&fifo->mutex);
freebytes(fifo, sizeof(t_fifo));
return;
}
/* fifo_put() and fifo_get are the only threadsafe functions!!! */
void fifo_put(t_fifo* fifo, void* data)
{
if (data != NULL)
{
t_fifocell * cell = (t_fifocell*) getbytes(sizeof(t_fifocell));
cell->data = data;
cell->next = NULL;
pthread_mutex_lock(&fifo->mutex);
fifo->tail->next = cell;
fifo->tail = cell;
pthread_mutex_unlock(&fifo->mutex);
}
return;
}
/* this fifo_get returns NULL if the fifo is empty
* or locked by another thread */
void* fifo_get(t_fifo* fifo)
{
t_fifocell * cell;
void* data;
if(pthread_mutex_trylock(&fifo->mutex) != EBUSY)
{
cell = fifo->head->next;
if (cell != NULL)
{
fifo->head->next = cell->next;
if(cell == fifo->tail)
fifo->tail = fifo->head;
data = cell->data;
freebytes (cell, sizeof(t_fifocell));
}
else
data = NULL;
pthread_mutex_unlock(&fifo->mutex);
}
else
data = NULL;
return data;
}
#endif
More information about the Pd-cvs
mailing list