aboutsummaryrefslogtreecommitdiff
path: root/externals/grill/py/source/main.cpp
diff options
context:
space:
mode:
authorThomas Grill <xovo@users.sourceforge.net>2005-01-09 04:59:30 +0000
committerThomas Grill <xovo@users.sourceforge.net>2005-01-09 04:59:30 +0000
commit53c16e06983f9b03464f41b8c0ed3206382c5538 (patch)
treed5a54d0c089ca1e622bfd605584922ae04580017 /externals/grill/py/source/main.cpp
parent66d28ea3c22decc8cc01d046f05dde113af16c70 (diff)
support for Python threads, at last
small fixes merged in 20041229-newdetach branch. renamed locking functions svn path=/trunk/; revision=2483
Diffstat (limited to 'externals/grill/py/source/main.cpp')
-rw-r--r--externals/grill/py/source/main.cpp232
1 files changed, 202 insertions, 30 deletions
diff --git a/externals/grill/py/source/main.cpp b/externals/grill/py/source/main.cpp
index 657349e7..86b5dd38 100644
--- a/externals/grill/py/source/main.cpp
+++ b/externals/grill/py/source/main.cpp
@@ -2,7 +2,7 @@
py/pyext - python external object for PD and MaxMSP
-Copyright (c)2002-2004 Thomas Grill (gr@grrrr.org)
+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.
@@ -55,13 +55,18 @@ void FreeThreadState()
#endif
-V py::lib_setup()
+void py::lib_setup()
{
post("");
- post("py/pyext %s - python script objects, (C)2002-2004 Thomas Grill",PY__VERSION);
+ 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("");
// -------------------------------------------------------------
@@ -90,11 +95,14 @@ V py::lib_setup()
module_obj = Py_InitModule(PYEXT_MODULE, func_tbl);
module_dict = PyModule_GetDict(module_obj); // borrowed reference
- PyModule_AddStringConstant(module_obj,"__doc__",(C *)py_doc);
+ PyModule_AddStringConstant(module_obj,"__doc__",(char *)py_doc);
// redirect stdout
- PyObject* py_out = Py_InitModule("stdout", StdOut_Methods);
+ 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
// release global lock
@@ -116,23 +124,29 @@ PyObject *py::module_dict = NULL;
py::py():
module(NULL),
- detach(false),shouldexit(false),thrcount(0),
+ detach(0),shouldexit(false),thrcount(0),
stoptick(0)
{
- PY_LOCK
+// interpreter = PyInterpreterState_New();
+
+ PyThreadState *state = PyLock();
Py_INCREF(module_obj);
- PY_UNLOCK
+ PyUnlock(state);
FLEXT_ADDTIMER(stoptmr,tick);
+
+ // launch thread worker
+ FLEXT_CALLMETHOD(threadworker);
}
py::~py()
{
- if(thrcount) {
- shouldexit = true;
-
+ 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((F)(PY_STOP_TICK/1000.));
+ for(int i = 0; i < (PY_STOP_WAIT/PY_STOP_TICK) && thrcount; ++i) Sleep((float)(PY_STOP_TICK/1000.));
// Wait forever
post("%s - Waiting for thread termination!",thisName());
@@ -141,13 +155,19 @@ py::~py()
}
Py_XDECREF(module_obj);
+/*
+ PyEval_AcquireLock();
+ PyInterpreterState_Clear(interpreter);
+ PyInterpreterState_Delete(interpreter);
+ PyEval_ReleaseLock();
+*/
}
void py::GetDir(PyObject *obj,AtomList &lst)
{
if(obj) {
- PY_LOCK
+ PyThreadState *state = PyLock();
PyObject *pvar = PyObject_Dir(obj);
if(!pvar)
@@ -162,7 +182,7 @@ void py::GetDir(PyObject *obj,AtomList &lst)
Py_DECREF(pvar);
}
- PY_UNLOCK
+ PyUnlock(state);
}
}
@@ -174,10 +194,10 @@ void py::m__dir(PyObject *obj)
ToOutAnything(GetOutAttr(),thisTag(),lst.Count(),lst.Atoms());
}
-V py::m__doc(PyObject *obj)
+void py::m__doc(PyObject *obj)
{
if(obj) {
- PY_LOCK
+ PyThreadState *state = PyLock();
PyObject *docf = PyDict_GetItemString(obj,"__doc__"); // borrowed!!!
if(docf && PyString_Check(docf)) {
@@ -206,17 +226,17 @@ V py::m__doc(PyObject *obj)
}
}
- PY_UNLOCK
+ PyUnlock(state);
}
}
-V py::SetArgs(I argc,const t_atom *argv)
+void py::SetArgs(int argc,const t_atom *argv)
{
// script arguments
- C **sargv = new C *[argc+1];
+ char **sargv = new char *[argc+1];
for(int i = 0; i <= argc; ++i) {
- sargv[i] = new C[256];
+ sargv[i] = new char[256];
if(!i)
strcpy(sargv[i],thisName());
else
@@ -230,11 +250,11 @@ V py::SetArgs(I argc,const t_atom *argv)
delete[] sargv;
}
-V py::ImportModule(const C *name)
+void py::ImportModule(const char *name)
{
if(!name) return;
- module = PyImport_ImportModule((C *)name); // increases module_obj ref count by one
+ module = PyImport_ImportModule((char *)name); // increases module_obj ref count by one
if (!module) {
PyErr_Print();
@@ -244,7 +264,7 @@ V py::ImportModule(const C *name)
dict = PyModule_GetDict(module);
}
-V py::UnimportModule()
+void py::UnimportModule()
{
if(!module) return;
@@ -260,7 +280,7 @@ V py::UnimportModule()
dict = NULL;
}
-V py::ReloadModule()
+void py::ReloadModule()
{
if(module) {
PyObject *newmod = PyImport_ReloadModule(module);
@@ -279,13 +299,13 @@ V py::ReloadModule()
post("%s - No module to reload",thisName());
}
-V py::GetModulePath(const C *mod,C *dir,I len)
+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
- C *name;
- I fd = open_via_path("",mod,".py",dir,&name,len,0);
+ char *name;
+ int fd = open_via_path("",mod,".py",dir,&name,len,0);
if(fd > 0) close(fd);
else name = NULL;
@@ -295,10 +315,25 @@ V py::GetModulePath(const C *mod,C *dir,I len)
// how do i get the path in Max/MSP?
short path;
long type;
- char smod[256];
+ char smod[1024];
strcat(strcpy(smod,mod),".py");
- if(!locatefile_extended(smod,&path,&type,&type,-1))
+ 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
*dir = 0;
@@ -307,7 +342,7 @@ V py::GetModulePath(const C *mod,C *dir,I len)
#endif
}
-V py::AddToPath(const C *dir)
+void py::AddToPath(const char *dir)
{
if(dir && *dir) {
PyObject *pobj = PySys_GetObject("path");
@@ -326,6 +361,19 @@ V py::AddToPath(const C *dir)
}
}
+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;
// post to the console
@@ -368,3 +416,127 @@ PyObject* py::StdOut_Write(PyObject* self, PyObject* args)
Py_INCREF(Py_None);
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;
+}