[PD-cvs] externals/grill/flext/source flcontainers.h,NONE,1.1 flqueue.cpp,1.27,1.28 flsupport.h,1.78,1.79

Thomas Grill xovo at users.sourceforge.net
Sat Feb 26 05:56:29 CET 2005


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





More information about the Pd-cvs mailing list