diff options
author | Thomas Grill <xovo@users.sourceforge.net> | 2005-07-08 14:30:31 +0000 |
---|---|---|
committer | Thomas Grill <xovo@users.sourceforge.net> | 2005-07-08 14:30:31 +0000 |
commit | 897b80c5585f7c9031ff1aafb504c21a9d3b1606 (patch) | |
tree | eaab38174de9e018827634ed079a885e232097a4 /externals/grill/py/source/main.cpp | |
parent | 6efb16b9040f7ba6db8c60559e0c815d54f05c43 (diff) |
better reload handling, but still far fom perfect
fixed minor other issues
cleaned up float vs. int pyext tags
simplifications in py and pyext
bumped version number
python-like dotted module.function syntax
send and receive wrapped PyObjects through inlets/outlets
multiply inlets for py (hot and cold inlets)
svn path=/trunk/; revision=3308
Diffstat (limited to 'externals/grill/py/source/main.cpp')
-rw-r--r-- | externals/grill/py/source/main.cpp | 621 |
1 files changed, 1 insertions, 620 deletions
diff --git a/externals/grill/py/source/main.cpp b/externals/grill/py/source/main.cpp index 428afea7..399f35c1 100644 --- a/externals/grill/py/source/main.cpp +++ b/externals/grill/py/source/main.cpp @@ -8,625 +8,6 @@ WARRANTIES, see the file, "license.txt," in this distribution. */ -#include "main.h" -#include <map> +#include "pybase.h" -static PyMethodDef StdOut_Methods[] = -{ - { "write", pybase::StdOut_Write, 1 }, - { NULL, NULL, } -}; -static PyObject *gcollect = NULL; - -#ifdef FLEXT_THREADS - -typedef std::map<flext::thrid_t,PyThreadState *> PyThrMap; - -static PyInterpreterState *pymain = NULL; -static PyThrMap pythrmap; -PyThreadState *pybase::pythrsys = NULL; - -int pybase::lockcount = 0; - -PyThreadState *pybase::FindThreadState() -{ - flext::thrid_t id = flext::GetThreadId(); - PyThrMap::iterator it = pythrmap.find(id); - if(it == pythrmap.end()) { - // Make new thread state - PyThreadState *st = PyThreadState_New(pymain); - pythrmap[id] = st; - return st; - } - else - return it->second; -} - -void pybase::FreeThreadState() -{ - flext::thrid_t id = flext::GetThreadId(); - PyThrMap::iterator it = pythrmap.find(id); - if(it != pythrmap.end()) { - // clear out any cruft from thread state object - PyThreadState_Clear(it->second); - // delete my thread state object - PyThreadState_Delete(it->second); - // delete from map - pythrmap.erase(it); - } -} -#endif - - -PyObject *pybase::module_obj = NULL; -PyObject *pybase::module_dict = NULL; - - -void initsymbol(); -void initsamplebuffer(); - -void pybase::lib_setup() -{ - post(""); - post("------------------------------------------------"); - post("py/pyext %s - python script objects",PY__VERSION); - post("(C)2002-2005 Thomas Grill - http://grrrr.org/ext"); - post(""); - post("using Python %s",Py_GetVersion()); - -#ifdef FLEXT_DEBUG - post(""); - post("DEBUG version compiled on %s %s",__DATE__,__TIME__); -#endif - - // ------------------------------------------------------------- - - Py_Initialize(); - -#ifdef FLEXT_DEBUG -// Py_VerboseFlag = 1; -#endif - -#ifdef FLEXT_THREADS - // enable thread support and acquire the global thread lock - PyEval_InitThreads(); - - // get thread state - pythrsys = PyThreadState_Get(); - // get main interpreter state - pymain = pythrsys->interp; - - // add thread state of main thread to map - pythrmap[GetThreadId()] = pythrsys; -#endif - - // sys.argv must be set to empty tuple - char *nothing = ""; - PySys_SetArgv(0,¬hing); - - // register/initialize pyext module only once! - module_obj = Py_InitModule(PYEXT_MODULE, func_tbl); - 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); - - // get garbage collector function - PyObject *gcobj = PyImport_ImportModule("gc"); - if(gcobj) { - gcollect = PyObject_GetAttrString(gcobj,"collect"); - Py_DECREF(gcobj); - } - - // add symbol type - initsymbol(); - PyModule_AddObject(module_obj,"Symbol",(PyObject *)&pySymbol_Type); - - // pre-defined symbols - PyModule_AddObject(module_obj,"_s_",(PyObject *)pySymbol__); - PyModule_AddObject(module_obj,"_s_bang",(PyObject *)pySymbol_bang); - PyModule_AddObject(module_obj,"_s_list",(PyObject *)pySymbol_list); - PyModule_AddObject(module_obj,"_s_symbol",(PyObject *)pySymbol_symbol); - PyModule_AddObject(module_obj,"_s_float",(PyObject *)pySymbol_float); - PyModule_AddObject(module_obj,"_s_int",(PyObject *)pySymbol_int); - - // add samplebuffer type - initsamplebuffer(); - PyModule_AddObject(module_obj,"Buffer",(PyObject *)&pySamplebuffer_Type); - - // ------------------------------------------------------------- - - FLEXT_SETUP(pyobj); - FLEXT_SETUP(pyext); - FLEXT_DSP_SETUP(pydsp); - -#ifdef FLEXT_THREADS - // release global lock - PyEval_ReleaseLock(); -#endif - - post("------------------------------------------------"); - post(""); -} - -FLEXT_LIB_SETUP(py,pybase::lib_setup) - - -pybase::pybase() - : module(NULL) -#ifdef FLEXT_THREADS - , shouldexit(false),thrcount(0),stoptick(0) -#endif - , detach(0) -{ - PyThreadState *state = PyLockSys(); - Py_INCREF(module_obj); - PyUnlock(state); -} - -pybase::~pybase() -{ - PyThreadState *state = PyLockSys(); - Py_XDECREF(module_obj); - PyUnlock(state); -} - -void pybase::Exit() -{ -#ifdef FLEXT_THREADS - 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(PY_STOP_TICK*0.001f); - if(thrcount) { - // Wait forever - post("py/pyext - Waiting for thread termination!"); - while(thrcount) Sleep(PY_STOP_TICK*0.001f); - post("py/pyext - Okay, all threads have terminated"); - } - } -#endif -} - -void pybase::GetDir(PyObject *obj,AtomList &lst) -{ - if(obj) { - PyThreadState *state = PyLock(); - - PyObject *pvar = PyObject_Dir(obj); - if(!pvar) - PyErr_Print(); // no method found - else { - if(!GetPyArgs(lst,pvar)) - post("py/pyext - Argument list could not be created"); - Py_DECREF(pvar); - } - - PyUnlock(state); - } -} - -void pybase::m__dir(PyObject *obj) -{ - AtomList lst; - GetDir(obj,lst); - // dump dir to attribute outlet - DumpOut(NULL,lst.Count(),lst.Atoms()); -} - -void pybase::m__doc(PyObject *obj) -{ - if(obj) { - PyThreadState *state = PyLock(); - - PyObject *docf = PyDict_GetItemString(obj,"__doc__"); // borrowed!!! - if(docf && PyString_Check(docf)) { - post(""); - const char *s = PyString_AS_STRING(docf); - - // FIX: Python doc strings can easily be larger than 1k characters - // -> split into separate lines - for(;;) { - char buf[1024]; - char *nl = strchr((char *)s,'\n'); // the cast is for Borland C++ - if(!nl) { - // no more newline found - post(s); - break; - } - else { - // copy string before newline to temp buffer and post - unsigned int l = nl-s; - if(l >= sizeof(buf)) l = sizeof buf-1; - strncpy(buf,s,l); // copy all but newline - buf[l] = 0; - post(buf); - s = nl+1; // set after newline - } - } - } - - PyUnlock(state); - } -} - -void pybase::OpenEditor() -{ - // this should once open the editor.... -} - -void pybase::SetArgs() -{ - // script arguments - int argc = args.Count(); - const t_atom *argv = args.Atoms(); - char **sargv = new char *[argc+1]; - for(int i = 0; i <= argc; ++i) { - sargv[i] = new char[256]; - if(!i) - strcpy(sargv[i],"py/pyext"); - else - GetAString(argv[i-1],sargv[i],255); - } - - // the arguments to the module are only recognized once! (at first use in a patcher) - PySys_SetArgv(argc+1,sargv); - - for(int j = 0; j <= argc; ++j) delete[] sargv[j]; - delete[] sargv; -} - -bool pybase::ImportModule(const char *name) -{ - if(!name) return false; - if(modname == name) return true; - modname = name; - return ReloadModule(); -} - -void pybase::UnimportModule() -{ - if(!module) return; - - FLEXT_ASSERT(dict && module_obj && module_dict); - - Py_DECREF(module); - - // reference count to module is not 0 here, altough probably the last instance was unloaded - // Python retains one reference to the module all the time - // we don't care - - module = NULL; - dict = NULL; -} - -bool pybase::ReloadModule() -{ - bool ok = false; - - SetArgs(); - PyObject *newmod = module - ?PyImport_ReloadModule(module) - :PyImport_ImportModule((char *)modname.c_str()); - - if(!newmod) { - // unload faulty module - if(module) UnimportModule(); - } - else { - Py_XDECREF(module); - module = newmod; - dict = PyModule_GetDict(module); // borrowed - ok = true; - } - return ok; -} - -void pybase::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; - - // if dir is current working directory... name points to dir - if(dir == name) strcpy(dir,"."); -#elif FLEXT_SYS == FLEXT_SYS_MAX - // how do i get the path in Max/MSP? - 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 - *dir = 0; -#else - *dir = 0; -#endif -} - -void pybase::AddToPath(const char *dir) -{ - if(dir && *dir) { - PyObject *pobj = PySys_GetObject("path"); - if(pobj && PyList_Check(pobj)) { - PyObject *ps = PyString_FromString(dir); - if(!PySequence_Contains(pobj,ps)) - PyList_Append(pobj,ps); // makes new reference - Py_DECREF(ps); - } - PySys_SetObject("path",pobj); // steals reference to pobj - } -} - -static const t_symbol *sym_response = flext::MakeSymbol("response"); - -void pybase::Respond(bool b) -{ - if(respond) { - t_atom a; - SetBool(a,b); - DumpOut(sym_response,1,&a); - } -} - -void pybase::Reload() -{ - PyThreadState *state = PyLockSys(); - - PyObject *reg = GetRegistry(REGNAME); - - if(reg) { - PyObject *key; - int pos = 0; - while(PyDict_Next(reg,&pos,&key,NULL)) { - pybase *th = (pybase *)PyLong_AsLong(key); - FLEXT_ASSERT(th); - th->Unload(); - } - - UnloadModule(); - } - - bool ok = ReloadModule(); - - if(ok) { - LoadModule(); - - if(reg) { - SetRegistry(REGNAME,reg); - - PyObject *key; - int pos = 0; - while(PyDict_Next(reg,&pos,&key,NULL)) { - pybase *th = (pybase *)PyLong_AsLong(key); - FLEXT_ASSERT(th); - th->Load(); - } - } - else - Load(); - } - - Report(); - PyUnlock(state); -} - - - -static PyObject *output = NULL; - -// post to the console -PyObject* pybase::StdOut_Write(PyObject* self, PyObject* args) -{ - // should always be a tuple - FLEXT_ASSERT(PyTuple_Check(args)); - - const int sz = PyTuple_GET_SIZE(args); - - for(int i = 0; i < sz; ++i) { - PyObject *val = PyTuple_GET_ITEM(args,i); // borrowed reference - PyObject *str = PyObject_Str(val); // new reference - char *cstr = PyString_AS_STRING(str); - char *lf = strchr(cstr,'\n'); - - // line feed in string - if(!lf) { - // no -> just append - if(output) - PyString_ConcatAndDel(&output,str); // str is decrefd - else - output = str; // take str reference - } - else { - // yes -> append up to line feed, reset output buffer to string remainder - PyObject *part = PyString_FromStringAndSize(cstr,lf-cstr); // new reference - if(output) - PyString_ConcatAndDel(&output,part); // str is decrefd - else - output = part; // take str reference - - // output concatenated string - post(PyString_AS_STRING(output)); - - Py_DECREF(output); - output = PyString_FromString(lf+1); // new reference - } - } - - 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 pybase::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; -#ifdef FLEXT_THREADS - case 1: - // put call into queue - ret = qucall(pmeth,pargs); - break; - case 2: - // each call a new thread - if(!shouldexit) { - ret = thrcall(new work_data(pmeth,pargs)); - if(!ret) post("py/pyext - Failed to launch thread!"); - } - break; -#endif - default: - post("py/pyext - Unknown detach mode"); - } - return ret; -} - -void pybase::work_wrapper(void *data) -{ - FLEXT_ASSERT(data); - -#ifdef FLEXT_THREADS - ++thrcount; -#endif - - PyThreadState *state = PyLock(); - - // call worker - work_data *w = (work_data *)data; - callpy(w->fun,w->args); - delete w; - - PyUnlock(state); - -#ifdef FLEXT_THREADS - --thrcount; -#endif -} - -#ifdef FLEXT_THREADS -bool pybase::qucall(PyObject *fun,PyObject *args) -{ - FifoEl *el = qufifo.New(); - el->Set(fun,args); - qufifo.Put(el); - qucond.Signal(); - return true; -} - -void pybase::threadworker() -{ - ++thrcount; - - FifoEl *el; - PyThreadState *my = FindThreadState(),*state; - - for(;;) { - while(el = qufifo.Get()) { - ++thrcount; - state = PyLock(my); - callpy(el->fun,el->args); - Py_XDECREF(el->fun); - Py_XDECREF(el->args); - PyUnlock(state); - qufifo.Free(el); - --thrcount; - } - if(shouldexit) - break; - else - qucond.Wait(); - } - - state = PyLock(my); - // unref remaining Python objects - while(el = qufifo.Get()) { - Py_XDECREF(el->fun); - Py_XDECREF(el->args); - qufifo.Free(el); - } - PyUnlock(state); - - --thrcount; -} -#endif - -#if FLEXT_SYS == FLEXT_SYS_MAX -short pybase::patcher_myvol(t_patcher *x) -{ - t_box *w; - if (x->p_vol) - return x->p_vol; - else if (w = (t_box *)x->p_vnewobj) - return patcher_myvol(w->b_patcher); - else - return 0; -} -#endif - -bool pybase::collect() -{ - if(gcollect) { - PyObject *ret = PyObject_CallObject(gcollect,NULL); - if(ret) { -#ifdef FLEXT_DEBUG - int refs = PyInt_AsLong(ret); - if(refs) post("py/pyext - Garbage collector reports %i unreachable objects",refs); -#endif - Py_DECREF(ret); - return false; - } - } - return true; -} - -/* -PY_EXPORT PyThreadState *py_Lock(PyThreadState *st = NULL) { return pybase::PyLock(st?st:pybase::FindThreadState()); } -PY_EXPORT PyThreadState *py_LockSys() { return pybase::PyLockSys(); } -PY_EXPORT void py_Unlock(PyThreadState *st) { pybase::PyUnlock(st); } -*/ |