Update of /cvsroot/pure-data/externals/grill/flext/source
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14844/source
Modified Files:
flqueue.cpp flsupport.h
Added Files:
flcontainers.h
Log Message:
- fixed typos and 64-bit compatibility
- conform to idle callback functionality in devel_0_38
new lock-free lifo and fifo
Index: flqueue.cpp
===================================================================
RCS file: /cvsroot/pure-data/externals/grill/flext/source/flqueue.cpp,v
retrieving revision 1.27
retrieving revision 1.28
diff -C2 -d -r1.27 -r1.28
*** flqueue.cpp 8 Feb 2005 04:56:22 -0000 1.27
--- flqueue.cpp 26 Feb 2005 04:56:22 -0000 1.28
***************
*** 19,22 ****
--- 19,23 ----
#include "flext.h"
#include "flinternal.h"
+ #include "flcontainers.h"
#include <string.h> // for memcpy
***************
*** 26,40 ****
#endif
- #define QUEUE_LENGTH 2048
- #define QUEUE_ATOMS 8192
! class qmsg
{
public:
! void Set(flext_base *t,int o,const t_symbol *s,int ac,const t_atom *av)
! {
! th = t; out = o;
! sym = s,argc = ac,argv = av;
! }
// \note PD sys lock must already be held by caller
--- 27,40 ----
#endif
! class qmsg:
! public flext,
! public Cell
{
public:
! qmsg(flext_base *t,int o,const t_symbol *s,int ac,const t_atom *av)
! : msg(s,ac,av)
! , th(t),out(o)
! {}
// \note PD sys lock must already be held by caller
***************
*** 43,60 ****
if(out < 0)
// message to self
! th->m_methodmain(-1-out,sym,argc,argv);
else
// message to outlet
! th->ToSysAnything(out,sym,argc,argv);
}
- int Args() const { return argc; }
-
private:
flext_base *th;
int out;
! const t_symbol *sym;
! int argc;
! const t_atom *argv;
};
--- 43,56 ----
if(out < 0)
// message to self
! th->m_methodmain(-1-out,msg.Header(),msg.Count(),msg.Atoms());
else
// message to outlet
! th->ToSysAnything(out,msg.Header(),msg.Count(),msg.Atoms());
}
private:
flext_base *th;
int out;
! AtomAnything msg;
};
***************
*** 63,107 ****
*/
class Queue:
! public flext
{
public:
! Queue()
! {
! qhead = qtail = 0;
! ahead = atail = 0;
! }
!
! bool Empty() const { return qhead == qtail; }
!
! int Count() const
! {
! int c = qtail-qhead;
! return c >= 0?c:c+QUEUE_LENGTH;
! }
! const qmsg &Head() { return lst[qhead]; }
! void Pop()
! {
! PopAtoms(Head().Args());
! qhead = (qhead+1)%QUEUE_LENGTH;
! }
void Push(flext_base *th,int o) // bang
{
! Set(th,o,sym_bang,0,NULL);
}
void Push(flext_base *th,int o,float dt)
{
! t_atom *at = GetAtoms(1);
! SetFloat(*at,dt);
! Set(th,o,sym_float,1,at);
}
void Push(flext_base *th,int o,int dt)
{
! t_atom *at = GetAtoms(1);
! SetInt(*at,dt);
const t_symbol *sym;
#if FLEXT_SYS == FLEXT_SYS_PD
--- 59,88 ----
*/
class Queue:
! public flext,
! public Fifo
{
public:
! inline bool Empty() const { return Size() == 0; }
! inline void Push(qmsg *q) { Fifo::Put(q); }
! inline qmsg *Pop() { return static_cast<qmsg *>(Fifo::Get()); }
void Push(flext_base *th,int o) // bang
{
! Put(new qmsg(th,o,sym_bang,0,NULL));
}
void Push(flext_base *th,int o,float dt)
{
! t_atom at;
! SetFloat(at,dt);
! Put(new qmsg(th,o,sym_float,1,&at));
}
void Push(flext_base *th,int o,int dt)
{
! t_atom at;
! SetInt(at,dt);
const t_symbol *sym;
#if FLEXT_SYS == FLEXT_SYS_PD
***************
*** 112,129 ****
#error Not implemented!
#endif
! Set(th,o,sym,1,at);
}
void Push(flext_base *th,int o,const t_symbol *dt)
{
! t_atom *at = GetAtoms(1);
! SetSymbol(*at,dt);
! Set(th,o,sym_symbol,1,at);
}
void Push(flext_base *th,int o,const t_atom &a)
{
- t_atom *at = GetAtoms(1);
- *at = a;
const t_symbol *sym;
if(IsSymbol(a))
--- 93,108 ----
#error Not implemented!
#endif
! Put(new qmsg(th,o,sym,1,&at));
}
void Push(flext_base *th,int o,const t_symbol *dt)
{
! t_atom at;
! SetSymbol(at,dt);
! Put(new qmsg(th,o,sym_symbol,1,&at));
}
void Push(flext_base *th,int o,const t_atom &a)
{
const t_symbol *sym;
if(IsSymbol(a))
***************
*** 143,204 ****
return;
}
! Set(th,o,sym,1,at);
}
void Push(flext_base *th,int o,int argc,const t_atom *argv)
{
! t_atom *at = GetAtoms(argc);
! memcpy(at,argv,argc*sizeof(t_atom));
! Set(th,o,sym_list,argc,at);
}
void Push(flext_base *th,int o,const t_symbol *sym,int argc,const t_atom *argv)
{
! t_atom *at = GetAtoms(argc);
! memcpy(at,argv,argc*sizeof(t_atom));
! Set(th,o,sym,argc,at);
! }
!
! protected:
! void Set(flext_base *th,int o,const t_symbol *sym,int argc,const t_atom *argv)
! {
! FLEXT_ASSERT(Count() < QUEUE_LENGTH-1);
! lst[qtail].Set(th,o,sym,argc,argv);
! qtail = (qtail+1)%QUEUE_LENGTH;
! }
!
! int CntAtoms() const
! {
! int c = atail-ahead;
! return c >= 0?c:c+QUEUE_ATOMS;
! }
!
! // must return contiguous region
! t_atom *GetAtoms(int argc)
! {
! t_atom *ret;
! if(atail+argc >= QUEUE_ATOMS) {
! FLEXT_ASSERT(ahead > argc);
! ret = atoms;
! atail = argc;
! }
! else {
! FLEXT_ASSERT(ahead <= atail || ahead > atail+argc);
! ret = atoms+atail;
! atail += argc;
! }
! return ret;
! }
!
! void PopAtoms(int argc)
! {
! const int p = ahead+argc;
! ahead = p >= QUEUE_ATOMS?argc:p;
}
-
- volatile int qhead,qtail;
- qmsg lst[QUEUE_LENGTH];
- volatile int ahead,atail;
- t_atom atoms[QUEUE_ATOMS];
};
--- 122,137 ----
return;
}
! Put(new qmsg(th,o,sym,1,&a));
}
void Push(flext_base *th,int o,int argc,const t_atom *argv)
{
! Put(new qmsg(th,o,sym_list,argc,argv));
}
void Push(flext_base *th,int o,const t_symbol *sym,int argc,const t_atom *argv)
{
! Put(new qmsg(th,o,sym,argc,argv));
}
};
***************
*** 223,227 ****
// On the other hand, if new queue elements are added by the methods called
// in the loop, these will be sent in the next tick to avoid recursion overflow.
! int qc = queue.Count();
if(!qc) break;
--- 156,160 ----
// On the other hand, if new queue elements are added by the methods called
// in the loop, these will be sent in the next tick to avoid recursion overflow.
! size_t qc = queue.Size();
if(!qc) break;
***************
*** 230,238 ****
#endif
! // once more, because flushing in destructors could have reduced the count
! for(qc = queue.Count(); qc--; ) {
! queue.Head().Send();
! queue.Pop();
! } // inner loop
#if FLEXT_QMODE == 2
--- 163,171 ----
#endif
! qmsg *q;
! while((q = queue.Pop()) != NULL) {
! q->Send();
! delete q;
! }
#if FLEXT_QMODE == 2
--- NEW FILE: flcontainers.h ---
/*
flext - C++ layer for Max/MSP and pd (pure data) externals
Copyright (c) 2001-2005 Thomas Grill (gr(a)grrrr.org)
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "license.txt," in this distribution.
*/
/*! \file flcontainers.h
\brief Lock-free container classes
This code has been adapted from the MidiShare project (c)Grame
*/
#ifndef __FLCONTAINERS_H
#define __FLCONTAINERS_H
#include "flprefix.h"
class Cell
{
friend class Lifo;
friend class Fifo;
private:
Cell *link;
};
#if 1 //def __Pentium__
#define VTYPE volatile
#else
#define VTYPE
#endif
#define __SMP__
class FLEXT_SHARE Lifo
{
public:
inline Lifo() { Init(); }
inline void Init() { ic = oc = 0; top = NULL; }
inline Cell *Avail() { return (Cell *)top; }
#if defined(_WIN32) && defined(_MSC_VER)
#ifdef __SMP__
#define LOCK lock
#else
#define LOCK
#endif
inline void Push(Cell *cell)
{
__asm
{
push eax
push ebx
push ecx
push edx
push esi
mov esi, this
mov eax, dword ptr [esi]
mov ecx, cell
mov edx, dword ptr [esi+4]
_loop:
mov ebx, eax
inc ebx
mov [ecx], edx
LOCK cmpxchg8b qword ptr [esi]
jnz _loop
pop esi
pop edx
pop ecx
pop ebx
pop eax
}
}
inline Cell *Pop()
{
__asm
{
push ebx
push ecx
push edx
push esi
mov esi, this
add esi, 4 /* point to top */
mov edx, dword ptr [esi+4]
mov eax, dword ptr [esi]
test eax, eax
jz _end
_loop:
mov ebx, dword ptr [eax]
mov ecx, edx
inc ecx
LOCK cmpxchg8b qword ptr [esi]
jz _end
test eax, eax
jnz _loop
_end:
pop esi
pop edx
pop ecx
pop ebx
}
}
inline size_t Size() const { return ic-oc; }
#elif defined(__GNUC__) && defined(__)
#ifndef SMPLOCK
# ifdef __SMP__
# define SMPLOCK "lock ; "
# else
# define SMPLOCK ""
# endif
#endif
inline void Push(Cell *cl)
{
__asm__ __volatile__ (
"# LFPUSH \n\t"
"pushl %%ebx \n\t"
"pushl %%ecx \n\t"
"movl 0(%%esi), %%eax \n\t"
"movl 4(%%esi), %%edx \n"
"1: \t"
"movl %%eax, %%ebx \n\t"
"incl %%ebx \n\t"
"movl %%edx, (%%ecx) \n\t"
SMPLOCK "cmpxchg8b (%%esi) \n\t"
"jnz 1b \n\t"
"popl %%ecx \n\t"
"popl %%ebx \n\t"
:/* no output */
:"S" (this), "c" (cl)
:"memory", "eax", "edx");
}
inline Cell *Pop()
{
cell* v=0;
__asm__ __volatile__ (
"# LFPOP \n\t"
"pushl %%ebx \n\t"
"pushl %%ecx \n\t"
"movl 4(%%esi), %%edx \n\t"
"movl (%%esi), %%eax \n\t"
"testl %%eax, %%eax \n\t"
"jz 20f \n"
"10: \t"
"movl (%%eax), %%ebx \n\t"
"movl %%edx, %%ecx \n\t"
"incl %%ecx \n\t"
SMPLOCK "cmpxchg8b (%%esi) \n\t"
"jz 20f \n\t"
"testl %%eax, %%eax \n\t"
"jnz 10b \n"
"20: \t"
"popl %%ecx \n\t"
"popl %%ebx \n\t"
:"=a" (v)
:"S" (&this->top)
:"memory", "edx");
return v;
}
inline size_t Size()
{
size_t n;
__asm__ __volatile__ (
"# LFSIZE \n\t"
"movl 8(%%esi), %%edx \n\t"
"movl (%%esi), %%eax \n\t"
"subl %%edx, %%eax \n\t"
:"=a" (n)
:"S" (this)
:"memory", "edx");
return n;
}
#elif defined(__GNUC__) && defined(__POWERPC__)
inline void Push(register Cell *cl)
{
register volatile long t1;
register long t2=0;
asm volatile (
"# LFPUSH \n"
"0: \n"
" lwarx %0, %3, %1 \n"
" stw %0, 0(%2) \n"
" sync \n"
" stwcx. %2, %3, %1 \n"
" bne- 0b \n"
"0: \n"
" lwarx %0, %3, %4 \n"
" addi %0, %0, 1 \n"
" sync \n"
" stwcx. %0, %3, %4 \n"
" bne- 0b \n"
: "=r" (t1)
: "r" (&this->top), "r" (cl), "r" (t2), "r" (&this->oc), "0" (t1)
: "r0" /* prevents using r0 because of the ambiguity of 'addi' coding: */
/* gcc version 2.95.3 20010315 (release - Linux-Mandrake 8.0 for PPC) */
/* compiles the instruction "addi 0, 0, n" as li 0, n */
);
}
inline Cell *Pop()
{
register Cell *result;
register volatile long a, b;
register long c=0;
asm volatile (
"# LFPOP \n"
"0: \n"
" lwarx %4, %1, %2 \n" /* creates a reservation on lf */
" cmpwi %4, 0 \n" /* test if the lifo is empty */
" beq- 1f \n"
" lwz %5, 0(%4) \n" /* next cell in b */
" sync \n" /* synchronize instructions */
" stwcx. %5, %1, %2 \n" /* if the reservation is not altered */
/* modify lifo top */
" bne- 0b \n" /* otherwise: loop and try again */
"0: \n"
" lwarx %5, %1, %3 \n" /* creates a reservation on lf->count */
" addi %5, %5, -1 \n" /* dec count */
" sync \n" /* synchronize instructions */
" stwcx. %5, %1, %3 \n" /* conditionnal store */
" bne- 0b \n"
"1: \n"
" mr %0, %4 \n"
:"=r" (result), "=r" (c)
: "r" (&this->top), "r" (&this->oc), "r" (a), "r" (b), "1" (c)
: "r0" /* prevents using r0 because of the ambiguity of 'addi' coding: */
/* gcc version 2.95.3 20010315 (release - Linux-Mandrake 8.0 for PPC) */
/* compiles the instruction "addi 0, 0, n" as li 0, n */
);
return result;
}
inline size_t Size() const { return oc; }
#endif
private:
// don't change order!
VTYPE size_t ic; // input (push) count
VTYPE Cell *top; // top of the stack
VTYPE size_t oc; // output (pop) count
#ifdef __POWERPC__
size_t unused[5]; // lifo size must be at least 32 bytes
// to avoid livelock in multiprocessor
#endif
};
class FLEXT_SHARE Fifo
{
public:
void Init() { in.Init(); out.Init(); }
inline size_t Size() const { return in.Size()+out.Size(); }
inline void Put(Cell *cl) { in.Push(cl); }
Cell *Get()
{
Cell *v1 = out.Pop();
if(!v1) {
v1 = in.Pop();
if(v1)
for(Cell *v2; (v2 = in.Pop()) != NULL; v1 = v2)
out.Push(v1);
}
return v1;
}
Cell *Avail()
{
Cell *v1 = out.Avail();
if(v1)
return v1;
else {
for(Cell *v2; (v2 = in.Pop()) != NULL; )
out.Push(v2);
return out.Avail();
}
}
Cell *Clear()
{
Cell *first = Get();
if(!first) return NULL;
Cell *next,*cur = first;
while((next = Get()) != NULL) {
cur->link = next;
cur = next;
}
cur->link = NULL;
Init();
return first;
}
Lifo in,out;
};
#endif
Index: flsupport.h
===================================================================
RCS file: /cvsroot/pure-data/externals/grill/flext/source/flsupport.h,v
retrieving revision 1.78
retrieving revision 1.79
diff -C2 -d -r1.78 -r1.79
*** flsupport.h 12 Feb 2005 04:56:09 -0000 1.78
--- flsupport.h 26 Feb 2005 04:56:23 -0000 1.79
***************
*** 139,143 ****
//! Flext version string
! static const char *VersionStr();
// --- buffer/array stuff -----------------------------------------
--- 139,143 ----
//! Flext version string
! static const char *VersionStr();
// --- buffer/array stuff -----------------------------------------