diff options
Diffstat (limited to 'sca-cpp/trunk/modules/python')
-rw-r--r-- | sca-cpp/trunk/modules/python/eval.hpp | 75 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/python/python-test.cpp | 37 |
2 files changed, 84 insertions, 28 deletions
diff --git a/sca-cpp/trunk/modules/python/eval.hpp b/sca-cpp/trunk/modules/python/eval.hpp index da5d226789..5c0be7d261 100644 --- a/sca-cpp/trunk/modules/python/eval.hpp +++ b/sca-cpp/trunk/modules/python/eval.hpp @@ -26,6 +26,8 @@ * Python script evaluation logic. */ #if PYTHON_VERSION == 27 +#undef _POSIX_C_SOURCE +#undef _XOPEN_SOURCE #include <python2.7/Python.h> #include <python2.7/frameobject.h> #include <python2.7/traceback.h> @@ -71,15 +73,12 @@ public: PythonRuntime() { debug("python::pythonruntime"); + // Save current process id #ifdef WANT_THREADS pthread_mutex_init(&mutex, NULL); - -#ifdef IS_DARWIN - // Save current process id pthread_mutex_init(&pidmutex, NULL); - pid = processId(); -#endif #endif + pid = processId(); // Initialize the Python interpreter #ifdef IS_DARWIN @@ -134,11 +133,9 @@ public: private: #ifdef WANT_THREADS pthread_mutex_t mutex; -#ifdef IS_DARWIN pthread_mutex_t pidmutex; - unsigned long pid; -#endif #endif + unsigned long pid; friend class PythonThreadIn; friend class PythonThreadOut; @@ -177,8 +174,8 @@ const string lastError(PythonRuntime* py) { PyObject* trace = NULL; PyErr_Fetch(&type, &val, &trace); if (type != NULL && val != NULL) { - PyObject* stype = PyObject_Str(type); - PyObject* sval = PyObject_Str(val); + PyObject* stype = PyObject_Repr(type); + PyObject* sval = PyObject_Repr(val); string msg = string() + PyString_AsString(stype) + " : " + PyString_AsString(sval) + lastErrorTrace(trace); pyDecRef(stype, py); pyDecRef(sval, py); @@ -220,11 +217,10 @@ private: class PythonThreadIn { public: PythonThreadIn(PythonRuntime* py) : py(py) { -#ifdef WANT_THREADS -#ifdef IS_DARWIN // Reinitialize Python thread support after a fork const unsigned long pid = processId(); +#ifdef WANT_THREADS if (pid != py->pid) { pthread_mutex_lock(&py->pidmutex); if (pid != py->pid) { @@ -236,16 +232,26 @@ public: } pthread_mutex_unlock(&py->pidmutex); } -#endif // Acquire the Python GIL //debug("python::gil::ensure"); gstate = PyGILState_Ensure(); //debug("python::gil::ensured"); +#else + if (pid != py->pid) { + debug("python::afterfork"); + PyOS_AfterFork(); + debug("python::afterforked"); + py->pid = pid; + } #endif } ~PythonThreadIn() { + // Run Python cyclic reference garbage collector + //const size_t c = PyGC_Collect(); + //debug(c, "python::gc::collect::c"); + #ifdef WANT_THREADS // Release the Python GIL //debug("python::gil::release"); @@ -520,7 +526,6 @@ PyObject* valueToPyObject(const value& v, PythonRuntime* py) { /** * Convert a python tuple to a list of values. */ - const list<value> pyTupleToValuesHelper(PyObject* o, const size_t i, const size_t size, PythonRuntime* py) { if (i == size) return list<value>(); @@ -546,6 +551,15 @@ struct pyCallable { pyCallable(const pyCallable& c) : func(c.func), py(c.py), owner(false) { } + const pyCallable& operator=(const pyCallable& c) { + if(this == &c) + return *this; + func = c.func; + py = c.py; + owner = false; + return *this; + } + ~pyCallable() { if (!owner) return; @@ -554,8 +568,7 @@ struct pyCallable { const value operator()(const list<value>& args) const { PythonThreadIn pyin(py); - { - // Temp + if (debug_islogging()) { PyObject* rfunc = PyObject_Repr(func); char* s = NULL; Py_ssize_t l = 0; @@ -564,8 +577,7 @@ struct pyCallable { pyDecRef(rfunc, py); } PyObject* pyargs = valuesToPyTuple(args, py); - { - // Temp + if (debug_islogging()) { PyObject* rargs = PyObject_Repr(pyargs); char* s = NULL; Py_ssize_t l = 0; @@ -573,9 +585,11 @@ struct pyCallable { debug(string(s, l), "python::operator()::args"); pyDecRef(rargs, py); } + PyObject* result = PyObject_CallObject(func, pyargs); - const value v = pyObjectToValue(result, py); pyDecRef(pyargs, py); + + const value v = pyObjectToValue(result, py); pyDecRef(result, py); return v; } @@ -605,6 +619,8 @@ const value pyObjectToValue(PyObject *o, PythonRuntime* py) { return value((double)PyFloat_AsDouble(o)); if (PyTuple_Check(o)) return pyTupleToValues(o, py); + if (PyObject_TypeCheck(o, &pyLambda_type)) + return *(((pyLambda*)o)->func); if (PyCallable_Check(o)) return lambda<value(const list<value>&)>(pyCallable(o, py)); return value(); @@ -646,10 +662,14 @@ const failable<value> evalScript(const value& expr, PyObject* script, PythonRunt // Call the function PyObject* result = PyObject_CallObject(func, args); + if (result == NULL) { + const string msg = lastError(&py); + pyDecRef(func, &py); + pyDecRef(args, &py); + return mkfailure<value>(string("Function call failed: ") + car<value>(expr) + " : " + msg); + } pyDecRef(func, &py); pyDecRef(args, &py); - if (result == NULL) - return mkfailure<value>(string("Function call failed: ") + car<value>(expr) + " : " + lastError(&py)); // Convert python result to a value const value v = pyObjectToValue(result, &py); @@ -680,10 +700,19 @@ const failable<PyObject*> readScript(const string& name, const string& path, ist return mkfailure<PyObject*>(string("Couldn't compile script: ") + path + " : " + lastError(&py)); PyObject* mod = PyImport_ExecCodeModuleEx(const_cast<char*>(c_str(name)), code, const_cast<char*>(c_str(path))); if (mod == NULL) { + const string msg = lastError(&py); pyDecRef(code, &py); - return mkfailure<PyObject*>(string("Couldn't import module: ") + path + " : " + lastError(&py)); + return mkfailure<PyObject*>(string("Couldn't import module: ") + path + " : " + msg); } - return mod; + pyDecRef(code, &py); + pyDecRef(mod, &py); + + // Lookup the loaded module + PyObject *lmod = PyDict_GetItemString(mods, const_cast<char*>(c_str(name))); + if (lmod != NULL) + return lmod; + + return mkfailure<PyObject*>(string("Couldn't lookup module: ") + path); } /** diff --git a/sca-cpp/trunk/modules/python/python-test.cpp b/sca-cpp/trunk/modules/python/python-test.cpp index bc275f27c7..29a66cc2e7 100644 --- a/sca-cpp/trunk/modules/python/python-test.cpp +++ b/sca-cpp/trunk/modules/python/python-test.cpp @@ -42,7 +42,7 @@ bool testEvalExpr() { PythonRuntime py; istringstream is(testPythonAdd); - failable<PyObject*> script = readScript("script", "script.py", is, py); + failable<PyObject*> script = readScript("script1", "script1.py", is, py); assert(hasContent(script)); const value exp = mklist<value>("add", 2, 3); @@ -54,6 +54,29 @@ bool testEvalExpr() { return true; } +const string testPythonMap = + "def addmap(x, y):\n" + " return tuple(map(lambda i: i + y, x))\n"; + +bool testEvalList() { + gc_scoped_pool pool; + PythonRuntime py; + + istringstream is(testPythonMap); + failable<PyObject*> script = readScript("script2", "script2.py", is, py); + assert(hasContent(script)); + + const value exp = mklist<value>("addmap", mklist<value>(1, 2, 3), 1); + const failable<value> r = evalScript(exp, content(script), py); + assert(hasContent(r)); + assert(car<value>(content(r)) == value(2)); + assert(cadr<value>(content(r)) == value(3)); + assert(caddr<value>(content(r)) == value(4)); + + releaseScript(content(script), py); + return true; +} + const value mult(const list<value>& args) { const double x = car(args); const double y = cadr(args); @@ -104,7 +127,7 @@ struct testEvalReadAdd { } const bool operator()() const { istringstream is(testPythonAdd); - failable<PyObject*> script = readScript("script", "script.py", is, py); + failable<PyObject*> script = readScript("script3", "script3.py", is, py); assert(hasContent(script)); const value exp = mklist<value>("add", 2, 3); @@ -139,7 +162,7 @@ bool testEvalPerf() { cout << "Python read + eval test " << time(erl, 5, 10000) << " ms" << endl; istringstream is(testPythonAdd); - failable<PyObject*> script = readScript("script", "script.py", is, py); + failable<PyObject*> script = readScript("script4", "script4.py", is, py); assert(hasContent(script)); const lambda<bool()> el = lambda<bool()>(testEvalAdd(content(script), py)); @@ -158,7 +181,7 @@ struct testReadEvalAddLoop { const bool operator()() const { for (int i = 0; i < 100; i++) { istringstream is(testPythonAdd); - failable<PyObject*> script = readScript("script", "script.py", is, py); + failable<PyObject*> script = readScript("script6", "script6.py", is, py); assert(hasContent(script)); const value exp = mklist<value>("add", 2, 3); @@ -247,7 +270,7 @@ bool testThreads() { cout << "Python eval + read thread test " << time(elr, 1, 1) / 10000.0 << " ms" << endl; istringstream is(testPythonAdd); - failable<PyObject*> script = readScript("script", "script.py", is, py); + failable<PyObject*> script = readScript("script7", "script7.py", is, py); assert(hasContent(script)); const lambda<bool()> el = lambda<bool()>(testEvalThreads(w, max, content(script), py)); @@ -263,9 +286,13 @@ bool testThreads() { } int main() { + tuscany::gc_scoped_pool p; tuscany::cout << "Testing..." << tuscany::endl; tuscany::python::testEvalExpr(); + tuscany::python::testEvalList(); + tuscany::python::testEvalLambda(); + tuscany::python::testEvalLambda(); tuscany::python::testEvalLambda(); tuscany::python::testEvalPerf(); #ifdef WANT_THREADS |