aboutsummaryrefslogtreecommitdiff
path: root/externals/grill/py
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
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')
-rw-r--r--externals/grill/py/license.txt2
-rw-r--r--externals/grill/py/package.txt4
-rw-r--r--externals/grill/py/pd/thread-1.pd47
-rw-r--r--externals/grill/py/py.vcproj2
-rw-r--r--externals/grill/py/readme.txt53
-rw-r--r--externals/grill/py/source/bound.cpp15
-rw-r--r--externals/grill/py/source/clmeth.cpp24
-rw-r--r--externals/grill/py/source/main.cpp232
-rw-r--r--externals/grill/py/source/main.h157
-rw-r--r--externals/grill/py/source/modmeth.cpp44
-rw-r--r--externals/grill/py/source/py.cpp174
-rw-r--r--externals/grill/py/source/pyargs.cpp24
-rw-r--r--externals/grill/py/source/pyext.cpp186
-rw-r--r--externals/grill/py/source/pyext.h64
-rw-r--r--externals/grill/py/source/register.cpp37
15 files changed, 564 insertions, 501 deletions
diff --git a/externals/grill/py/license.txt b/externals/grill/py/license.txt
index 7de52136..8d768d93 100644
--- a/externals/grill/py/license.txt
+++ b/externals/grill/py/license.txt
@@ -28,7 +28,7 @@ This package uses the flext C++ layer - See its license text below:
--- flext ----------------------------------------------
flext - C++ layer for Max/MSP and pd (pure data) externals
-Copyright (C) 2001-2003 Thomas Grill
+Copyright (C) 2001-2005 Thomas Grill
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/externals/grill/py/package.txt b/externals/grill/py/package.txt
index 5603e6eb..03c6fa9d 100644
--- a/externals/grill/py/package.txt
+++ b/externals/grill/py/package.txt
@@ -1,9 +1,7 @@
NAME=py
-BUILDTYPE=multi
-
+BUILDTYPE=multi
BUILDDIR=build
-
SRCDIR=source
diff --git a/externals/grill/py/pd/thread-1.pd b/externals/grill/py/pd/thread-1.pd
index b2daa5f0..e46f6521 100644
--- a/externals/grill/py/pd/thread-1.pd
+++ b/externals/grill/py/pd/thread-1.pd
@@ -1,11 +1,11 @@
-#N canvas 135 178 644 401 12;
+#N canvas 135 178 648 405 12;
#X msg 35 292 help;
#X msg 34 317 doc;
#X msg 70 318 doc+;
#X floatatom 142 340 5 0 0 0 - - -;
#X text 17 66 This demonstrates threading. See the threads.py file.
;
-#X obj 137 243 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+#X obj 137 243 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1
1;
#X msg 137 263 detach \$1;
#X floatatom 250 341 5 0 0 0 - - -;
@@ -19,31 +19,42 @@
#X obj 157 208 0;
#X text 84 114 without threads;
#X text 248 112 with threads;
-#X text 249 129 non-blocking;
#X text 175 362 watch that!;
-#X msg 411 154 stop;
-#X text 381 133 you can even stop it;
+#X msg 421 264 stop;
+#X text 391 243 you can even stop it;
#X obj 142 306 pyext threads ex1;
#X text 90 128 - blocking!! -;
#X obj 16 13 cnv 15 600 40 empty empty py/pyext 10 22 0 24 -260818
-1 0;
-#X text 213 32 http://www.parasitaere-kapazitaeten.net;
-#X text 213 16 Python script objects \, (C)2003-2004 Thomas Grill;
-#X connect 0 0 20 0;
-#X connect 1 0 20 0;
-#X connect 2 0 20 0;
+#X obj 407 150 bng 15 250 50 0 empty empty empty 0 -6 0 8 -258699 -1
+-1;
+#X obj 407 177 t b b b;
+#X text 383 112 with threads;
+#X text 249 129 non-blocking;
+#X text 384 129 parallel;
+#X obj 445 205 2;
+#X text 213 32 http://grrrr.org/ext;
+#X text 213 16 Python script objects \, (C)2003-2005 Thomas Grill;
+#X connect 0 0 19 0;
+#X connect 1 0 19 0;
+#X connect 2 0 19 0;
#X connect 5 0 6 0;
-#X connect 6 0 20 0;
+#X connect 6 0 19 0;
#X connect 8 0 11 0;
#X connect 9 0 10 0;
-#X connect 10 0 20 1;
-#X connect 10 1 20 2;
+#X connect 10 0 19 1;
+#X connect 10 1 19 2;
#X connect 10 2 13 0;
-#X connect 11 0 20 1;
-#X connect 11 1 20 2;
+#X connect 11 0 19 1;
+#X connect 11 1 19 2;
#X connect 11 2 12 0;
#X connect 12 0 5 0;
#X connect 13 0 5 0;
-#X connect 18 0 20 0;
-#X connect 20 0 3 0;
-#X connect 20 1 7 0;
+#X connect 17 0 19 0;
+#X connect 19 0 3 0;
+#X connect 19 1 7 0;
+#X connect 22 0 23 0;
+#X connect 23 0 19 1;
+#X connect 23 1 19 2;
+#X connect 23 2 27 0;
+#X connect 27 0 5 0;
diff --git a/externals/grill/py/py.vcproj b/externals/grill/py/py.vcproj
index 1b04f084..c108f9a7 100644
--- a/externals/grill/py/py.vcproj
+++ b/externals/grill/py/py.vcproj
@@ -85,7 +85,7 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
- AdditionalIncludeDirectories="c:\programme\audio\pd\src;c:\data\pdmax\flext\source;&quot;C:\data\prog\packs\Python-2.4\include&quot;;&quot;C:\data\prog\packs\Python-2.4\PC&quot;"
+ AdditionalIncludeDirectories="c:\data\prog\pd\pd-cvs\src;c:\data\pdmax\flext\source;&quot;C:\data\prog\packs\Python-2.4\include&quot;;&quot;C:\data\prog\packs\Python-2.4\PC&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;FLEXT_SYS=2;FLEXT_THREADS"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
diff --git a/externals/grill/py/readme.txt b/externals/grill/py/readme.txt
index 797a6b77..b9d818d8 100644
--- a/externals/grill/py/readme.txt
+++ b/externals/grill/py/readme.txt
@@ -1,24 +1,16 @@
-py/pyext - python script objects for PD (and MaxMSP... once, under MacOSX and Windows)
+py/pyext - python script objects for PD and Max/MSP
-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.
Donations for further development of the package are highly appreciated.
-Visit https://www.paypal.com/xclick/business=t.grill%40gmx.net&item_name=pyext&no_note=1&tax=0&currency_code=EUR
+Visit https://www.paypal.com/xclick/business=gr%40grrrr.org&item_name=pyext&no_note=1&tax=0&currency_code=EUR
----------------------------------------------------------------------------
You will need the flext C++ layer for PD and Max/MSP externals to compile this.
-see http://www.parasitaere-kapazitaeten.net/ext
-
-
-Package files:
-- readme.txt: this one
-- gpl.txt,license.txt: GPL license stuff
-- main.cpp, main.h, modmeth.cpp, pyargs.cpp, register.cpp: base class
-- py.cpp: py object
-- pyext.cpp, pyext.h, clmeth.cpp, bound.cpp: pyext object
+see http://grrrr.org/ext/flext
----------------------------------------------------------------------------
@@ -29,7 +21,6 @@ Access the flexibility of the python language in PD and MaxMSP
PD - Load it as i library with e.g. "pd -lib py -path scripts"
-Max/MSP - Wait for Windows or a Mach-O MacOSX version. MacOS9 doesn't want it.
Check out the sample patches and scripts
@@ -51,32 +42,7 @@ Known bugs:
----------------------------------------------------------------------------
The py/pyext package should run with Python version >= 2.1.
-It has been thoroughly tested with version 2.2 and 2.3
-
-
-The package should at least compile (and is tested) with the following compilers:
-
-
-PD @ Windows:
--------------
-o Borland C++ 5.5 (free): edit "config-pd-bcc.txt" & run "build-pd-bcc.bat"
-
-o Microsoft Visual C++ 6/7: edit "config-pd-msvc.txt" & run "build-pd-msvc.bat"
-
-
-PD @ linux:
------------
-o GCC: edit "config-pd-linux.txt" & run "sh build-pd-linux.sh"
-
-
-PD @ MacOSX:
----------------------
-You'll need to have Python installed as a framework.
-This is the default with Panther - otherwise, all newer Python source distributions are buildable as a darwin framework
-( ./configure --enable-framework=/System/Library/Frameworks && make && make installframework )
-
-o GCC: edit "config-pd-darwin.txt" & run "sh build-pd-darwin.sh"
-
+It has been thoroughly tested with versions 2.2 to 2.4
----------------------------------------------------------------------------
@@ -85,6 +51,9 @@ Version history:
0.2.0:
- ADD: handling of Python threads
- FIX: output of single atoms instead of 1-element lists
+- ADD: new detach mechanism (call queue)
+- ADD: support for Max/MSP @ OSX and Windows
+- DEL: eliminated meaningless inchannels and outchannels methods
0.1.4:
- ADD: better (and independent) handling of inlet and outlet count (as class variables or dynamically initialized in __init__)
@@ -153,13 +122,9 @@ general:
features:
- enable multiple interpreters?
-- make a pygui object where Tkinter draws to the PD canvas...
- stop individual threads
- Python type for symbols
+- support named (keyword) arguments (like attributes for messages)
tests:
- check for python threading support
-
-bugs:
-- named (keyword) arguments are not supported
-
diff --git a/externals/grill/py/source/bound.cpp b/externals/grill/py/source/bound.cpp
index 2504dde0..ce17578c 100644
--- a/externals/grill/py/source/bound.cpp
+++ b/externals/grill/py/source/bound.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.
@@ -21,11 +21,12 @@ struct bounddata
FuncSet funcs;
};
-bool pyext::boundmeth(flext_base *,t_symbol *sym,int argc,t_atom *argv,void *data)
+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);
- PY_LOCK
+ PyThreadState *state = pyth->PyLock();
PyObject *args = MakePyArgs(sym,argc,argv,-1,obj->self != NULL);
@@ -40,14 +41,14 @@ bool pyext::boundmeth(flext_base *,t_symbol *sym,int argc,t_atom *argv,void *dat
Py_XDECREF(args);
- PY_UNLOCK
+ pyth->PyUnlock(state);
return true;
}
PyObject *pyext::pyext_bind(PyObject *,PyObject *args)
{
PyObject *self,*meth;
- C *name;
+ char *name;
if(!PyArg_ParseTuple(args, "OsO:pyext_bind", &self,&name,&meth))
post("py/pyext - Wrong arguments!");
else if(!PyInstance_Check(self) || !(PyMethod_Check(meth) || PyFunction_Check(meth))) {
@@ -91,7 +92,7 @@ PyObject *pyext::pyext_bind(PyObject *,PyObject *args)
PyObject *pyext::pyext_unbind(PyObject *,PyObject *args)
{
PyObject *self,*meth;
- C *name;
+ char *name;
if(!PyArg_ParseTuple(args, "OsO:pyext_bind", &self,&name,&meth))
post("py/pyext - Wrong arguments!");
else if(!PyInstance_Check(self) || !(PyMethod_Check(meth) || PyFunction_Check(meth))) {
@@ -127,7 +128,7 @@ PyObject *pyext::pyext_unbind(PyObject *,PyObject *args)
}
-V pyext::ClearBinding()
+void pyext::ClearBinding()
{
// in case the object couldn't be constructed...
if(!pyobj) return;
diff --git a/externals/grill/py/source/clmeth.cpp b/externals/grill/py/source/clmeth.cpp
index d437f146..8423aa4b 100644
--- a/externals/grill/py/source/clmeth.cpp
+++ b/externals/grill/py/source/clmeth.cpp
@@ -2,7 +2,7 @@
py/pyext - python external object for PD and Max/MSP
-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.
@@ -39,8 +39,8 @@ PyMethodDef pyext::attr_tbl[] =
};
-const C *pyext::pyext_doc =
- "py/pyext - python external object for PD and Max/MSP, (C)2002-2004 Thomas Grill\n"
+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"
"_outlet(self,ix,args...): Send a message to an indexed outlet\n"
@@ -81,7 +81,7 @@ PyObject* pyext::pyext_setattr(PyObject *,PyObject *args)
return NULL;
}
- BL handled = false;
+ bool handled = false;
if(PyString_Check(name)) {
char* sname = PyString_AsString(name);
if (sname) {
@@ -136,7 +136,7 @@ PyObject* pyext::pyext_getattr(PyObject *,PyObject *args)
//! Send message to outlet
PyObject *pyext::pyext_outlet(PyObject *,PyObject *args)
{
- BL ok = false;
+ bool ok = false;
// should always be a tuple!
FLEXT_ASSERT(PyTuple_Check(args));
@@ -150,10 +150,10 @@ PyObject *pyext::pyext_outlet(PyObject *,PyObject *args)
) {
pyext *ext = GetThis(self);
- I sz = PyTuple_Size(args);
+ int sz = PyTuple_Size(args);
PyObject *val;
- BL tp =
+ bool tp =
sz == 3 &&
PySequence_Check(
val = PyTuple_GetItem(args,2) // borrow reference
@@ -164,7 +164,7 @@ PyObject *pyext::pyext_outlet(PyObject *,PyObject *args)
AtomList *lst = GetPyArgs(val);
if(lst) {
- I o = PyInt_AsLong(outl);
+ int o = PyInt_AsLong(outl);
if(o >= 1 && o <= ext->Outlets()) {
// by using the queue there is no immediate call of the next object
// deadlock would occur if this was another py/pyext object!
@@ -225,7 +225,7 @@ PyObject *pyext::pyext_stop(PyObject *,PyObject *args)
}
else {
pyext *ext = GetThis(self);
- I cnt = 0;
+ int cnt = 0;
t_atom at;
if(val >= 0) flext::SetInt(at,val);
ext->m_stop(cnt,&at);
@@ -255,15 +255,15 @@ PyObject *pyext::pyext_tocanvas(PyObject *,PyObject *args)
{
FLEXT_ASSERT(PyTuple_Check(args));
- BL ok = false;
+ bool ok = false;
PyObject *self = PyTuple_GetItem(args,0); // borrowed ref
if(self && PyInstance_Check(self)) {
pyext *ext = GetThis(self);
- I sz = PySequence_Size(args);
+ int sz = PySequence_Size(args);
PyObject *val;
- BL tp =
+ bool tp =
sz == 2 &&
PySequence_Check(
val = PyTuple_GetItem(args,1) // borrowed ref
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;
+}
diff --git a/externals/grill/py/source/main.h b/externals/grill/py/source/main.h
index 6dde3f54..e953b319 100644
--- a/externals/grill/py/source/main.h
+++ b/externals/grill/py/source/main.h
@@ -2,7 +2,7 @@
py/pyext - python script 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.
@@ -24,8 +24,8 @@ WARRANTIES, see the file, "license.txt," in this distribution.
#include <unistd.h>
#endif
-#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 408)
-#error You need at least flext version 0.4.8
+#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 500)
+#error You need at least flext version 0.5.0
#endif
#define PY__VERSION "0.2.0pre"
@@ -38,16 +38,28 @@ WARRANTIES, see the file, "license.txt," in this distribution.
#define PY_STOP_TICK 10 // ms
+class Fifo
+{
+protected:
+ struct FifoEl {
+ PyObject *fun;
+ PyObject *args;
+ FifoEl *nxt;
+ };
+public:
+ Fifo(): head(NULL),tail(NULL) {}
+ ~Fifo();
-#define I int
-#define C char
-#define V void
-#define BL bool
-#define F float
-#define D double
+ bool Push(PyObject *f,PyObject *a);
+ bool Pop(PyObject *&f,PyObject *&a);
+
+protected:
+ FifoEl *head,*tail;
+};
-#include "main.h"
+PyThreadState *FindThreadState();
+void FreeThreadState();
class py:
public flext_base
@@ -57,43 +69,43 @@ class py:
public:
py();
~py();
- static V lib_setup();
+ static void lib_setup();
- static PyObject *MakePyArgs(const t_symbol *s,int argc,const t_atom *argv,I inlet = -1,BL withself = false);
+ 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:
- V m__dir(PyObject *obj);
- V m__doc(PyObject *obj);
+ void m__dir(PyObject *obj);
+ void m__doc(PyObject *obj);
- V m_dir() { m__dir(module); }
- V mg_dir(AtomList &lst) { m__dir(module); }
- V m_doc() { m__doc(dict); }
+ 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 C *py_doc;
+ static const char *py_doc;
- V GetDir(PyObject *obj,AtomList &lst);
+ void 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();
+ 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();
- V Register(const C *reg);
- V Unregister(const C *reg);
- V Reregister(const C *reg);
- virtual V Reload() = 0;
+ void Register(const char *reg);
+ void Unregister(const char *reg);
+ void Reregister(const char *reg);
+ virtual void Reload() = 0;
- V Respond(BL b) { if(respond) { t_atom a[1]; SetBool(a[0],b); ToOutAnything(GetOutAttr(),MakeSymbol("response"),1,a); } }
+ void Respond(bool b);
- 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; }
+ 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 /*,tuple,list*/ };
+ enum retval { nothing,atom,sequ };
// --- module stuff -----
@@ -108,8 +120,7 @@ protected:
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);
static PyObject *py_setvalue(PyObject *,PyObject *args);
@@ -117,24 +128,59 @@ protected:
// ----thread stuff ------------
- virtual V m_stop(int argc,const t_atom *argv);
+ virtual void m_stop(int argc,const t_atom *argv);
- BL detach,shouldexit,respond;
- I thrcount;
- I stoptick;
+ bool shouldexit,respond;
+ int thrcount;
+ int stoptick;
Timer stoptmr;
+ int detach;
- V tick(V *);
+ 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:
#ifdef FLEXT_THREADS
ThrMutex mutex;
- inline V Lock() { mutex.Unlock(); }
- inline V Unlock() { mutex.Unlock(); }
+ 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 V Lock() {}
- inline V Unlock() {}
+ inline void Lock() {}
+ inline void Unlock() {}
+
+ inline PyThreadState *PyLock() { return NULL; }
+ inline void PyUnlock(PyThreadState *st) {}
#endif
static PyObject* StdOut_Write(PyObject* Self, PyObject* Args);
@@ -142,34 +188,15 @@ public:
protected:
// callbacks
- FLEXT_ATTRVAR_B(detach)
+ FLEXT_ATTRVAR_I(detach)
FLEXT_ATTRVAR_B(respond)
FLEXT_CALLBACK_V(m_stop)
FLEXT_CALLBACK(m_dir)
FLEXT_CALLGET_V(mg_dir)
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
+ FLEXT_THREAD(threadworker)
+};
#endif
diff --git a/externals/grill/py/source/modmeth.cpp b/externals/grill/py/source/modmeth.cpp
index 5a3efd10..88e3290a 100644
--- a/externals/grill/py/source/modmeth.cpp
+++ b/externals/grill/py/source/modmeth.cpp
@@ -2,7 +2,7 @@
py/pyext - python external object for PD and Max/MSP
-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.
@@ -21,8 +21,6 @@ PyMethodDef py::func_tbl[] =
{ "_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
{ "_getvalue", py::py_getvalue, METH_VARARGS,"Get value of a 'value' object" },
@@ -32,8 +30,8 @@ PyMethodDef py::func_tbl[] =
{NULL, NULL, 0, NULL} // sentinel
};
-const C *py::py_doc =
- "py/pyext - python external object for PD and Max/MSP, (C)2002-2004 Thomas Grill\n"
+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"
"_send(args...): Send a message to a send symbol\n"
@@ -42,15 +40,13 @@ const C *py::py_doc =
#endif
"_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"
;
-V py::tick(V *)
+void py::tick(void *)
{
Lock();
@@ -73,15 +69,15 @@ V py::tick(V *)
Unlock();
}
-V py::m_stop(int argc,const t_atom *argv)
+void py::m_stop(int argc,const t_atom *argv)
{
if(thrcount) {
Lock();
- I wait = PY_STOP_WAIT;
+ int wait = PY_STOP_WAIT;
if(argc >= 1 && CanbeInt(argv[0])) wait = GetAInt(argv[0]);
- I ticks = wait/PY_STOP_TICK;
+ int ticks = wait/PY_STOP_TICK;
if(stoptick) {
// already stopping
if(ticks < stoptick) stoptick = ticks;
@@ -106,32 +102,6 @@ PyObject *py::py_blocksize(PyObject *self,PyObject *args)
return PyLong_FromLong(sys_getblksize());
}
-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)
{
// should always be a tuple
diff --git a/externals/grill/py/source/py.cpp b/externals/grill/py/source/py.cpp
index 021e710f..05aeea8d 100644
--- a/externals/grill/py/source/py.cpp
+++ b/externals/grill/py/source/py.cpp
@@ -2,7 +2,7 @@
py/pyext - python script object for PD and Max/MSP
-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.
@@ -17,40 +17,43 @@ class pyobj:
FLEXT_HEADER_S(pyobj,py,Setup)
public:
- pyobj(I argc,const t_atom *argv);
+ pyobj(int argc,const t_atom *argv);
~pyobj();
protected:
- BL m_method_(I n,const t_symbol *s,I argc,const t_atom *argv);
+ bool m_method_(int n,const t_symbol *s,int argc,const t_atom *argv);
- BL work(const t_symbol *s,I argc,const t_atom *argv);
+ bool work(const t_symbol *s,int 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); }
+ 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 V m_help();
+ virtual void m_help();
// methods for python arguments
- V callwork(const t_symbol *s,I argc,const t_atom *argv);
+ void callwork(const t_symbol *s,int 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); }
+ 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 V Reload();
+ virtual void Reload();
- V SetFunction(const C *func);
- V ResetFunction();
+ void SetFunction(const char *func);
+ void ResetFunction();
private:
+
+ virtual bool callpy(PyObject *fun,PyObject *args);
+
static void Setup(t_classid c);
FLEXT_CALLBACK(m_bang)
@@ -98,10 +101,10 @@ void pyobj::Setup(t_classid c)
FLEXT_CADDATTR_VAR1(c,"respond",respond);
}
-pyobj::pyobj(I argc,const t_atom *argv):
+pyobj::pyobj(int argc,const t_atom *argv):
function(NULL),funname(NULL)
{
- PY_LOCK
+ PyThreadState *state = PyLock();
AddInAnything(2);
AddOutAnything();
@@ -116,7 +119,7 @@ pyobj::pyobj(I argc,const t_atom *argv):
if(!IsString(argv[0]))
post("%s - script name argument is invalid",thisName());
else {
- C dir[1024];
+ char dir[1024];
GetModulePath(GetString(argv[0]),dir,sizeof(dir));
// set script path
AddToPath(dir);
@@ -127,12 +130,11 @@ pyobj::pyobj(I argc,const t_atom *argv):
// add current dir to path
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")
#endif
@@ -153,29 +155,29 @@ pyobj::pyobj(I argc,const t_atom *argv):
}
}
- PY_UNLOCK
+ PyUnlock(state);
}
pyobj::~pyobj()
{
- PY_LOCK
+ PyThreadState *state = PyLock();
Unregister("_py");
- PY_UNLOCK
+ PyUnlock(state);
}
-BL pyobj::m_method_(I n,const t_symbol *s,I argc,const t_atom *argv)
+bool pyobj::m_method_(int n,const t_symbol *s,int argc,const t_atom *argv)
{
if(n == 1)
post("%s - no method for type %s",thisName(),GetString(s));
return false;
}
-V pyobj::m_reload()
+void pyobj::m_reload()
{
- PY_LOCK
+ PyThreadState *state = PyLock();
Unregister("_py");
@@ -184,29 +186,29 @@ V pyobj::m_reload()
Register("_py");
SetFunction(funname?GetString(funname):NULL);
- PY_UNLOCK
+ PyUnlock(state);
}
-V pyobj::m_reload_(I argc,const t_atom *argv)
+void pyobj::m_reload_(int argc,const t_atom *argv)
{
- PY_LOCK
+ PyThreadState *state = PyLock();
SetArgs(argc,argv);
- PY_UNLOCK
+ PyUnlock(state);
m_reload();
}
-V pyobj::m_set(I argc,const t_atom *argv)
+void pyobj::m_set(int argc,const t_atom *argv)
{
- PY_LOCK
+ PyThreadState *state = PyLock();
- I ix = 0;
+ int ix = 0;
if(argc >= 2) {
if(!IsString(argv[ix])) {
post("%s - script name is not valid",thisName());
return;
}
- const C *sn = GetString(argv[ix]);
+ const char *sn = GetString(argv[ix]);
if(!module || !strcmp(sn,PyModule_GetName(module))) {
ImportModule(sn);
@@ -221,13 +223,13 @@ V pyobj::m_set(I argc,const t_atom *argv)
else
SetFunction(GetString(argv[ix]));
- PY_UNLOCK
+ PyUnlock(state);
}
-V pyobj::m_help()
+void pyobj::m_help()
{
post("");
- post("%s %s - python script object, (C)2002-2004 Thomas Grill",thisName(),PY__VERSION);
+ post("%s %s - python script object, (C)2002-2005 Thomas Grill",thisName(),PY__VERSION);
#ifdef FLEXT_DEBUG
post("DEBUG VERSION, compiled on " __DATE__ " " __TIME__);
#endif
@@ -248,13 +250,13 @@ V pyobj::m_help()
post("\tdir: dump module dictionary");
post("\tdir+: dump function dictionary");
#ifdef FLEXT_THREADS
- post("\tdetach 0/1: detach threads");
+ post("\tdetach 0/1/2: detach threads");
post("\tstop {wait time (ms)}: stop threads");
#endif
post("");
}
-V pyobj::ResetFunction()
+void pyobj::ResetFunction()
{
if(!module || !dict)
{
@@ -263,7 +265,7 @@ V pyobj::ResetFunction()
return;
}
- function = funname?PyDict_GetItemString(dict,(C *)GetString(funname)):NULL; // borrowed!!!
+ function = funname?PyDict_GetItemString(dict,(char *)GetString(funname)):NULL; // borrowed!!!
if(!function) {
PyErr_Clear();
if(funname) post("%s - Function %s could not be found",thisName(),GetString(funname));
@@ -274,7 +276,7 @@ V pyobj::ResetFunction()
}
}
-V pyobj::SetFunction(const C *func)
+void pyobj::SetFunction(const char *func)
{
if(func) {
funname = MakeSymbol(func);
@@ -285,63 +287,51 @@ V pyobj::SetFunction(const C *func)
}
-V pyobj::Reload()
+void pyobj::Reload()
{
ResetFunction();
}
-
-BL pyobj::work(const t_symbol *s,I argc,const t_atom *argv)
+bool pyobj::callpy(PyObject *fun,PyObject *args)
{
- AtomList *rargs = NULL;
- BL ret;
-
- ++thrcount;
- PY_LOCK
+ 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) {
- 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;
- }
+ 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());
ret = false;
}
- 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);
}
-
-
diff --git a/externals/grill/py/source/pyargs.cpp b/externals/grill/py/source/pyargs.cpp
index 3c2d3c35..90686a90 100644
--- a/externals/grill/py/source/pyargs.cpp
+++ b/externals/grill/py/source/pyargs.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.
@@ -21,13 +21,13 @@ static PyObject *MakePyAtom(const t_atom &at)
return (double)ival == fval?PyInt_FromLong(ival):PyFloat_FromDouble(fval);
}
// these following should never happen
- else if(flext::IsFloat(at)) return PyFloat_FromDouble((D)flext::GetFloat(at));
+ else if(flext::IsFloat(at)) return PyFloat_FromDouble((double)flext::GetFloat(at));
else if(flext::IsInt(at)) return PyInt_FromLong(flext::GetInt(at));
return NULL;
}
-PyObject *py::MakePyArgs(const t_symbol *s,int argc,const t_atom *argv,I inlet,BL withself)
+PyObject *py::MakePyArgs(const t_symbol *s,int argc,const t_atom *argv,int inlet,bool withself)
{
PyObject *pArgs;
@@ -40,10 +40,10 @@ PyObject *py::MakePyArgs(const t_symbol *s,int argc,const t_atom *argv,I inlet,B
else
*/
{
- BL any = IsAnything(s);
+ bool any = IsAnything(s);
pArgs = PyTuple_New(argc+(any?1:0)+(inlet >= 0?1:0));
- I pix = 0;
+ int pix = 0;
if(inlet >= 0) {
PyObject *pValue = PyInt_FromLong(inlet);
@@ -52,7 +52,7 @@ PyObject *py::MakePyArgs(const t_symbol *s,int argc,const t_atom *argv,I inlet,B
PyTuple_SetItem(pArgs, pix++, pValue);
}
- I ix;
+ int ix;
PyObject *tmp;
if(!withself || argc < (any?1:2)) tmp = pArgs,ix = pix;
else tmp = PyTuple_New(argc+(any?1:0)),ix = 0;
@@ -64,7 +64,7 @@ PyObject *py::MakePyArgs(const t_symbol *s,int argc,const t_atom *argv,I inlet,B
PyTuple_SetItem(tmp, ix++, pValue);
}
- for(I i = 0; i < argc; ++i) {
+ for(int i = 0; i < argc; ++i) {
PyObject *pValue = MakePyAtom(argv[i]);
if(!pValue) {
post("py/pyext: cannot convert argument %i",any?i+1:i);
@@ -95,8 +95,8 @@ flext::AtomList *py::GetPyArgs(PyObject *pValue,PyObject **self)
// analyze return value or tuple
- I rargc = 0;
- BL ok = true;
+ int rargc = 0;
+ bool ok = true;
retval tp = nothing;
if(PyString_Check(pValue)) {
@@ -116,7 +116,7 @@ flext::AtomList *py::GetPyArgs(PyObject *pValue,PyObject **self)
ret = new AtomList(rargc);
- for(I ix = 0; ix < rargc; ++ix) {
+ for(int ix = 0; ix < rargc; ++ix) {
PyObject *arg;
if(tp == sequ)
arg = PySequence_GetItem(pValue,ix); // new reference
@@ -125,7 +125,7 @@ flext::AtomList *py::GetPyArgs(PyObject *pValue,PyObject **self)
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(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)) {
// assumed to be self ... that should be checked _somehow_ !!!
@@ -135,7 +135,7 @@ flext::AtomList *py::GetPyArgs(PyObject *pValue,PyObject **self)
else {
PyObject *tp = PyObject_Type(arg);
PyObject *stp = tp?PyObject_Str(tp):NULL;
- C *tmp = "";
+ char *tmp = "";
if(stp) tmp = PyString_AsString(stp);
post("py/pyext: Could not convert argument %s",tmp);
Py_XDECREF(stp);
diff --git a/externals/grill/py/source/pyext.cpp b/externals/grill/py/source/pyext.cpp
index 9e1ff30b..f0fc25ba 100644
--- a/externals/grill/py/source/pyext.cpp
+++ b/externals/grill/py/source/pyext.cpp
@@ -2,7 +2,7 @@
py/pyext - python script object for PD and Max/MSP
-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.
@@ -13,9 +13,14 @@ WARRANTIES, see the file, "license.txt," in this distribution.
FLEXT_LIB_V("pyext pyext. pyx pyx.",pyext)
-V pyext::Setup(t_classid c)
+
+static const t_symbol *sym_get;
+
+void pyext::Setup(t_classid c)
{
- FLEXT_CADDMETHOD_(c,0,"reload.",m_reload);
+ 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);
FLEXT_CADDMETHOD_(c,0,"dir+",m_dir_);
@@ -35,7 +40,6 @@ V pyext::Setup(t_classid c)
FLEXT_CADDATTR_VAR1(c,"respond",respond);
-
// ----------------------------------------------------
// register/initialize pyext base class along with module
@@ -112,7 +116,7 @@ static short patcher_myvol(t_patcher *x)
PyObject *pyext::class_obj = NULL;
PyObject *pyext::class_dict = NULL;
-pyext::pyext(I argc,const t_atom *argv):
+pyext::pyext(int argc,const t_atom *argv):
pyobj(NULL),pythr(NULL),
inlets(-1),outlets(-1),
methname(NULL)
@@ -127,7 +131,7 @@ pyext::pyext(I argc,const t_atom *argv):
const t_atom *clname = NULL;
- PY_LOCK
+ PyThreadState *state = PyLock();
// init script module
if(argc > apre) {
@@ -238,7 +242,7 @@ pyext::pyext(I argc,const t_atom *argv):
else
inlets = outlets = 0;
- PY_UNLOCK
+ PyUnlock(state);
if(inlets < 0 || outlets < 0)
InitProblem();
@@ -253,7 +257,7 @@ pyext::pyext(I argc,const t_atom *argv):
pyext::~pyext()
{
- PY_LOCK
+ PyThreadState *state = PyLock();
ClearBinding();
@@ -265,10 +269,10 @@ pyext::~pyext()
Unregister("_pyext");
UnimportModule();
- PY_UNLOCK
+ PyUnlock(state);
}
-BL pyext::DoInit()
+bool pyext::DoInit()
{
SetThis();
@@ -293,12 +297,12 @@ BL pyext::DoInit()
return true;
}
-BL pyext::MakeInstance()
+bool 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)));
+ PyObject *pref = PyObject_GetAttrString(module,const_cast<char *>(GetString(methname)));
if(!pref)
PyErr_Print();
else {
@@ -319,7 +323,7 @@ BL pyext::MakeInstance()
return false;
}
-V pyext::Reload()
+void pyext::Reload()
{
ClearBinding();
Py_XDECREF(pyobj);
@@ -333,9 +337,9 @@ V pyext::Reload()
}
-V pyext::m_reload()
+void pyext::m_reload()
{
- PY_LOCK
+ PyThreadState *state = PyLock();
Unregister("_pyext"); // self
@@ -346,10 +350,10 @@ V pyext::m_reload()
SetThis();
- PY_UNLOCK
+ PyUnlock(state);
}
-V pyext::m_reload_(I argc,const t_atom *argv)
+void pyext::m_reload_(int argc,const t_atom *argv)
{
args(argc,argv);
m_reload();
@@ -357,7 +361,7 @@ V pyext::m_reload_(I argc,const t_atom *argv)
void pyext::m_get(const t_symbol *s)
{
- PY_LOCK
+ PyThreadState *state = PyLock();
PyObject *pvar = PyObject_GetAttrString(pyobj,const_cast<char *>(GetString(s))); /* fetch bound method */
if(!pvar) {
@@ -368,7 +372,7 @@ void pyext::m_get(const t_symbol *s)
AtomList *lst = GetPyArgs(pvar);
if(lst) {
// dump value to attribute outlet
- AtomAnything out("get",lst->Count()+1);
+ AtomAnything out(sym_get,lst->Count()+1);
SetSymbol(out[0],s);
out.Set(lst->Count(),lst->Atoms(),1);
delete lst;
@@ -380,12 +384,12 @@ void pyext::m_get(const t_symbol *s)
Py_DECREF(pvar);
}
- PY_UNLOCK
+ PyUnlock(state);
}
void pyext::m_set(int argc,const t_atom *argv)
{
- PY_LOCK
+ PyThreadState *state = PyLock();
if(argc < 2 || !IsString(argv[0]))
post("%s - Syntax: set varname arguments...",thisName());
@@ -417,25 +421,25 @@ void pyext::m_set(int argc,const t_atom *argv)
}
}
- PY_UNLOCK
+ PyUnlock(state);
}
-BL pyext::m_method_(I n,const t_symbol *s,I argc,const t_atom *argv)
+bool pyext::m_method_(int n,const t_symbol *s,int argc,const t_atom *argv)
{
- BL ret = false;
+ bool ret = false;
if(pyobj && n >= 1)
- ret = callwork(n,s,argc,argv);
+ ret = work(n,s,argc,argv);
else
post("%s - no method for type '%s' into inlet %i",thisName(),GetString(s),n);
return ret;
}
-V pyext::m_help()
+void pyext::m_help()
{
post("");
- post("%s %s - python class object, (C)2002-2004 Thomas Grill",thisName(),PY__VERSION);
+ post("%s %s - python class object, (C)2002-2005 Thomas Grill",thisName(),PY__VERSION);
#ifdef FLEXT_DEBUG
post("DEBUG VERSION, compiled on " __DATE__ " " __TIME__);
#endif
@@ -460,97 +464,50 @@ V pyext::m_help()
post("");
}
-PyObject *pyext::call(const C *meth,I inlet,const t_symbol *s,I argc,const t_atom *argv)
+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)
{
- PyObject *ret = NULL;
+ bool ret = false;
- PyObject *pmeth = PyObject_GetAttrString(pyobj,const_cast<char *>(meth)); /* fetch bound method */
+ PyObject *pmeth = PyObject_GetAttrString(pyobj,const_cast<char *>(meth)); /* fetch bound method */
if(pmeth == NULL) {
PyErr_Clear(); // no method found
}
else {
PyObject *pargs = MakePyArgs(s,argc,argv,inlet?inlet:-1,true);
- if(!pargs)
+ 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;
+ Py_DECREF(pmeth);
}
-
-#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 = gencall(pmeth,pargs);
}
- else
- ret = ok = work(n,s,argc,argv);
- Respond(ok);
- return ret;
+ return ret;
}
-BL pyext::work(I n,const t_symbol *s,I argc,const t_atom *argv)
+bool pyext::work(int n,const t_symbol *s,int argc,const t_atom *argv)
{
- BL retv = false;
+ bool ret = false;
- PY_LOCK
+ PyThreadState *state = PyLock();
- PyObject *ret = NULL;
- char *str = new char[strlen(GetString(s))+10];
+ // should be enough...
+ char str[256];
{
// try tag/inlet
@@ -563,7 +520,7 @@ BL pyext::work(I n,const t_symbol *s,I argc,const t_atom *argv)
sprintf(str,"_anything_%i",n);
if(s == sym_bang && !argc) {
t_atom argv;
- SetString(argv,"");
+ SetSymbol(argv,sym__);
ret = call(str,0,s,1,&argv);
}
else
@@ -576,29 +533,22 @@ BL pyext::work(I n,const t_symbol *s,I argc,const t_atom *argv)
}
if(!ret) {
// try anything at any inlet
- strcpy(str,"_anything_");
+ const char *str1 = "_anything_";
if(s == sym_bang && !argc) {
t_atom argv;
- SetString(argv,"");
- ret = call(str,n,s,1,&argv);
+ SetSymbol(argv,sym__);
+ ret = call(str1,n,s,1,&argv);
}
else
- ret = call(str,n,s,argc,argv);
+ ret = call(str1,n,s,argc,argv);
}
if(!ret)
// no matching python method found
post("%s - no matching method found for '%s' into inlet %i",thisName(),GetString(s),n);
- if(str) delete[] str;
+ PyUnlock(state);
- if(ret) {
- if(!PyObject_Not(ret)) post("%s - returned value is ignored",thisName());
- Py_DECREF(ret);
- retv = true;
- }
-
- PY_UNLOCK
-
- return retv;
+ Respond(ret);
+ return ret;
}
diff --git a/externals/grill/py/source/pyext.h b/externals/grill/py/source/pyext.h
index 9fd4c157..45ba866d 100644
--- a/externals/grill/py/source/pyext.h
+++ b/externals/grill/py/source/pyext.h
@@ -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.
@@ -19,7 +19,7 @@ class pyext:
FLEXT_HEADER_S(pyext,py,Setup)
public:
- pyext(I argc,const t_atom *argv);
+ pyext(int argc,const t_atom *argv);
~pyext();
static PyObject *pyext__doc__(PyObject *,PyObject *args);
@@ -38,46 +38,46 @@ public:
static PyObject *pyext_stop(PyObject *,PyObject *args);
static PyObject *pyext_isthreaded(PyObject *,PyObject *);
- I Inlets() const { return inlets; }
- I Outlets() const { return outlets; }
+ int Inlets() const { return inlets; }
+ int Outlets() const { return outlets; }
protected:
- virtual BL m_method_(I n,const t_symbol *s,I argc,const t_atom *argv);
+ virtual bool m_method_(int n,const t_symbol *s,int argc,const t_atom *argv);
- BL work(I n,const t_symbol *s,I argc,const t_atom *argv);
+ bool work(int n,const t_symbol *s,int 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();
+ 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();
- V m_get(const t_symbol *s);
- V m_set(I argc,const t_atom *argv);
+ void m_get(const t_symbol *s);
+ void m_set(int argc,const t_atom *argv);
const t_symbol *methname;
PyObject *pyobj;
- I inlets,outlets;
+ int inlets,outlets;
private:
- static V Setup(t_classid);
+ static void Setup(t_classid);
static pyext *GetThis(PyObject *self);
void SetThis();
- V ClearBinding();
- BL MakeInstance();
- BL DoInit();
+ void ClearBinding();
+ bool MakeInstance();
+ bool DoInit();
AtomList args;
- virtual V Reload();
+ virtual void Reload();
static PyObject *class_obj,*class_dict;
static PyMethodDef attr_tbl[],meth_tbl[];
- static const C *pyext_doc;
+ static const char *pyext_doc;
// -------- bind stuff ------------------
static PyObject *pyext_bind(PyObject *,PyObject *args);
@@ -85,24 +85,10 @@ private:
// ---------------------------
- PyObject *call(const C *meth,I inlet,const t_symbol *s,I argc,const t_atom *argv);
+ bool call(const char *meth,int inlet,const t_symbol *s,int 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
+ virtual bool callpy(PyObject *fun,PyObject *args);
+ static bool stcallpy(PyObject *fun,PyObject *args);
PyThreadState *pythr;
diff --git a/externals/grill/py/source/register.cpp b/externals/grill/py/source/register.cpp
index c0ca4675..ae273955 100644
--- a/externals/grill/py/source/register.cpp
+++ b/externals/grill/py/source/register.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.
@@ -11,39 +11,37 @@ WARRANTIES, see the file, "license.txt," in this distribution.
#include "main.h"
-V py::Register(const C *regnm)
+void py::Register(const char *regnm)
{
if(module) {
// add this to module registry
- PyObject *reg = PyDict_GetItemString(dict,(C *)regnm); // borrowed!!!
+ PyObject *reg = PyDict_GetItemString(dict,(char *)regnm); // borrowed!!!
PyObject *add = Py_BuildValue("[i]",(long)this);
if(!reg || !PyList_Check(reg)) {
- if(PyDict_SetItemString(dict,(C *)regnm,add)) {
+ if(PyDict_SetItemString(dict,(char *)regnm,add)) {
post("%s - Could not set registry",thisName());
}
- // Py_XDECREF(reg);
}
else {
PySequence_InPlaceConcat(reg,add);
}
}
-
}
-V py::Unregister(const C *regnm)
+void py::Unregister(const char *regnm)
{
if(module) {
// remove this from module registry
- PyObject *reg = PyDict_GetItemString(dict,(C *)regnm); // borrowed!!!
+ PyObject *reg = PyDict_GetItemString(dict,(char *)regnm); // borrowed!!!
PyObject *add = Py_BuildValue("i",(int)this);
if(!reg || !PySequence_Check(reg))
- post("%s - Registry not found!?",thisName());
+ post("%s - Internal error: Registry not found!?",thisName());
else {
- I ix = PySequence_Index(reg,add);
+ int ix = PySequence_Index(reg,add);
if(ix < 0) {
- post("%s - This object not found in registry?!",thisName());
+ post("%s - Internal error: object not found in registry?!",thisName());
}
else {
PySequence_DelItem(reg,ix);
@@ -51,24 +49,23 @@ V py::Unregister(const C *regnm)
}
Py_DECREF(add);
}
-
}
-V py::Reregister(const C *regnm)
+void py::Reregister(const char *regnm)
{
if(module) {
// remove this from module registry
- PyObject *reg = PyDict_GetItemString(dict,(C *)regnm); // borrowed!!!
+ PyObject *reg = PyDict_GetItemString(dict,(char *)regnm); // borrowed!!!
if(!reg || !PySequence_Check(reg))
- post("%s - Registry not found!?",thisName());
+ post("%s - Internal error: Registry not found!?",thisName());
else {
- I cnt = PySequence_Size(reg);
- for(I i = 0; i < cnt; ++i) {
+ 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 - Corrupt registry?!",thisName());
+ post("%s - Internal error: Corrupt registry?!",thisName());
}
else {
py *th = (py *)PyInt_AsLong(it);
@@ -81,8 +78,4 @@ V py::Reregister(const C *regnm)
}
}
}
-
}
-
-
-