From 327c548eb8237c5dd1c6f9eca4fe7787e03506b1 Mon Sep 17 00:00:00 2001 From: Thomas Grill Date: Sat, 26 Feb 2005 04:56:23 +0000 Subject: - fixed typos and 64-bit compatibility - conform to idle callback functionality in devel_0_38 new lock-free lifo and fifo svn path=/trunk/; revision=2582 --- externals/grill/flext/flext.vcproj | 3 + externals/grill/flext/source/flcontainers.h | 315 ++++++++++++++++++++++++++++ externals/grill/flext/source/flqueue.cpp | 137 ++++-------- externals/grill/flext/source/flsupport.h | 2 +- 4 files changed, 354 insertions(+), 103 deletions(-) create mode 100644 externals/grill/flext/source/flcontainers.h (limited to 'externals') diff --git a/externals/grill/flext/flext.vcproj b/externals/grill/flext/flext.vcproj index 8c043589..b948179c 100644 --- a/externals/grill/flext/flext.vcproj +++ b/externals/grill/flext/flext.vcproj @@ -3310,6 +3310,9 @@ copy F:\prog\max\flext\max-msvc\flext.max.dll f:\prog\dll BrowseInformation="1"/> + + diff --git a/externals/grill/flext/source/flcontainers.h b/externals/grill/flext/source/flcontainers.h new file mode 100644 index 00000000..562bbf64 --- /dev/null +++ b/externals/grill/flext/source/flcontainers.h @@ -0,0 +1,315 @@ +/* + +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 diff --git a/externals/grill/flext/source/flqueue.cpp b/externals/grill/flext/source/flqueue.cpp index f629379b..62a8b35a 100755 --- a/externals/grill/flext/source/flqueue.cpp +++ b/externals/grill/flext/source/flqueue.cpp @@ -18,6 +18,7 @@ WARRANTIES, see the file, "license.txt," in this distribution. #include "flext.h" #include "flinternal.h" +#include "flcontainers.h" #include // for memcpy #ifdef FLEXT_THREADS @@ -25,84 +26,64 @@ WARRANTIES, see the file, "license.txt," in this distribution. flext::thrid_t flext::thrmsgid = 0; #endif -#define QUEUE_LENGTH 2048 -#define QUEUE_ATOMS 8192 -class qmsg +class qmsg: + public flext, + public Cell { 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; - } + 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 void Send() const { if(out < 0) // message to self - th->m_methodmain(-1-out,sym,argc,argv); + th->m_methodmain(-1-out,msg.Header(),msg.Count(),msg.Atoms()); else // message to outlet - th->ToSysAnything(out,sym,argc,argv); + th->ToSysAnything(out,msg.Header(),msg.Count(),msg.Atoms()); } - int Args() const { return argc; } - private: flext_base *th; int out; - const t_symbol *sym; - int argc; - const t_atom *argv; + AtomAnything msg; }; /* \TODO This is only thread-safe if called from one thread which need NOT be the case. Reimplement in a thread-safe manner!!! */ class Queue: - public flext + public flext, + public Fifo { 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; - } + inline bool Empty() const { return Size() == 0; } - const qmsg &Head() { return lst[qhead]; } + inline void Push(qmsg *q) { Fifo::Put(q); } - void Pop() - { - PopAtoms(Head().Args()); - qhead = (qhead+1)%QUEUE_LENGTH; - } + inline qmsg *Pop() { return static_cast(Fifo::Get()); } void Push(flext_base *th,int o) // bang { - Set(th,o,sym_bang,0,NULL); + Put(new qmsg(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); + 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 = GetAtoms(1); - SetInt(*at,dt); + t_atom at; + SetInt(at,dt); const t_symbol *sym; #if FLEXT_SYS == FLEXT_SYS_PD sym = sym_float; @@ -111,20 +92,18 @@ public: #else #error Not implemented! #endif - Set(th,o,sym,1,at); + Put(new qmsg(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); + 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) { - t_atom *at = GetAtoms(1); - *at = a; const t_symbol *sym; if(IsSymbol(a)) sym = sym_symbol; @@ -142,64 +121,18 @@ public: error("atom type not supported"); return; } - Set(th,o,sym,1,at); + Put(new qmsg(th,o,sym,1,&a)); } 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); + 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) { - 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; + Put(new qmsg(th,o,sym,argc,argv)); } - - 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]; }; static Queue queue; @@ -222,18 +155,18 @@ static void QWork(bool syslock) // qc will be a minimum guaranteed number of present queue elements. // 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(); + size_t qc = queue.Size(); if(!qc) break; #if FLEXT_QMODE == 2 if(syslock) flext::Lock(); #endif - // once more, because flushing in destructors could have reduced the count - for(qc = queue.Count(); qc--; ) { - queue.Head().Send(); - queue.Pop(); - } // inner loop + qmsg *q; + while((q = queue.Pop()) != NULL) { + q->Send(); + delete q; + } #if FLEXT_QMODE == 2 if(syslock) flext::Unlock(); diff --git a/externals/grill/flext/source/flsupport.h b/externals/grill/flext/source/flsupport.h index 9377b021..123f956a 100644 --- a/externals/grill/flext/source/flsupport.h +++ b/externals/grill/flext/source/flsupport.h @@ -138,7 +138,7 @@ public: static int Version(); //! Flext version string - static const char *VersionStr(); + static const char *VersionStr(); // --- buffer/array stuff ----------------------------------------- -- cgit v1.2.1