diff options
Diffstat (limited to 'externals/grill/flext/source/flthr.cpp')
-rw-r--r-- | externals/grill/flext/source/flthr.cpp | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/externals/grill/flext/source/flthr.cpp b/externals/grill/flext/source/flthr.cpp new file mode 100644 index 00000000..fd780a1c --- /dev/null +++ b/externals/grill/flext/source/flthr.cpp @@ -0,0 +1,237 @@ +/* + +flext - C++ layer for Max/MSP and pd (pure data) externals + +Copyright (c) 2001,2002 Thomas Grill (xovo@gmx.net) +For information on usage and redistribution, and for a DISCLAIMER OF ALL +WARRANTIES, see the file, "license.txt," in this distribution. + +*/ + +/*! \file flthr.cpp + \brief Implementation of the flext thread functionality. +*/ + +#ifdef FLEXT_THREADS + +#include "flext.h" +#include "flinternal.h" + +#ifdef MAXMSP +#define SCHEDTICK 1 +#endif + +#ifdef NT +#include <windows.h> +#endif +#include <errno.h> + +bool flext_base::StartThread(void *(*meth)(thr_params *p),thr_params *p,char *methname) +{ + static bool init = false; + static pthread_attr_t attr; +#ifdef _DEBUG + if(!p) { + ERRINTERNAL(); + return false; + } +#endif + if(!init) { + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); + init = true; + } + + // set thread priority one point below normal + // so thread construction won't disturb real-time audio + pthread_t id = pthread_self(); + sched_param parm; + int policy; + pthread_getschedparam(id,&policy,&parm); + int prio = parm.sched_priority; + int schmin = sched_get_priority_min(policy); + if(prio > schmin) { + parm.sched_priority = prio-1; + pthread_setschedparam(id,policy,&parm); + } + + pthread_t thrid; + int ret = pthread_create (&thrid,&attr,(void *(*)(void *))meth,p); + + // set thread priority back to normal + parm.sched_priority = prio; + pthread_setschedparam(id,policy,&parm); + + if(ret) { +#ifdef _DEBUG + error((char *)(ret == EAGAIN?"%s - Unsufficient resources to launch thread!":"%s - Could not launch method!"),methname); +#endif + delete p; + return false; + } + else { +#ifdef MAXMSP + sched_yield(); +#endif + return true; + } +} + +bool flext_base::PushThread() +{ + tlmutex.Lock(); + + // make an entry into thread list + thr_entry *nt = new thr_entry; + if(thrtail) thrtail->nxt = nt; + else thrhead = nt; + thrtail = nt; + + { +#ifdef NT + // set detached thread to lower priority class + DWORD err; + HANDLE thr = GetCurrentThread(); + DWORD cl = GetThreadPriority(thr); + if(!cl && (err = GetLastError())) + post("flext - error getting thread priority"); + else { + BOOL ret = SetThreadPriority(thr,cl-2); + if(!ret) { + err = GetLastError(); + if(!err) post("flext - error setting thread priority"); + } + } +#else + // set initial detached thread priority two points below normal + sched_param parm; + int policy; + if(pthread_getschedparam(nt->thrid,&policy,&parm)) + post("flext - can't get thread parameters"); + int prio = parm.sched_priority; + int schmin = sched_get_priority_min(policy); + if(prio > schmin) { + parm.sched_priority = prio-2; + if(pthread_setschedparam(nt->thrid,policy,&parm)) + post("flext - can't set thread parameters"); + } +#endif + } + + tlmutex.Unlock(); + +#ifdef MAXMSP + clock_delay(yclk,0); +#endif + return true; +} + +void flext_base::PopThread() +{ + tlmutex.Lock(); + + pthread_t id = pthread_self(); + + thr_entry *prv = NULL,*ti; + for(ti = thrhead; ti; prv = ti,ti = ti->nxt) + if(ti->Is()) break; + + if(ti) { + if(prv) + prv->nxt = ti->nxt; + else + thrhead = ti->nxt; + if(thrtail == ti) thrtail = prv; + + ti->nxt = NULL; + delete ti; + } + else { +#ifdef _DEBUG + post("%s - INTERNAL ERROR: Thread not found!",thisName()); +#endif + } + + tlmutex.Unlock(); +} + +#ifdef MAXMSP +void flext_base::YTick(flext_base *th) +{ + clock_delay(th->yclk,0); + qelem_set(th->qclk); + sched_yield(); +} +#endif + +flext_base::thrid_t flext_base::GetThreadId() +{ + return pthread_self(); +} + +bool flext_base::ChangePriority(int dp,thrid_t id) +{ + sched_param parm; + int policy; + if(pthread_getschedparam(id,&policy,&parm) < 0) { +#ifdef _DEBUG + post("flext - failed to get parms"); +#endif + return false; + } + else { + parm.sched_priority += dp; + if(pthread_setschedparam(id,policy,&parm) < 0) { +#ifdef _DEBUG + post("flext - failed to change priority"); +#endif + return false; + } + } + return true; +} + + +int flext_base::GetPriority(thrid_t id) +{ + sched_param parm; + int policy; + if(pthread_getschedparam(id,&policy,&parm) < 0) { +#ifdef _DEBUG + post("flext - failed to get parms"); +#endif + return -1; + } + return parm.sched_priority; +} + + +bool flext_base::SetPriority(int p,thrid_t id) +{ + sched_param parm; + int policy; + if(pthread_getschedparam(id,&policy,&parm) < 0) { +#ifdef _DEBUG + post("flext - failed to get parms"); +#endif + return false; + } + else { + parm.sched_priority = p; + if(pthread_setschedparam(id,policy,&parm) < 0) { +#ifdef _DEBUG + post("flext - failed to change priority"); +#endif + return false; + } + } + return true; +} + +flext_base::thr_params::thr_params(flext_base *c,int n): cl(c),var(new _data[n]) {} +flext_base::thr_params::~thr_params() { if(var) delete[] var; } + +void flext_base::thr_params::set_any(const t_symbol *s,int argc,const t_atom *argv) { var[0]._any.args = new AtomAnything(s,argc,argv); } +void flext_base::thr_params::set_list(int argc,const t_atom *argv) { var[0]._list.args = new AtomList(argc,argv); } + +#endif // FLEXT_THREADS |