aboutsummaryrefslogtreecommitdiff
path: root/externals/grill/flext
diff options
context:
space:
mode:
Diffstat (limited to 'externals/grill/flext')
-rw-r--r--externals/grill/flext/readme.txt2
-rw-r--r--externals/grill/flext/source/flclass.h31
-rw-r--r--externals/grill/flext/source/fldefs.h20
-rw-r--r--externals/grill/flext/source/flext.cpp31
-rw-r--r--externals/grill/flext/source/flthr.cpp164
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();