Update of /cvsroot/pure-data/externals/grill/py/source In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7214/source
Modified Files: bound.cpp clmeth.cpp main.cpp main.h modmeth.cpp py.cpp pyargs.cpp pyext.cpp pyext.h register.cpp Log Message: support for Python threads, at last small fixes merged in 20041229-newdetach branch. renamed locking functions
Index: clmeth.cpp =================================================================== RCS file: /cvsroot/pure-data/externals/grill/py/source/clmeth.cpp,v retrieving revision 1.11 retrieving revision 1.12 diff -C2 -d -r1.11 -r1.12 *** clmeth.cpp 17 Dec 2004 05:04:29 -0000 1.11 --- clmeth.cpp 9 Jan 2005 04:59:30 -0000 1.12 *************** *** 3,7 **** py/pyext - python external object for PD and Max/MSP
! Copyright (c) 2002-2004 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. --- 3,7 ---- py/pyext - python external object for PD and Max/MSP
! Copyright (c)2002-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. *************** *** 40,45 ****
! const C *pyext::pyext_doc = ! "py/pyext - python external object for PD and Max/MSP, (C)2002-2004 Thomas Grill\n" "\n" "This is the pyext base class. Available methods:\n" --- 40,45 ----
! const char *pyext::pyext_doc = ! "py/pyext - python external object for PD and Max/MSP, (C)2002-2005 Thomas Grill\n" "\n" "This is the pyext base class. Available methods:\n" *************** *** 82,86 **** }
! BL handled = false; if(PyString_Check(name)) { char* sname = PyString_AsString(name); --- 82,86 ---- }
! bool handled = false; if(PyString_Check(name)) { char* sname = PyString_AsString(name); *************** *** 137,141 **** PyObject *pyext::pyext_outlet(PyObject *,PyObject *args) { ! BL ok = false;
// should always be a tuple! --- 137,141 ---- PyObject *pyext::pyext_outlet(PyObject *,PyObject *args) { ! bool ok = false;
// should always be a tuple! *************** *** 151,158 **** pyext *ext = GetThis(self);
! I sz = PyTuple_Size(args); PyObject *val;
! BL tp = sz == 3 && PySequence_Check( --- 151,158 ---- pyext *ext = GetThis(self);
! int sz = PyTuple_Size(args); PyObject *val;
! bool tp = sz == 3 && PySequence_Check( *************** *** 165,169 **** AtomList *lst = GetPyArgs(val); if(lst) { ! I o = PyInt_AsLong(outl); if(o >= 1 && o <= ext->Outlets()) { // by using the queue there is no immediate call of the next object --- 165,169 ---- AtomList *lst = GetPyArgs(val); if(lst) { ! int o = PyInt_AsLong(outl); if(o >= 1 && o <= ext->Outlets()) { // by using the queue there is no immediate call of the next object *************** *** 226,230 **** else { pyext *ext = GetThis(self); ! I cnt = 0; t_atom at; if(val >= 0) flext::SetInt(at,val); --- 226,230 ---- else { pyext *ext = GetThis(self); ! int cnt = 0; t_atom at; if(val >= 0) flext::SetInt(at,val); *************** *** 256,268 **** FLEXT_ASSERT(PyTuple_Check(args));
! BL ok = false; PyObject *self = PyTuple_GetItem(args,0); // borrowed ref if(self && PyInstance_Check(self)) { pyext *ext = GetThis(self);
! I sz = PySequence_Size(args); PyObject *val;
! BL tp = sz == 2 && PySequence_Check( --- 256,268 ---- FLEXT_ASSERT(PyTuple_Check(args));
! bool ok = false; PyObject *self = PyTuple_GetItem(args,0); // borrowed ref if(self && PyInstance_Check(self)) { pyext *ext = GetThis(self);
! int sz = PySequence_Size(args); PyObject *val;
! bool tp = sz == 2 && PySequence_Check(
Index: pyargs.cpp =================================================================== RCS file: /cvsroot/pure-data/externals/grill/py/source/pyargs.cpp,v retrieving revision 1.9 retrieving revision 1.10 diff -C2 -d -r1.9 -r1.10 *** pyargs.cpp 10 Nov 2004 03:31:34 -0000 1.9 --- pyargs.cpp 9 Jan 2005 04:59:30 -0000 1.10 *************** *** 3,7 **** py/pyext - python external object for PD and MaxMSP
! Copyright (c)2002-2004 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. --- 3,7 ---- py/pyext - python external object for PD and MaxMSP
! Copyright (c)2002-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. *************** *** 22,26 **** } // these following should never happen ! else if(flext::IsFloat(at)) return PyFloat_FromDouble((D)flext::GetFloat(at)); else if(flext::IsInt(at)) return PyInt_FromLong(flext::GetInt(at));
--- 22,26 ---- } // these following should never happen ! else if(flext::IsFloat(at)) return PyFloat_FromDouble((double)flext::GetFloat(at)); else if(flext::IsInt(at)) return PyInt_FromLong(flext::GetInt(at));
*************** *** 28,32 **** }
! PyObject *py::MakePyArgs(const t_symbol *s,int argc,const t_atom *argv,I inlet,BL withself) { PyObject *pArgs; --- 28,32 ---- }
! PyObject *py::MakePyArgs(const t_symbol *s,int argc,const t_atom *argv,int inlet,bool withself) { PyObject *pArgs; *************** *** 41,48 **** */ { ! BL any = IsAnything(s); pArgs = PyTuple_New(argc+(any?1:0)+(inlet >= 0?1:0));
! I pix = 0;
if(inlet >= 0) { --- 41,48 ---- */ { ! bool any = IsAnything(s); pArgs = PyTuple_New(argc+(any?1:0)+(inlet >= 0?1:0));
! int pix = 0;
if(inlet >= 0) { *************** *** 53,57 **** }
! I ix; PyObject *tmp; if(!withself || argc < (any?1:2)) tmp = pArgs,ix = pix; --- 53,57 ---- }
! int ix; PyObject *tmp; if(!withself || argc < (any?1:2)) tmp = pArgs,ix = pix; *************** *** 65,69 **** }
! for(I i = 0; i < argc; ++i) { PyObject *pValue = MakePyAtom(argv[i]); if(!pValue) { --- 65,69 ---- }
! for(int i = 0; i < argc; ++i) { PyObject *pValue = MakePyAtom(argv[i]); if(!pValue) { *************** *** 96,101 **** // analyze return value or tuple
! I rargc = 0; ! BL ok = true; retval tp = nothing;
--- 96,101 ---- // analyze return value or tuple
! int rargc = 0; ! bool ok = true; retval tp = nothing;
*************** *** 117,121 **** ret = new AtomList(rargc);
! for(I ix = 0; ix < rargc; ++ix) { PyObject *arg; if(tp == sequ) --- 117,121 ---- ret = new AtomList(rargc);
! for(int ix = 0; ix < rargc; ++ix) { PyObject *arg; if(tp == sequ) *************** *** 126,130 **** if(PyInt_Check(arg)) SetInt((*ret)[ix],PyInt_AsLong(arg)); else if(PyLong_Check(arg)) SetInt((*ret)[ix],PyLong_AsLong(arg)); ! else if(PyFloat_Check(arg)) SetFloat((*ret)[ix],(F)PyFloat_AsDouble(arg)); else if(PyString_Check(arg)) SetString((*ret)[ix],PyString_AsString(arg)); else if(ix == 0 && self && PyInstance_Check(arg)) { --- 126,130 ---- if(PyInt_Check(arg)) SetInt((*ret)[ix],PyInt_AsLong(arg)); else if(PyLong_Check(arg)) SetInt((*ret)[ix],PyLong_AsLong(arg)); ! else if(PyFloat_Check(arg)) SetFloat((*ret)[ix],(float)PyFloat_AsDouble(arg)); else if(PyString_Check(arg)) SetString((*ret)[ix],PyString_AsString(arg)); else if(ix == 0 && self && PyInstance_Check(arg)) { *************** *** 136,140 **** PyObject *tp = PyObject_Type(arg); PyObject *stp = tp?PyObject_Str(tp):NULL; ! C *tmp = ""; if(stp) tmp = PyString_AsString(stp); post("py/pyext: Could not convert argument %s",tmp); --- 136,140 ---- PyObject *tp = PyObject_Type(arg); PyObject *stp = tp?PyObject_Str(tp):NULL; ! char *tmp = ""; if(stp) tmp = PyString_AsString(stp); post("py/pyext: Could not convert argument %s",tmp);
Index: main.cpp =================================================================== RCS file: /cvsroot/pure-data/externals/grill/py/source/main.cpp,v retrieving revision 1.18 retrieving revision 1.19 diff -C2 -d -r1.18 -r1.19 *** main.cpp 10 Nov 2004 03:31:34 -0000 1.18 --- main.cpp 9 Jan 2005 04:59:30 -0000 1.19 *************** *** 3,7 **** py/pyext - python external object for PD and MaxMSP
! Copyright (c)2002-2004 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. --- 3,7 ---- py/pyext - python external object for PD and MaxMSP
! Copyright (c)2002-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. *************** *** 56,66 ****
! V py::lib_setup() { post(""); ! post("py/pyext %s - python script objects, (C)2002-2004 Thomas Grill",PY__VERSION); #ifdef FLEXT_DEBUG post("DEBUG version compiled on %s %s",__DATE__,__TIME__); #endif post("");
--- 56,71 ----
! void py::lib_setup() { post(""); ! post("--------------------------------------"); ! post("py/pyext %s - python script objects",PY__VERSION); ! post(" (C)2002-2005 Thomas Grill"); ! post(" http://grrrr.org/ext"); #ifdef FLEXT_DEBUG + post(""); post("DEBUG version compiled on %s %s",__DATE__,__TIME__); #endif + post("--------------------------------------"); post("");
*************** *** 91,99 **** module_dict = PyModule_GetDict(module_obj); // borrowed reference
! PyModule_AddStringConstant(module_obj,"__doc__",(C *)py_doc);
// redirect stdout ! PyObject* py_out = Py_InitModule("stdout", StdOut_Methods); PySys_SetObject("stdout", py_out);
#ifdef FLEXT_THREADS --- 96,107 ---- module_dict = PyModule_GetDict(module_obj); // borrowed reference
! PyModule_AddStringConstant(module_obj,"__doc__",(char *)py_doc);
// redirect stdout ! PyObject* py_out; ! py_out = Py_InitModule("stdout", StdOut_Methods); PySys_SetObject("stdout", py_out); + py_out = Py_InitModule("stderr", StdOut_Methods); + PySys_SetObject("stderr", py_out);
#ifdef FLEXT_THREADS *************** *** 117,137 **** py::py(): module(NULL), ! detach(false),shouldexit(false),thrcount(0), stoptick(0) { ! PY_LOCK Py_INCREF(module_obj); ! PY_UNLOCK
FLEXT_ADDTIMER(stoptmr,tick); }
py::~py() { ! if(thrcount) { ! shouldexit = true; ! // Wait for a certain time ! for(int i = 0; i < (PY_STOP_WAIT/PY_STOP_TICK) && thrcount; ++i) Sleep((F)(PY_STOP_TICK/1000.));
// Wait forever --- 125,151 ---- py::py(): module(NULL), ! detach(0),shouldexit(false),thrcount(0), stoptick(0) { ! // interpreter = PyInterpreterState_New(); ! ! PyThreadState *state = PyLock(); Py_INCREF(module_obj); ! PyUnlock(state);
FLEXT_ADDTIMER(stoptmr,tick); + + // launch thread worker + FLEXT_CALLMETHOD(threadworker); }
py::~py() { ! shouldexit = true; ! qucond.Signal(); ! ! if(thrcount) { // Wait for a certain time ! for(int i = 0; i < (PY_STOP_WAIT/PY_STOP_TICK) && thrcount; ++i) Sleep((float)(PY_STOP_TICK/1000.));
// Wait forever *************** *** 142,145 **** --- 156,165 ---- Py_XDECREF(module_obj); + /* + PyEval_AcquireLock(); + PyInterpreterState_Clear(interpreter); + PyInterpreterState_Delete(interpreter); + PyEval_ReleaseLock(); + */ }
*************** *** 148,152 **** { if(obj) { ! PY_LOCK
PyObject *pvar = PyObject_Dir(obj); --- 168,172 ---- { if(obj) { ! PyThreadState *state = PyLock();
PyObject *pvar = PyObject_Dir(obj); *************** *** 163,167 **** }
! PY_UNLOCK } } --- 183,187 ---- }
! PyUnlock(state); } } *************** *** 175,182 **** }
! V py::m__doc(PyObject *obj) { if(obj) { ! PY_LOCK
PyObject *docf = PyDict_GetItemString(obj,"__doc__"); // borrowed!!! --- 195,202 ---- }
! void py::m__doc(PyObject *obj) { if(obj) { ! PyThreadState *state = PyLock();
PyObject *docf = PyDict_GetItemString(obj,"__doc__"); // borrowed!!! *************** *** 207,221 **** }
! PY_UNLOCK } }
! V py::SetArgs(I argc,const t_atom *argv) { // script arguments ! C **sargv = new C *[argc+1]; for(int i = 0; i <= argc; ++i) { ! sargv[i] = new C[256]; if(!i) strcpy(sargv[i],thisName()); --- 227,241 ---- }
! PyUnlock(state); } }
! void py::SetArgs(int argc,const t_atom *argv) { // script arguments ! char **sargv = new char *[argc+1]; for(int i = 0; i <= argc; ++i) { ! sargv[i] = new char[256]; if(!i) strcpy(sargv[i],thisName()); *************** *** 231,239 **** }
! V py::ImportModule(const C *name) { if(!name) return;
! module = PyImport_ImportModule((C *)name); // increases module_obj ref count by one if (!module) {
--- 251,259 ---- }
! void py::ImportModule(const char *name) { if(!name) return;
! module = PyImport_ImportModule((char *)name); // increases module_obj ref count by one if (!module) {
*************** *** 245,249 **** }
! V py::UnimportModule() { if(!module) return; --- 265,269 ---- }
! void py::UnimportModule() { if(!module) return; *************** *** 261,265 **** }
! V py::ReloadModule() { if(module) { --- 281,285 ---- }
! void py::ReloadModule() { if(module) { *************** *** 280,290 **** }
! V py::GetModulePath(const C *mod,C *dir,I len) { #if FLEXT_SYS == FLEXT_SYS_PD // uarghh... pd doesn't show its path for extra modules
! C *name; ! I fd = open_via_path("",mod,".py",dir,&name,len,0); if(fd > 0) close(fd); else name = NULL; --- 300,310 ---- }
! void py::GetModulePath(const char *mod,char *dir,int len) { #if FLEXT_SYS == FLEXT_SYS_PD // uarghh... pd doesn't show its path for extra modules
! char *name; ! int fd = open_via_path("",mod,".py",dir,&name,len,0); if(fd > 0) close(fd); else name = NULL; *************** *** 296,303 **** short path; long type; ! char smod[256]; strcat(strcpy(smod,mod),".py"); ! if(!locatefile_extended(smod,&path,&type,&type,-1)) path_topathname(path,NULL,dir); else // not found --- 316,338 ---- short path; long type; ! char smod[1024]; strcat(strcpy(smod,mod),".py"); ! if(!locatefile_extended(smod,&path,&type,&type,-1)) { ! #if FLEXT_OS == FLEXT_OS_WIN path_topathname(path,NULL,dir); + #else + // convert pathname to unix style + path_topathname(path,NULL,smod); + char *colon = strchr(smod,':'); + if(colon) { + *colon = 0; + strcpy(dir,"/Volumes/"); + strcat(dir,smod); + strcat(dir,colon+1); + } + else + strcpy(dir,smod); + #endif + } else // not found *************** *** 308,312 **** }
! V py::AddToPath(const C *dir) { if(dir && *dir) { --- 343,347 ---- }
! void py::AddToPath(const char *dir) { if(dir && *dir) { *************** *** 327,330 **** --- 362,378 ---- }
+ static const t_symbol *sym_response = flext::MakeSymbol("response"); + + void py::Respond(bool b) + { + if(respond) { + t_atom a; + SetBool(a,b); + ToOutAnything(GetOutAttr(),sym_response,1,&a); + } + } + + + static PyObject *output = NULL;
*************** *** 369,370 **** --- 417,542 ---- return Py_None; } + + + class work_data + { + public: + work_data(PyObject *f,PyObject *a): fun(f),args(a) {} + ~work_data() { Py_DECREF(fun); Py_DECREF(args); } + + PyObject *fun,*args; + }; + + bool py::gencall(PyObject *pmeth,PyObject *pargs) + { + bool ret = false; + + // Now call method + switch(detach) { + case 0: + ret = callpy(pmeth,pargs); + Py_DECREF(pargs); + Py_DECREF(pmeth); + break; + case 1: + // put call into queue + ret = qucall(pmeth,pargs); + break; + case 2: + // each call a new thread + if(!shouldexit) { + ret = FLEXT_CALLMETHOD_X(work_wrapper,new work_data(pmeth,pargs)); + if(!ret) post("%s - Failed to launch thread!",thisName()); + } + break; + default: + FLEXT_ASSERT(false); + } + return ret; + } + + void py::work_wrapper(void *data) + { + FLEXT_ASSERT(data); + + ++thrcount; + + PyThreadState *state = PyLock(); + + // call worker + work_data *w = (work_data *)data; + callpy(w->fun,w->args); + delete w; + + PyUnlock(state); + + --thrcount; + } + + bool py::qucall(PyObject *fun,PyObject *args) + { + if(qufifo.Push(fun,args)) { + qucond.Signal(); + return true; + } + else + return false; + } + + void py::threadworker() + { + PyObject *fun,*args; + PyThreadState *state; + + while(!shouldexit) { + state = PyLock(); + while(qufifo.Pop(fun,args)) { + callpy(fun,args); + Py_XDECREF(fun); + Py_XDECREF(args); + } + PyUnlock(state); + qucond.Wait(); + } + + state = PyLock(); + // unref remaining Python objects + while(qufifo.Pop(fun,args)) { + Py_XDECREF(fun); + Py_XDECREF(args); + } + PyUnlock(state); + } + + Fifo::~Fifo() + { + FifoEl *el = head; + while(el) { + FifoEl *n = el->nxt; + delete el; + el = n; + } + } + + bool Fifo::Push(PyObject *f,PyObject *a) + { + FifoEl *el = new FifoEl; + el->fun = f; + el->args = a; + if(tail) tail->nxt = el; + else head = el; + tail = el; + return true; + } + + bool Fifo::Pop(PyObject *&f,PyObject *&a) + { + if(!head) return false; + FifoEl *el = head; + head = el->nxt; + f = el->fun; + a = el->args; + if(tail == el) tail = NULL; + delete el; + return true; + }
Index: pyext.h =================================================================== RCS file: /cvsroot/pure-data/externals/grill/py/source/pyext.h,v retrieving revision 1.17 retrieving revision 1.18 diff -C2 -d -r1.17 -r1.18 *** pyext.h 10 Nov 2004 03:31:34 -0000 1.17 --- pyext.h 9 Jan 2005 04:59:30 -0000 1.18 *************** *** 3,7 **** py/pyext - python external object for PD and MaxMSP
! Copyright (c)2002-2004 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. --- 3,7 ---- py/pyext - python external object for PD and MaxMSP
! Copyright (c)2002-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. *************** *** 20,24 ****
public: ! pyext(I argc,const t_atom *argv); ~pyext();
--- 20,24 ----
public: ! pyext(int argc,const t_atom *argv); ~pyext();
*************** *** 39,82 **** static PyObject *pyext_isthreaded(PyObject *,PyObject *);
! I Inlets() const { return inlets; } ! I Outlets() const { return outlets; }
protected: ! virtual BL m_method_(I n,const t_symbol *s,I argc,const t_atom *argv);
! BL work(I n,const t_symbol *s,I argc,const t_atom *argv);
! V m_reload(); ! V m_reload_(I argc,const t_atom *argv); ! V ms_args(const AtomList &a) { m_reload_(a.Count(),a.Atoms()); } ! V m_dir_() { m__dir(pyobj); } ! V mg_dir_(AtomList &lst) { GetDir(pyobj,lst); } ! V m_doc_() { m__doc(((PyInstanceObject *)pyobj)->in_class->cl_dict); } ! virtual V m_help();
! V m_get(const t_symbol *s); ! V m_set(I argc,const t_atom *argv);
const t_symbol *methname; PyObject *pyobj; ! I inlets,outlets;
private: ! static V Setup(t_classid);
static pyext *GetThis(PyObject *self); void SetThis();
! V ClearBinding(); ! BL MakeInstance(); ! BL DoInit();
AtomList args;
! virtual V Reload();
static PyObject *class_obj,*class_dict; static PyMethodDef attr_tbl[],meth_tbl[]; ! static const C *pyext_doc;
// -------- bind stuff ------------------ --- 39,82 ---- static PyObject *pyext_isthreaded(PyObject *,PyObject *);
! int Inlets() const { return inlets; } ! int Outlets() const { return outlets; }
protected: ! virtual bool m_method_(int n,const t_symbol *s,int argc,const t_atom *argv);
! bool work(int n,const t_symbol *s,int argc,const t_atom *argv);
! void m_reload(); ! void m_reload_(int argc,const t_atom *argv); ! void ms_args(const AtomList &a) { m_reload_(a.Count(),a.Atoms()); } ! void m_dir_() { m__dir(pyobj); } ! void mg_dir_(AtomList &lst) { GetDir(pyobj,lst); } ! void m_doc_() { m__doc(((PyInstanceObject *)pyobj)->in_class->cl_dict); } ! virtual void m_help();
! void m_get(const t_symbol *s); ! void m_set(int argc,const t_atom *argv);
const t_symbol *methname; PyObject *pyobj; ! int inlets,outlets;
private: ! static void Setup(t_classid);
static pyext *GetThis(PyObject *self); void SetThis();
! void ClearBinding(); ! bool MakeInstance(); ! bool DoInit();
AtomList args;
! virtual void Reload();
static PyObject *class_obj,*class_dict; static PyMethodDef attr_tbl[],meth_tbl[]; ! static const char *pyext_doc;
// -------- bind stuff ------------------ *************** *** 86,107 **** // ---------------------------
! PyObject *call(const C *meth,I inlet,const t_symbol *s,I argc,const t_atom *argv); ! ! V work_wrapper(void *data); ! BL callwork(I n,const t_symbol *s,I argc,const t_atom *argv); ! ! class work_data: ! public flext::AtomAnything ! { ! public: ! work_data(I _n,const t_symbol *_s,I _argc,const t_atom *_argv): n(_n),AtomAnything(_s,_argc,_argv) {} ! I n; ! };
! #ifdef FLEXT_THREADS ! FLEXT_THREAD_X(work_wrapper) ! #else ! FLEXT_CALLBACK_X(work_wrapper) ! #endif
PyThreadState *pythr; --- 86,93 ---- // ---------------------------
! bool call(const char *meth,int inlet,const t_symbol *s,int argc,const t_atom *argv);
! virtual bool callpy(PyObject *fun,PyObject *args); ! static bool stcallpy(PyObject *fun,PyObject *args);
PyThreadState *pythr;
Index: modmeth.cpp =================================================================== RCS file: /cvsroot/pure-data/externals/grill/py/source/modmeth.cpp,v retrieving revision 1.12 retrieving revision 1.13 diff -C2 -d -r1.12 -r1.13 *** modmeth.cpp 10 Nov 2004 03:31:34 -0000 1.12 --- modmeth.cpp 9 Jan 2005 04:59:30 -0000 1.13 *************** *** 3,7 **** py/pyext - python external object for PD and Max/MSP
! Copyright (c) 2002-2004 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. --- 3,7 ---- py/pyext - python external object for PD and Max/MSP
! Copyright (c)2002-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. *************** *** 22,27 **** { "_samplerate", py::py_samplerate, METH_NOARGS,"Get system sample rate" }, { "_blocksize", py::py_blocksize, METH_NOARGS,"Get system block size" }, - { "_inchannels", py::py_inchannels, METH_NOARGS,"Get number of audio in channels" }, - { "_outchannels", py::py_outchannels, METH_NOARGS,"Get number of audio out channels" },
#if FLEXT_SYS == FLEXT_SYS_PD --- 22,25 ---- *************** *** 33,38 **** };
! const C *py::py_doc = ! "py/pyext - python external object for PD and Max/MSP, (C)2002-2004 Thomas Grill\n" "\n" "This is the pyext module. Available function:\n" --- 31,36 ---- };
! const char *py::py_doc = ! "py/pyext - python external object for PD and Max/MSP, (C)2002-2005 Thomas Grill\n" "\n" "This is the pyext module. Available function:\n" *************** *** 43,48 **** "_samplerate(): Get system sample rate\n" "_blocksize(): Get current blocksize\n" - "_inchannels(): Get number of audio in channels\n" - "_outchannels(): Get number of audio out channels\n" "_getvalue(name): Get value of a 'value' object\n" "_setvalue(name,float): Set value of a 'value' object\n" --- 41,44 ---- *************** *** 51,55 ****
! V py::tick(V *) { Lock(); --- 47,51 ----
! void py::tick(void *) { Lock(); *************** *** 74,86 **** }
! V py::m_stop(int argc,const t_atom *argv) { if(thrcount) { Lock();
! I wait = PY_STOP_WAIT; if(argc >= 1 && CanbeInt(argv[0])) wait = GetAInt(argv[0]);
! I ticks = wait/PY_STOP_TICK; if(stoptick) { // already stopping --- 70,82 ---- }
! void py::m_stop(int argc,const t_atom *argv) { if(thrcount) { Lock();
! int wait = PY_STOP_WAIT; if(argc >= 1 && CanbeInt(argv[0])) wait = GetAInt(argv[0]);
! int ticks = wait/PY_STOP_TICK; if(stoptick) { // already stopping *************** *** 107,136 **** }
- PyObject *py::py_inchannels(PyObject *self,PyObject *args) - { - #if FLEXT_SYS == FLEXT_SYS_PD - I ch = sys_get_inchannels(); - #elif FLEXT_SYS == FLEXT_SYS_MAX - I ch = sys_getch(); // not working - #else - #pragma message("Not implemented!") - ch = 0; - #endif - return PyLong_FromLong(ch); - } - - PyObject *py::py_outchannels(PyObject *self,PyObject *args) - { - #if FLEXT_SYS == FLEXT_SYS_PD - I ch = sys_get_outchannels(); - #elif FLEXT_SYS == FLEXT_SYS_MAX - I ch = sys_getch(); // not working - #else - #pragma message("Not implemented!") - ch = 0; - #endif - return PyLong_FromLong(ch); - } - PyObject *py::py_send(PyObject *,PyObject *args) { --- 103,106 ----
Index: bound.cpp =================================================================== RCS file: /cvsroot/pure-data/externals/grill/py/source/bound.cpp,v retrieving revision 1.12 retrieving revision 1.13 diff -C2 -d -r1.12 -r1.13 *** bound.cpp 10 Nov 2004 03:31:34 -0000 1.12 --- bound.cpp 9 Jan 2005 04:59:30 -0000 1.13 *************** *** 3,7 **** py/pyext - python external object for PD and MaxMSP
! Copyright (c) 2002-2004 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. --- 3,7 ---- py/pyext - python external object for PD and MaxMSP
! Copyright (c)2002-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. *************** *** 22,30 **** };
! bool pyext::boundmeth(flext_base *,t_symbol *sym,int argc,t_atom *argv,void *data) { bounddata *obj = (bounddata *)data;
! PY_LOCK
PyObject *args = MakePyArgs(sym,argc,argv,-1,obj->self != NULL); --- 22,31 ---- };
! bool pyext::boundmeth(flext_base *th,t_symbol *sym,int argc,t_atom *argv,void *data) { bounddata *obj = (bounddata *)data; + py *pyth = static_cast<py *>(th);
! PyThreadState *state = pyth->PyLock();
PyObject *args = MakePyArgs(sym,argc,argv,-1,obj->self != NULL); *************** *** 41,45 **** Py_XDECREF(args);
! PY_UNLOCK return true; } --- 42,46 ---- Py_XDECREF(args);
! pyth->PyUnlock(state); return true; } *************** *** 48,52 **** { PyObject *self,*meth; ! C *name; if(!PyArg_ParseTuple(args, "OsO:pyext_bind", &self,&name,&meth)) post("py/pyext - Wrong arguments!"); --- 49,53 ---- { PyObject *self,*meth; ! char *name; if(!PyArg_ParseTuple(args, "OsO:pyext_bind", &self,&name,&meth)) post("py/pyext - Wrong arguments!"); *************** *** 92,96 **** { PyObject *self,*meth; ! C *name; if(!PyArg_ParseTuple(args, "OsO:pyext_bind", &self,&name,&meth)) post("py/pyext - Wrong arguments!"); --- 93,97 ---- { PyObject *self,*meth; ! char *name; if(!PyArg_ParseTuple(args, "OsO:pyext_bind", &self,&name,&meth)) post("py/pyext - Wrong arguments!"); *************** *** 128,132 ****
! V pyext::ClearBinding() { // in case the object couldn't be constructed... --- 129,133 ----
! void pyext::ClearBinding() { // in case the object couldn't be constructed...
Index: register.cpp =================================================================== RCS file: /cvsroot/pure-data/externals/grill/py/source/register.cpp,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** register.cpp 10 Nov 2004 03:31:34 -0000 1.4 --- register.cpp 9 Jan 2005 04:59:30 -0000 1.5 *************** *** 3,7 **** py/pyext - python external object for PD and MaxMSP
! Copyright (c) 2002-2004 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. --- 3,7 ---- py/pyext - python external object for PD and MaxMSP
! Copyright (c)2002-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. *************** *** 12,27 ****
! V py::Register(const C *regnm) { if(module) { // add this to module registry
! PyObject *reg = PyDict_GetItemString(dict,(C *)regnm); // borrowed!!! PyObject *add = Py_BuildValue("[i]",(long)this); if(!reg || !PyList_Check(reg)) { ! if(PyDict_SetItemString(dict,(C *)regnm,add)) { post("%s - Could not set registry",thisName()); } - // Py_XDECREF(reg); } else { --- 12,26 ----
! void py::Register(const char *regnm) { if(module) { // add this to module registry
! PyObject *reg = PyDict_GetItemString(dict,(char *)regnm); // borrowed!!! PyObject *add = Py_BuildValue("[i]",(long)this); if(!reg || !PyList_Check(reg)) { ! if(PyDict_SetItemString(dict,(char *)regnm,add)) { post("%s - Could not set registry",thisName()); } } else { *************** *** 29,48 **** } } - }
! V py::Unregister(const C *regnm) { if(module) { // remove this from module registry ! PyObject *reg = PyDict_GetItemString(dict,(C *)regnm); // borrowed!!! PyObject *add = Py_BuildValue("i",(int)this); if(!reg || !PySequence_Check(reg)) ! post("%s - Registry not found!?",thisName()); else { ! I ix = PySequence_Index(reg,add); if(ix < 0) { ! post("%s - This object not found in registry?!",thisName()); } else { --- 28,46 ---- } } }
! void py::Unregister(const char *regnm) { if(module) { // remove this from module registry ! PyObject *reg = PyDict_GetItemString(dict,(char *)regnm); // borrowed!!! PyObject *add = Py_BuildValue("i",(int)this); if(!reg || !PySequence_Check(reg)) ! post("%s - Internal error: Registry not found!?",thisName()); else { ! int ix = PySequence_Index(reg,add); if(ix < 0) { ! post("%s - Internal error: object not found in registry?!",thisName()); } else { *************** *** 52,73 **** Py_DECREF(add); } - }
! V py::Reregister(const C *regnm) { if(module) { // remove this from module registry ! PyObject *reg = PyDict_GetItemString(dict,(C *)regnm); // borrowed!!!
if(!reg || !PySequence_Check(reg)) ! post("%s - Registry not found!?",thisName()); else { ! I cnt = PySequence_Size(reg); ! for(I i = 0; i < cnt; ++i) { PyObject *it = PySequence_GetItem(reg,i); // new reference if(!it || !PyInt_Check(it)) { ! post("%s - Corrupt registry?!",thisName()); } else { --- 50,70 ---- Py_DECREF(add); } }
! void py::Reregister(const char *regnm) { if(module) { // remove this from module registry ! PyObject *reg = PyDict_GetItemString(dict,(char *)regnm); // borrowed!!!
if(!reg || !PySequence_Check(reg)) ! post("%s - Internal error: Registry not found!?",thisName()); else { ! int cnt = PySequence_Size(reg); ! for(int i = 0; i < cnt; ++i) { PyObject *it = PySequence_GetItem(reg,i); // new reference if(!it || !PyInt_Check(it)) { ! post("%s - Internal error: Corrupt registry?!",thisName()); } else { *************** *** 82,88 **** } } - } - - - --- 79,81 ----
Index: main.h =================================================================== RCS file: /cvsroot/pure-data/externals/grill/py/source/main.h,v retrieving revision 1.25 retrieving revision 1.26 diff -C2 -d -r1.25 -r1.26 *** main.h 17 Dec 2004 05:04:29 -0000 1.25 --- main.h 9 Jan 2005 04:59:30 -0000 1.26 *************** *** 3,7 **** py/pyext - python script object for PD and MaxMSP
! Copyright (c)2002-2004 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. --- 3,7 ---- py/pyext - python script object for PD and MaxMSP
! Copyright (c)2002-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. *************** *** 25,30 **** #endif
! #if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 408) ! #error You need at least flext version 0.4.8 #endif
--- 25,30 ---- #endif
! #if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 500) ! #error You need at least flext version 0.5.0 #endif
*************** *** 39,52 ****
! #define I int ! #define C char ! #define V void ! #define BL bool ! #define F float ! #define D double
! #include "main.h"
class py: --- 39,64 ----
+ class Fifo + { + protected: + struct FifoEl { + PyObject *fun; + PyObject *args; + FifoEl *nxt; + }; + public: + Fifo(): head(NULL),tail(NULL) {} + ~Fifo();
! bool Push(PyObject *f,PyObject *a); ! bool Pop(PyObject *&f,PyObject *&a); ! ! protected: ! FifoEl *head,*tail; ! };
! PyThreadState *FindThreadState(); ! void FreeThreadState();
class py: *************** *** 58,98 **** py(); ~py(); ! static V lib_setup();
! static PyObject *MakePyArgs(const t_symbol *s,int argc,const t_atom *argv,I inlet = -1,BL withself = false); static AtomList *GetPyArgs(PyObject *pValue,PyObject **self = NULL);
protected:
! V m__dir(PyObject *obj); ! V m__doc(PyObject *obj);
! V m_dir() { m__dir(module); } ! V mg_dir(AtomList &lst) { m__dir(module); } ! V m_doc() { m__doc(dict); }
PyObject *module,*dict; // inherited user class module and associated dictionary
! static const C *py_doc;
! V GetDir(PyObject *obj,AtomList &lst);
! V GetModulePath(const C *mod,C *dir,I len); ! V AddToPath(const C *dir); ! V SetArgs(I argc,const t_atom *argv); ! V ImportModule(const C *name); ! V UnimportModule(); ! V ReloadModule();
! V Register(const C *reg); ! V Unregister(const C *reg); ! V Reregister(const C *reg); ! virtual V Reload() = 0;
! V Respond(BL b) { if(respond) { t_atom a[1]; SetBool(a[0],b); ToOutAnything(GetOutAttr(),MakeSymbol("response"),1,a); } }
! static BL IsAnything(const t_symbol *s) { return s && s != sym_bang && s != sym_float && s != sym_int && s != sym_symbol && s != sym_list && s != sym_pointer; }
! enum retval { nothing,atom,sequ /*,tuple,list*/ };
// --- module stuff ----- --- 70,110 ---- py(); ~py(); ! static void lib_setup();
! static PyObject *MakePyArgs(const t_symbol *s,int argc,const t_atom *argv,int inlet = -1,bool withself = false); static AtomList *GetPyArgs(PyObject *pValue,PyObject **self = NULL);
protected:
! void m__dir(PyObject *obj); ! void m__doc(PyObject *obj);
! void m_dir() { m__dir(module); } ! void mg_dir(AtomList &lst) { m__dir(module); } ! void m_doc() { m__doc(dict); }
PyObject *module,*dict; // inherited user class module and associated dictionary
! static const char *py_doc;
! void GetDir(PyObject *obj,AtomList &lst);
! void GetModulePath(const char *mod,char *dir,int len); ! void AddToPath(const char *dir); ! void SetArgs(int argc,const t_atom *argv); ! void ImportModule(const char *name); ! void UnimportModule(); ! void ReloadModule();
! void Register(const char *reg); ! void Unregister(const char *reg); ! void Reregister(const char *reg); ! virtual void Reload() = 0;
! void Respond(bool b);
! static bool IsAnything(const t_symbol *s) { return s && s != sym_bang && s != sym_float && s != sym_int && s != sym_symbol && s != sym_list && s != sym_pointer; }
! enum retval { nothing,atom,sequ };
// --- module stuff ----- *************** *** 109,114 **** static PyObject *py_samplerate(PyObject *,PyObject *args); static PyObject *py_blocksize(PyObject *,PyObject *args); ! static PyObject *py_inchannels(PyObject *,PyObject *args); ! static PyObject *py_outchannels(PyObject *,PyObject *args); #if FLEXT_SYS == FLEXT_SYS_PD static PyObject *py_getvalue(PyObject *,PyObject *args); --- 121,125 ---- static PyObject *py_samplerate(PyObject *,PyObject *args); static PyObject *py_blocksize(PyObject *,PyObject *args); ! #if FLEXT_SYS == FLEXT_SYS_PD static PyObject *py_getvalue(PyObject *,PyObject *args); *************** *** 118,129 **** // ----thread stuff ------------
! virtual V m_stop(int argc,const t_atom *argv);
! BL detach,shouldexit,respond; ! I thrcount; ! I stoptick; Timer stoptmr;
! V tick(V *);
public: --- 129,160 ---- // ----thread stuff ------------
! virtual void m_stop(int argc,const t_atom *argv);
! bool shouldexit,respond; ! int thrcount; ! int stoptick; Timer stoptmr; + int detach;
! void tick(void *); ! ! bool gencall(PyObject *fun,PyObject *args); ! virtual bool callpy(PyObject *fun,PyObject *args) = 0; ! ! private: ! // PyInterpreterState *interpreter; ! ! bool qucall(PyObject *fun,PyObject *args); ! void threadworker(); ! Fifo qufifo; ! ThrCond qucond; ! ! void work_wrapper(void *data); ! ! #ifdef FLEXT_THREADS ! FLEXT_THREAD_X(work_wrapper) ! #else ! FLEXT_CALLBACK_X(work_wrapper) ! #endif
public: *************** *** 131,139 **** #ifdef FLEXT_THREADS ThrMutex mutex; ! inline V Lock() { mutex.Unlock(); } ! inline V Unlock() { mutex.Unlock(); } #else ! inline V Lock() {} ! inline V Unlock() {} #endif
--- 162,185 ---- #ifdef FLEXT_THREADS ThrMutex mutex; ! inline void Lock() { mutex.Unlock(); } ! inline void Unlock() { mutex.Unlock(); } ! ! inline PyThreadState *PyLock() ! { ! PyEval_AcquireLock(); ! return PyThreadState_Swap(FindThreadState()); ! } ! ! inline void PyUnlock(PyThreadState *st) ! { ! PyThreadState_Swap(st); ! PyEval_ReleaseLock(); ! } #else ! inline void Lock() {} ! inline void Unlock() {} ! ! inline PyThreadState *PyLock() { return NULL; } ! inline void PyUnlock(PyThreadState *st) {} #endif
*************** *** 143,147 **** // callbacks
! FLEXT_ATTRVAR_B(detach) FLEXT_ATTRVAR_B(respond) FLEXT_CALLBACK_V(m_stop) --- 189,193 ---- // callbacks
! FLEXT_ATTRVAR_I(detach) FLEXT_ATTRVAR_B(respond) FLEXT_CALLBACK_V(m_stop) *************** *** 150,175 **** FLEXT_CALLBACK(m_doc) FLEXT_CALLBACK_T(tick) - };
! #ifdef FLEXT_THREADS ! ! PyThreadState *FindThreadState(); ! void FreeThreadState(); ! ! #define PY_LOCK \ ! { \ ! PyEval_AcquireLock(); \ ! PyThreadState *__st = FindThreadState(); \ ! PyThreadState *__oldst = PyThreadState_Swap(__st); ! ! #define PY_UNLOCK \ ! PyThreadState_Swap(__oldst); \ ! PyEval_ReleaseLock(); \ ! } ! ! #else ! #define PY_LOCK ! #define PY_UNLOCK ! #endif
#endif --- 196,202 ---- FLEXT_CALLBACK(m_doc) FLEXT_CALLBACK_T(tick)
! FLEXT_THREAD(threadworker) ! };
#endif
Index: pyext.cpp =================================================================== RCS file: /cvsroot/pure-data/externals/grill/py/source/pyext.cpp,v retrieving revision 1.22 retrieving revision 1.23 diff -C2 -d -r1.22 -r1.23 *** pyext.cpp 10 Nov 2004 03:31:34 -0000 1.22 --- pyext.cpp 9 Jan 2005 04:59:30 -0000 1.23 *************** *** 3,7 **** py/pyext - python script object for PD and Max/MSP
! Copyright (c)2002-2004 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. --- 3,7 ---- py/pyext - python script object for PD and Max/MSP
! Copyright (c)2002-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. *************** *** 14,20 **** FLEXT_LIB_V("pyext pyext. pyx pyx.",pyext)
! V pyext::Setup(t_classid c) { ! FLEXT_CADDMETHOD_(c,0,"reload.",m_reload); FLEXT_CADDMETHOD_(c,0,"reload",m_reload_); FLEXT_CADDMETHOD_(c,0,"dir",m_dir); --- 14,25 ---- FLEXT_LIB_V("pyext pyext. pyx pyx.",pyext)
! ! static const t_symbol *sym_get; ! ! void pyext::Setup(t_classid c) { ! sym_get = flext::MakeSymbol("get"); ! ! FLEXT_CADDMETHOD_(c,0,"reload.",m_reload); FLEXT_CADDMETHOD_(c,0,"reload",m_reload_); FLEXT_CADDMETHOD_(c,0,"dir",m_dir); *************** *** 36,40 **** FLEXT_CADDATTR_VAR1(c,"respond",respond);
- // ----------------------------------------------------
--- 41,44 ---- *************** *** 113,117 **** PyObject *pyext::class_dict = NULL;
! pyext::pyext(I argc,const t_atom *argv): pyobj(NULL),pythr(NULL), inlets(-1),outlets(-1), --- 117,121 ---- PyObject *pyext::class_dict = NULL;
! pyext::pyext(int argc,const t_atom *argv): pyobj(NULL),pythr(NULL), inlets(-1),outlets(-1), *************** *** 128,132 **** const t_atom *clname = NULL;
! PY_LOCK
// init script module --- 132,136 ---- const t_atom *clname = NULL;
! PyThreadState *state = PyLock();
// init script module *************** *** 239,243 **** inlets = outlets = 0;
! PY_UNLOCK if(inlets < 0 || outlets < 0) --- 243,247 ---- inlets = outlets = 0;
! PyUnlock(state); if(inlets < 0 || outlets < 0) *************** *** 254,258 **** pyext::~pyext() { ! PY_LOCK
ClearBinding(); --- 258,262 ---- pyext::~pyext() { ! PyThreadState *state = PyLock();
ClearBinding(); *************** *** 266,273 **** UnimportModule();
! PY_UNLOCK }
! BL pyext::DoInit() { SetThis(); --- 270,277 ---- UnimportModule();
! PyUnlock(state); }
! bool pyext::DoInit() { SetThis(); *************** *** 294,303 **** }
! BL pyext::MakeInstance() { // pyobj should already have been decref'd / cleared before getting here!! if(module && methname) { ! PyObject *pref = PyObject_GetAttrString(module,const_cast<C *>(GetString(methname))); if(!pref) PyErr_Print(); --- 298,307 ---- }
! bool pyext::MakeInstance() { // pyobj should already have been decref'd / cleared before getting here!! if(module && methname) { ! PyObject *pref = PyObject_GetAttrString(module,const_cast<char *>(GetString(methname))); if(!pref) PyErr_Print(); *************** *** 320,324 **** }
! V pyext::Reload() { ClearBinding(); --- 324,328 ---- }
! void pyext::Reload() { ClearBinding(); *************** *** 334,340 ****
! V pyext::m_reload() { ! PY_LOCK
Unregister("_pyext"); // self --- 338,344 ----
! void pyext::m_reload() { ! PyThreadState *state = PyLock();
Unregister("_pyext"); // self *************** *** 347,354 **** SetThis();
! PY_UNLOCK }
! V pyext::m_reload_(I argc,const t_atom *argv) { args(argc,argv); --- 351,358 ---- SetThis();
! PyUnlock(state); }
! void pyext::m_reload_(int argc,const t_atom *argv) { args(argc,argv); *************** *** 358,362 **** void pyext::m_get(const t_symbol *s) { ! PY_LOCK
PyObject *pvar = PyObject_GetAttrString(pyobj,const_cast<char *>(GetString(s))); /* fetch bound method */ --- 362,366 ---- void pyext::m_get(const t_symbol *s) { ! PyThreadState *state = PyLock();
PyObject *pvar = PyObject_GetAttrString(pyobj,const_cast<char *>(GetString(s))); /* fetch bound method */ *************** *** 369,373 **** if(lst) { // dump value to attribute outlet ! AtomAnything out("get",lst->Count()+1); SetSymbol(out[0],s); out.Set(lst->Count(),lst->Atoms(),1); --- 373,377 ---- if(lst) { // dump value to attribute outlet ! AtomAnything out(sym_get,lst->Count()+1); SetSymbol(out[0],s); out.Set(lst->Count(),lst->Atoms(),1); *************** *** 381,390 **** }
! PY_UNLOCK }
void pyext::m_set(int argc,const t_atom *argv) { ! PY_LOCK
if(argc < 2 || !IsString(argv[0])) --- 385,394 ---- }
! PyUnlock(state); }
void pyext::m_set(int argc,const t_atom *argv) { ! PyThreadState *state = PyLock();
if(argc < 2 || !IsString(argv[0])) *************** *** 418,430 **** }
! PY_UNLOCK }
! BL pyext::m_method_(I n,const t_symbol *s,I argc,const t_atom *argv) { ! BL ret = false; if(pyobj && n >= 1) ! ret = callwork(n,s,argc,argv); else post("%s - no method for type '%s' into inlet %i",thisName(),GetString(s),n); --- 422,434 ---- }
! PyUnlock(state); }
! bool pyext::m_method_(int n,const t_symbol *s,int argc,const t_atom *argv) { ! bool ret = false; if(pyobj && n >= 1) ! ret = work(n,s,argc,argv); else post("%s - no method for type '%s' into inlet %i",thisName(),GetString(s),n); *************** *** 433,440 ****
! V pyext::m_help() { post(""); ! post("%s %s - python class object, (C)2002-2004 Thomas Grill",thisName(),PY__VERSION); #ifdef FLEXT_DEBUG post("DEBUG VERSION, compiled on " __DATE__ " " __TIME__); --- 437,444 ----
! void pyext::m_help() { post(""); ! post("%s %s - python class object, (C)2002-2005 Thomas Grill",thisName(),PY__VERSION); #ifdef FLEXT_DEBUG post("DEBUG VERSION, compiled on " __DATE__ " " __TIME__); *************** *** 461,469 **** }
! PyObject *pyext::call(const C *meth,I inlet,const t_symbol *s,I argc,const t_atom *argv) { ! PyObject *ret = NULL;
! PyObject *pmeth = PyObject_GetAttrString(pyobj,const_cast<char *>(meth)); /* fetch bound method */ if(pmeth == NULL) { PyErr_Clear(); // no method found --- 465,489 ---- }
! bool pyext::callpy(PyObject *fun,PyObject *args) { ! PyObject *ret = PyObject_Call(fun,args,NULL); ! if(ret == NULL) { ! // function not found resp. arguments not matching ! PyErr_Print(); ! return false; ! } ! else { ! if(!PyObject_Not(ret)) post("pyext - returned value is ignored"); ! Py_DECREF(ret); ! return true; ! } ! }
! ! bool pyext::call(const char *meth,int inlet,const t_symbol *s,int argc,const t_atom *argv) ! { ! bool ret = false; ! ! PyObject *pmeth = PyObject_GetAttrString(pyobj,const_cast<char *>(meth)); /* fetch bound method */ if(pmeth == NULL) { PyErr_Clear(); // no method found *************** *** 471,555 **** else { PyObject *pargs = MakePyArgs(s,argc,argv,inlet?inlet:-1,true); ! if(!pargs) PyErr_Print(); ! else { ! ret = PyEval_CallObject(pmeth, pargs); ! if (ret == NULL) // function not found resp. arguments not matching ! PyErr_Print(); ! ! Py_DECREF(pargs); ! } ! Py_DECREF(pmeth); ! } ! ! return ret; ! } ! ! V pyext::work_wrapper(V *data) ! { ! ++thrcount; ! #ifdef FLEXT_DEBUG ! if(!data) ! post("%s - no data!",thisName()); ! else ! #endif ! { ! #ifdef FLEXT_THREADS ! // --- make new Python thread --- ! // get the global lock ! PyEval_AcquireLock(); ! // create a thread state object for this thread ! PyThreadState *newthr = FindThreadState(); ! // free the lock ! PyEval_ReleaseLock(); ! #endif ! { ! // call worker ! work_data *w = (work_data *)data; ! work(w->n,w->Header(),w->Count(),w->Atoms()); ! delete w; } ! ! #ifdef FLEXT_THREADS ! // --- delete Python thread --- ! // grab the lock ! PyEval_AcquireLock(); ! // swap my thread state out of the interpreter ! PyThreadState_Swap(NULL); ! // delete mapped thread state ! FreeThreadState(); ! // release the lock ! PyEval_ReleaseLock(); ! // ----------------------------- ! #endif ! } ! --thrcount; ! } ! ! BL pyext::callwork(I n,const t_symbol *s,I argc,const t_atom *argv) ! { ! BL ret = true,ok = false; ! if(detach) { ! if(shouldexit) ! post("%s - Stopping.... new threads can't be launched now!",thisName()); ! else { ! ret = FLEXT_CALLMETHOD_X(work_wrapper,new work_data(n,s,argc,argv)); ! if(!ret) post("%s - Failed to launch thread!",thisName()); ! } } ! else ! ret = ok = work(n,s,argc,argv); ! Respond(ok); ! return ret; }
! BL pyext::work(I n,const t_symbol *s,I argc,const t_atom *argv) { ! BL retv = false;
! PY_LOCK
! PyObject *ret = NULL; ! char *str = new char[strlen(GetString(s))+10];
{ --- 491,512 ---- else { PyObject *pargs = MakePyArgs(s,argc,argv,inlet?inlet:-1,true); ! if(!pargs) { PyErr_Print(); ! Py_DECREF(pmeth); } ! else ! ret = gencall(pmeth,pargs); } ! return ret; }
! bool pyext::work(int n,const t_symbol *s,int argc,const t_atom *argv) { ! bool ret = false;
! PyThreadState *state = PyLock();
! // should be enough... ! char str[256];
{ *************** *** 564,568 **** if(s == sym_bang && !argc) { t_atom argv; ! SetString(argv,""); ret = call(str,0,s,1,&argv); } --- 521,525 ---- if(s == sym_bang && !argc) { t_atom argv; ! SetSymbol(argv,sym__); ret = call(str,0,s,1,&argv); } *************** *** 577,588 **** if(!ret) { // try anything at any inlet ! strcpy(str,"_anything_"); if(s == sym_bang && !argc) { t_atom argv; ! SetString(argv,""); ! ret = call(str,n,s,1,&argv); } else ! ret = call(str,n,s,argc,argv); }
--- 534,545 ---- if(!ret) { // try anything at any inlet ! const char *str1 = "_anything_"; if(s == sym_bang && !argc) { t_atom argv; ! SetSymbol(argv,sym__); ! ret = call(str1,n,s,1,&argv); } else ! ret = call(str1,n,s,argc,argv); }
*************** *** 591,604 **** post("%s - no matching method found for '%s' into inlet %i",thisName(),GetString(s),n);
! if(str) delete[] str; ! ! if(ret) { ! if(!PyObject_Not(ret)) post("%s - returned value is ignored",thisName()); ! Py_DECREF(ret); ! retv = true; ! } ! ! PY_UNLOCK
! return retv; } --- 548,554 ---- post("%s - no matching method found for '%s' into inlet %i",thisName(),GetString(s),n);
! PyUnlock(state);
! Respond(ret); ! return ret; }
Index: py.cpp =================================================================== RCS file: /cvsroot/pure-data/externals/grill/py/source/py.cpp,v retrieving revision 1.15 retrieving revision 1.16 diff -C2 -d -r1.15 -r1.16 *** py.cpp 10 Nov 2004 03:31:34 -0000 1.15 --- py.cpp 9 Jan 2005 04:59:30 -0000 1.16 *************** *** 3,7 **** py/pyext - python script object for PD and Max/MSP
! Copyright (c)2002-2004 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. --- 3,7 ---- py/pyext - python script object for PD and Max/MSP
! Copyright (c)2002-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. *************** *** 18,55 ****
public: ! pyobj(I argc,const t_atom *argv); ~pyobj();
protected: ! BL m_method_(I n,const t_symbol *s,I argc,const t_atom *argv);
! BL work(const t_symbol *s,I argc,const t_atom *argv);
! V m_bang() { callwork(sym_bang,0,NULL); } ! V m_reload(); ! V m_reload_(I argc,const t_atom *argv); ! V m_set(I argc,const t_atom *argv); ! V m_dir_() { m__dir(function); } ! V m_doc_() { m__doc(function); }
! virtual V m_help();
// methods for python arguments ! V callwork(const t_symbol *s,I argc,const t_atom *argv); ! V m_py_list(I argc,const t_atom *argv) { callwork(sym_list,argc,argv); } ! V m_py_float(I argc,const t_atom *argv) { callwork(sym_float,argc,argv); } ! V m_py_int(I argc,const t_atom *argv) { callwork(sym_int,argc,argv); } ! V m_py_any(const t_symbol *s,I argc,const t_atom *argv) { callwork(s,argc,argv); }
const t_symbol *funname; PyObject *function;
! virtual V Reload();
! V SetFunction(const C *func); ! V ResetFunction();
private: static void Setup(t_classid c);
--- 18,58 ----
public: ! pyobj(int argc,const t_atom *argv); ~pyobj();
protected: ! bool m_method_(int n,const t_symbol *s,int argc,const t_atom *argv);
! bool work(const t_symbol *s,int argc,const t_atom *argv);
! void m_bang() { callwork(sym_bang,0,NULL); } ! void m_reload(); ! void m_reload_(int argc,const t_atom *argv); ! void m_set(int argc,const t_atom *argv); ! void m_dir_() { m__dir(function); } ! void m_doc_() { m__doc(function); }
! virtual void m_help();
// methods for python arguments ! void callwork(const t_symbol *s,int argc,const t_atom *argv); ! void m_py_list(int argc,const t_atom *argv) { callwork(sym_list,argc,argv); } ! void m_py_float(int argc,const t_atom *argv) { callwork(sym_float,argc,argv); } ! void m_py_int(int argc,const t_atom *argv) { callwork(sym_int,argc,argv); } ! void m_py_any(const t_symbol *s,int argc,const t_atom *argv) { callwork(s,argc,argv); }
const t_symbol *funname; PyObject *function;
! virtual void Reload();
! void SetFunction(const char *func); ! void ResetFunction();
private: + + virtual bool callpy(PyObject *fun,PyObject *args); + static void Setup(t_classid c);
*************** *** 99,106 **** }
! pyobj::pyobj(I argc,const t_atom *argv): function(NULL),funname(NULL) { ! PY_LOCK
AddInAnything(2); --- 102,109 ---- }
! pyobj::pyobj(int argc,const t_atom *argv): function(NULL),funname(NULL) { ! PyThreadState *state = PyLock();
AddInAnything(2); *************** *** 117,121 **** post("%s - script name argument is invalid",thisName()); else { ! C dir[1024]; GetModulePath(GetString(argv[0]),dir,sizeof(dir)); // set script path --- 120,124 ---- post("%s - script name argument is invalid",thisName()); else { ! char dir[1024]; GetModulePath(GetString(argv[0]),dir,sizeof(dir)); // set script path *************** *** 128,137 **** AddToPath(GetString(canvas_getcurrentdir())); #elif FLEXT_SYS == FLEXT_SYS_MAX ! #if FLEXT_OS == FLEXT_OS_WIN ! #else short path = patcher_myvol(thisCanvas()); path_topathname(path,NULL,dir); AddToPath(dir); ! #endif #else #pragma message("Adding current dir to path is not implemented") --- 131,139 ---- AddToPath(GetString(canvas_getcurrentdir())); #elif FLEXT_SYS == FLEXT_SYS_MAX ! /* short path = patcher_myvol(thisCanvas()); path_topathname(path,NULL,dir); AddToPath(dir); ! */ #else #pragma message("Adding current dir to path is not implemented") *************** *** 154,165 **** }
! PY_UNLOCK }
pyobj::~pyobj() { ! PY_LOCK Unregister("_py"); ! PY_UNLOCK }
--- 156,167 ---- }
! PyUnlock(state); }
pyobj::~pyobj() { ! PyThreadState *state = PyLock(); Unregister("_py"); ! PyUnlock(state); }
*************** *** 167,171 ****
! BL pyobj::m_method_(I n,const t_symbol *s,I argc,const t_atom *argv) { if(n == 1) --- 169,173 ----
! bool pyobj::m_method_(int n,const t_symbol *s,int argc,const t_atom *argv) { if(n == 1) *************** *** 174,180 **** }
! V pyobj::m_reload() { ! PY_LOCK
Unregister("_py"); --- 176,182 ---- }
! void pyobj::m_reload() { ! PyThreadState *state = PyLock();
Unregister("_py"); *************** *** 185,205 **** SetFunction(funname?GetString(funname):NULL);
! PY_UNLOCK }
! V pyobj::m_reload_(I argc,const t_atom *argv) { ! PY_LOCK SetArgs(argc,argv); ! PY_UNLOCK
m_reload(); }
! V pyobj::m_set(I argc,const t_atom *argv) { ! PY_LOCK
! I ix = 0; if(argc >= 2) { if(!IsString(argv[ix])) { --- 187,207 ---- SetFunction(funname?GetString(funname):NULL);
! PyUnlock(state); }
! void pyobj::m_reload_(int argc,const t_atom *argv) { ! PyThreadState *state = PyLock(); SetArgs(argc,argv); ! PyUnlock(state);
m_reload(); }
! void pyobj::m_set(int argc,const t_atom *argv) { ! PyThreadState *state = PyLock();
! int ix = 0; if(argc >= 2) { if(!IsString(argv[ix])) { *************** *** 207,211 **** return; } ! const C *sn = GetString(argv[ix]);
if(!module || !strcmp(sn,PyModule_GetName(module))) { --- 209,213 ---- return; } ! const char *sn = GetString(argv[ix]);
if(!module || !strcmp(sn,PyModule_GetName(module))) { *************** *** 222,232 **** SetFunction(GetString(argv[ix]));
! PY_UNLOCK }
! V pyobj::m_help() { post(""); ! post("%s %s - python script object, (C)2002-2004 Thomas Grill",thisName(),PY__VERSION); #ifdef FLEXT_DEBUG post("DEBUG VERSION, compiled on " __DATE__ " " __TIME__); --- 224,234 ---- SetFunction(GetString(argv[ix]));
! PyUnlock(state); }
! void pyobj::m_help() { post(""); ! post("%s %s - python script object, (C)2002-2005 Thomas Grill",thisName(),PY__VERSION); #ifdef FLEXT_DEBUG post("DEBUG VERSION, compiled on " __DATE__ " " __TIME__); *************** *** 249,253 **** post("\tdir+: dump function dictionary"); #ifdef FLEXT_THREADS ! post("\tdetach 0/1: detach threads"); post("\tstop {wait time (ms)}: stop threads"); #endif --- 251,255 ---- post("\tdir+: dump function dictionary"); #ifdef FLEXT_THREADS ! post("\tdetach 0/1/2: detach threads"); post("\tstop {wait time (ms)}: stop threads"); #endif *************** *** 255,259 **** }
! V pyobj::ResetFunction() { if(!module || !dict) --- 257,261 ---- }
! void pyobj::ResetFunction() { if(!module || !dict) *************** *** 264,268 **** }
! function = funname?PyDict_GetItemString(dict,(C *)GetString(funname)):NULL; // borrowed!!! if(!function) { PyErr_Clear(); --- 266,270 ---- }
! function = funname?PyDict_GetItemString(dict,(char *)GetString(funname)):NULL; // borrowed!!! if(!function) { PyErr_Clear(); *************** *** 275,279 **** }
! V pyobj::SetFunction(const C *func) { if(func) { --- 277,281 ---- }
! void pyobj::SetFunction(const char *func) { if(func) { *************** *** 286,314 ****
! V pyobj::Reload() { ResetFunction(); }
! ! BL pyobj::work(const t_symbol *s,I argc,const t_atom *argv) { ! AtomList *rargs = NULL; ! BL ret; ! ! ++thrcount; ! PY_LOCK
if(function) { ! PyObject *pArgs = MakePyArgs(s,argc,argv); ! PyObject *pValue = PyObject_CallObject(function, pArgs); ! ! rargs = GetPyArgs(pValue); ! if(!rargs) PyErr_Print();
! Py_XDECREF(pArgs); ! Py_XDECREF(pValue); ! ret = true; ! } else { post("%s: no function defined",thisName()); --- 288,332 ----
! void pyobj::Reload() { ResetFunction(); }
! bool pyobj::callpy(PyObject *fun,PyObject *args) { ! PyObject *ret = PyObject_Call(fun,args,NULL); ! if(ret == NULL) { ! // function not found resp. arguments not matching ! PyErr_Print(); ! return false; ! } ! else { ! AtomList *rargs = GetPyArgs(ret); ! if(!rargs) ! PyErr_Print(); ! else { ! // call to outlet _outside_ the Mutex lock! ! // otherwise (if not detached) deadlock will occur ! if(rargs->Count()) ToOutList(0,*rargs); ! delete rargs; ! } ! Py_DECREF(ret); ! return true; ! } ! }
+ void pyobj::callwork(const t_symbol *s,int argc,const t_atom *argv) + { + bool ret = false; + if(function) { ! PyThreadState *state = PyLock(); ! ! PyObject *pargs = MakePyArgs(s,argc,argv); ! Py_INCREF(function); ! ret = gencall(function,pargs);
! PyUnlock(state); ! } else { post("%s: no function defined",thisName()); *************** *** 316,347 **** }
- PY_UNLOCK - --thrcount; - - if(rargs) { - // call to outlet _outside_ the Mutex lock! - // otherwise (if not detached) deadlock will occur - if(rargs->Count()) ToOutList(0,*rargs); - delete rargs; - } - - return ret; - } - - V pyobj::callwork(const t_symbol *s,I argc,const t_atom *argv) - { - BL ret = false; - if(detach) { - if(shouldexit) - post("%s - New threads can't be launched now!",thisName()); - else { - ret = FLEXT_CALLMETHOD_A(work,s,argc,argv); - if(!ret) post("%s - Failed to launch thread!",thisName()); - } - } - else - ret = work(s,argc,argv); Respond(ret); } - - --- 334,337 ----