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@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 -----------------------------------------