diff options
Diffstat (limited to 'externals/grill/flext')
-rw-r--r-- | externals/grill/flext/readme.txt | 2 | ||||
-rw-r--r-- | externals/grill/flext/source/flclass.h | 31 | ||||
-rw-r--r-- | externals/grill/flext/source/fldefs.h | 20 | ||||
-rw-r--r-- | externals/grill/flext/source/flext.cpp | 31 | ||||
-rw-r--r-- | externals/grill/flext/source/flthr.cpp | 164 |
5 files changed, 202 insertions, 46 deletions
diff --git a/externals/grill/flext/readme.txt b/externals/grill/flext/readme.txt index 4a83e225..b58df39c 100644 --- a/externals/grill/flext/readme.txt +++ b/externals/grill/flext/readme.txt @@ -109,6 +109,8 @@ Version history: - also FLEXT_DEBUG for debug build - SndObjs: virtual FreeObject routine is now called at destruction (by parent class), derived class doesn't need to call it! - SndObjs: fixed typo (numbers of output slots was wrong) and init bug +- introduced a helper thread for launching flext threads in the background +- threads are now handled on class (as opposed to object) level 0.4.0: - the use of the const keyword is enforced (e.g. the preferred type for symbols is now "const t_symbol *") diff --git a/externals/grill/flext/source/flclass.h b/externals/grill/flext/source/flclass.h index 12efeb82..6f74b5fe 100644 --- a/externals/grill/flext/source/flclass.h +++ b/externals/grill/flext/source/flclass.h @@ -467,20 +467,19 @@ protected: class thr_entry { public: - thr_entry(pthread_t id = pthread_self()): thrid(id),nxt(NULL) {} + thr_entry(flext_base *t,void *(*m)(thr_params *),thr_params *p,pthread_t id = pthread_self()): th(t),meth(m),params(p),thrid(id),active(false),nxt(NULL) {} //! \brief Check if this class represents the current thread bool Is(pthread_t id = pthread_self()) const { return pthread_equal(thrid,id) != 0; } + bool active; pthread_t thrid; + void *(*meth)(thr_params *); + thr_params *params; + flext_base *th; thr_entry *nxt; }; - /*! \brief Start a method thread - \internal - */ - static bool StartThread(void *(*meth)(thr_params *p),thr_params *p,char *methname); - /*! \brief Add current thread to list of active threads \return true on success \internal @@ -491,6 +490,13 @@ protected: \internal */ void PopThread(); + +public: + /*! \brief Start a method thread + \internal + */ + bool StartThread(void *(*meth)(thr_params *p),thr_params *p,char *methname); + #endif protected: @@ -657,11 +663,18 @@ private: bool shouldexit; int thrcount; - pthread_t thrid; // the thread that created the object (the system thread) + static pthread_t thrid; // the thread that created the object (the system thread) ThrMutex qmutex; - thr_entry *thrhead,*thrtail; - ThrMutex tlmutex; + static thr_entry *thrhead,*thrtail; + static ThrMutex tlmutex; + + static pthread_t thrhelpid; + static bool StartHelper(); + static bool StopHelper(); + static void ThrHelper(void *); + + void TermThreads(); #endif class qmsg; diff --git a/externals/grill/flext/source/fldefs.h b/externals/grill/flext/source/fldefs.h index 10c7bf93..f7488fe0 100644 --- a/externals/grill/flext/source/fldefs.h +++ b/externals/grill/flext/source/fldefs.h @@ -413,7 +413,7 @@ FLEXT_CALLBACK_1(M_FUN,t_symptr) #define FLEXT_THREAD(M_FUN) \ static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c) { \ thr_params *p = new thr_params(c); \ - return StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ + return c->StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ } \ static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ thisType *th = FLEXT_CAST<thisType *>(p->cl); \ @@ -430,7 +430,7 @@ static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ #define FLEXT_THREAD_A(M_FUN) \ static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,t_symbol *s,int argc,t_atom *argv) { \ thr_params *p = new thr_params(c); p->set_any(s,argc,argv); \ - return StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ + return c->StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ } \ static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ thisType *th = FLEXT_CAST<thisType *>(p->cl); \ @@ -449,7 +449,7 @@ static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ #define FLEXT_THREAD_V(M_FUN) \ static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,int argc,t_atom *argv) { \ thr_params *p = new thr_params(c); p->set_list(argc,argv); \ - return StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ + return c->StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ } \ static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ thisType *th = FLEXT_CAST<thisType *>(p->cl); \ @@ -470,7 +470,7 @@ static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ #define FLEXT_THREAD_X(M_FUN) \ static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,void *data) { \ thr_params *p = new thr_params(c); p->var[0]._ext.data = data; \ - return StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ + return c->StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ } \ static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ thisType *th = FLEXT_CAST<thisType *>(p->cl); \ @@ -489,7 +489,7 @@ static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ #define FLEXT_THREAD_B(M_FUN) \ static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,int &arg1) { \ thr_params *p = new thr_params(c); p->var[0]._bool = arg1 != 0; \ - return StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ + return c->StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ } \ static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ thisType *th = FLEXT_CAST<thisType *>(p->cl); \ @@ -508,7 +508,7 @@ static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,TP1 &arg1) { \ thr_params *p = new thr_params(c,1); \ p->var[0]._ ## TP1 = arg1; \ - return StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ + return c->StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ } \ static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ thisType *th = FLEXT_CAST<thisType *>(p->cl); \ @@ -528,7 +528,7 @@ static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,TP1 &arg1,TP2 &arg2) { \ thr_params *p = new thr_params(c,2); \ p->var[0]._ ## TP1 = arg1; \ p->var[1]._ ## TP2 = arg2; \ - return StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ + return c->StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ } \ static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ thisType *th = FLEXT_CAST<thisType *>(p->cl); \ @@ -550,7 +550,7 @@ static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,TP1 &arg1,TP2 &arg2,TP3 &arg3) { p->var[0]._ ## TP1 = arg1; \ p->var[1]._ ## TP2 = arg2; \ p->var[2]._ ## TP3 = arg3; \ - return StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ + return c->StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ } \ static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ thisType *th = FLEXT_CAST<thisType *>(p->cl); \ @@ -574,7 +574,7 @@ static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,TP1 &arg1,TP2 &arg2,TP3 &arg3,TP p->var[1]._ ## TP2 = arg2; \ p->var[2]._ ## TP3 = arg3; \ p->var[3]._ ## TP4 = arg4; \ - return StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ + return c->StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ } \ static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ thisType *th = FLEXT_CAST<thisType *>(p->cl); \ @@ -600,7 +600,7 @@ static bool FLEXT_CALL_PRE(M_FUN)(flext_base *c,TP1 &arg1,TP2 &arg2,TP3 &arg3,TP p->var[2]._ ## TP3 = arg3; \ p->var[3]._ ## TP4 = arg4; \ p->var[4]._ ## TP5 = arg5; \ - return StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ + return c->StartThread(FLEXT_THR_PRE(M_FUN),p,#M_FUN); \ } \ static void *FLEXT_THR_PRE(M_FUN)(thr_params *p) { \ thisType *th = FLEXT_CAST<thisType *>(p->cl); \ diff --git a/externals/grill/flext/source/flext.cpp b/externals/grill/flext/source/flext.cpp index dedf7c49..d0fdb766 100644 --- a/externals/grill/flext/source/flext.cpp +++ b/externals/grill/flext/source/flext.cpp @@ -130,10 +130,8 @@ flext_base::flext_base(): LOG1("%s - flext logging is on",thisName()); #ifdef FLEXT_THREADS - thrid = pthread_self(); - shouldexit = false; - thrhead = thrtail = NULL; +// thrhead = thrtail = NULL; #endif qhead = qtail = NULL; qclk = (t_qelem *)(qelem_new(this,(t_method)QTick)); @@ -147,26 +145,7 @@ flext_base::flext_base(): flext_base::~flext_base() { #ifdef FLEXT_THREADS - // wait for thread termination - shouldexit = true; - for(int wi = 0; thrhead && wi < 100; ++wi) Sleep(0.01f); - -//#ifdef _POSIX_THREADS - qmutex.Lock(); // Lock message queue - tlmutex.Lock(); - // timeout -> hard termination - while(thrhead) { - thr_entry *t = thrhead; - if(pthread_cancel(t->thrid)) post("%s - Thread could not be terminated!",thisName()); - thrhead = t->nxt; - t->nxt = NULL; delete t; - } - tlmutex.Unlock(); - qmutex.Unlock(); -//#else -//#pragma message ("No tread cancelling") -//#endif - + TermThreads(); #endif // send remaining pending messages @@ -482,6 +461,12 @@ void flext_base::Setup(t_class *c) ADD_IN_FT(7); ADD_IN_FT(8); ADD_IN_FT(9); + +#ifdef FLEXT_THREADS + thrid = pthread_self(); + + StartHelper(); +#endif } void flext_base::cb_help(t_class *c) { thisObject(c)->m_help(); } diff --git a/externals/grill/flext/source/flthr.cpp b/externals/grill/flext/source/flthr.cpp index f23eb38f..97da5584 100644 --- a/externals/grill/flext/source/flthr.cpp +++ b/externals/grill/flext/source/flthr.cpp @@ -23,16 +23,146 @@ WARRANTIES, see the file, "license.txt," in this distribution. #include <errno.h> +//! Thread id of system thread +pthread_t flext_base::thrid; + +//! Thread id of helper thread +pthread_t flext_base::thrhelpid; + +flext_base::thr_entry *flext_base::thrhead = NULL,*flext_base::thrtail = NULL; +flext::ThrMutex flext_base::tlmutex; + +//! Helper thread should terminate +bool thrhelpexit = false; + +flext::ThrCond *thrhelpcond = NULL; + +//! Start helper thread +bool flext_base::StartHelper() +{ + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); + + thrhelpexit = false; + int ret = pthread_create (&thrhelpid,&attr,(void *(*)(void *))ThrHelper,NULL); + if(ret) { + error((char *)("flext - Could not launch helper thread!")); + return false; + } + else + return true; +} + +#if 0 +/*! \brief Stop helper thread + \note not called! +*/ +bool flext_base::StopHelper() +{ + thrhelpexit = true; + if(thrhelpcond) thrhelpcond->Signal(); +} +#endif + +//! Static helper thread function +void flext_base::ThrHelper(void *) +{ + // set prototype thread attributes + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); + + // set thread priority one point below normal + // so thread construction won't disturb real-time audio + sched_param parm; + int policy; + pthread_getschedparam(thrhelpid,&policy,&parm); + int prio = parm.sched_priority; + int schmin = sched_get_priority_min(policy); + if(prio > schmin) { + parm.sched_priority = prio-1; + pthread_setschedparam(thrhelpid,policy,&parm); + } + + thrhelpcond = new ThrCond; + + // helper loop + for(;;) { + thrhelpcond->Wait(); + if(thrhelpexit) break; + + tlmutex.Lock(); + + // start all inactive threads in queue + thr_entry *prv = NULL,*ti; + for(ti = thrhead; ti; prv = ti,ti = ti->nxt) { + if(!ti->active) { + int ret = pthread_create (&ti->thrid,&attr,(void *(*)(void *))ti->meth,ti->params); + if(ret) { + error((char *)("flext - Could not launch thread!")); + + // delete from queue + if(prv) + prv->nxt = ti->nxt; + else + thrhead = ti->nxt; + if(thrtail == ti) thrtail = prv; + + ti->nxt = NULL; + delete ti; + } + else { + // set active flag + ti->active = true; + } + } + } + + tlmutex.Unlock(); + } + + delete thrhelpcond; + thrhelpcond = NULL; +} + + +bool flext_base::StartThread(void *(*meth)(thr_params *p),thr_params *p,char *methname) +{ +#ifdef FLEXT_DEBUG + if(!p || !thrhelpcond) { + ERRINTERNAL(); + return false; + } +#endif + + tlmutex.Lock(); + + // make an entry into thread list + thr_entry *nt = new thr_entry(this,meth,p); + if(thrtail) thrtail->nxt = nt; + else thrhead = nt; + thrtail = nt; + + // signal thread helper + thrhelpcond->Signal(); + + tlmutex.Unlock(); + return true; +} + +/* bool flext_base::StartThread(void *(*meth)(thr_params *p),thr_params *p,char *methname) { - static bool init = false; - static pthread_attr_t attr; #ifdef FLEXT_DEBUG if(!p) { ERRINTERNAL(); return false; } #endif + + static bool init = false; + static pthread_attr_t attr; if(!init) { pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); @@ -62,8 +192,9 @@ bool flext_base::StartThread(void *(*meth)(thr_params *p),thr_params *p,char *me if(ret) { #ifdef FLEXT_DEBUG error((char *)(ret == EAGAIN?"%s - Unsufficient resources to launch thread!":"%s - Could not launch method!"),methname); -#endif +#else error((char *)("%s - Could not launch method!"),methname); +#endif delete p; return false; @@ -71,6 +202,7 @@ bool flext_base::StartThread(void *(*meth)(thr_params *p),thr_params *p,char *me else return true; } +*/ bool flext_base::PushThread() { @@ -78,12 +210,13 @@ bool flext_base::PushThread() // post("Push thread"); +/* // make an entry into thread list thr_entry *nt = new thr_entry; if(thrtail) thrtail->nxt = nt; else thrhead = nt; thrtail = nt; - +*/ { #if FLEXT_OS == FLEXT_OS_WIN // set detached thread to lower priority class @@ -151,6 +284,29 @@ void flext_base::PopThread() tlmutex.Unlock(); } +void flext_base::TermThreads() +{ + // wait for thread termination + shouldexit = true; + for(int wi = 0; thrhead && wi < 100; ++wi) Sleep(0.01f); + + qmutex.Lock(); // Lock message queue + tlmutex.Lock(); + + // timeout -> hard termination + for(thr_entry *t = thrhead; t; ) + if(t->th == this) { + if(pthread_cancel(t->thrid)) post("%s - Thread could not be terminated!",thisName()); + thr_entry *tn = t->nxt; + t->nxt = NULL; delete t; + t = tn; + } + else t = t->nxt; + + tlmutex.Unlock(); + qmutex.Unlock(); +} + flext_base::thrid_t flext_base::GetThreadId() { return pthread_self(); |