diff options
author | jsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68> | 2011-09-05 23:30:31 +0000 |
---|---|---|
committer | jsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68> | 2011-09-05 23:30:31 +0000 |
commit | c298b01922ab03d078f33ec1ceb3e7471277f48c (patch) | |
tree | fbeebb3c73b23b841ebe3d1be9cab397e80bf0fd /sca-cpp | |
parent | 31ed46ac8dab9abaee7c74b8d8fb53bde49a317e (diff) |
Support multithreaded execution of Python components with the HTTPD event MPM.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1165452 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'sca-cpp')
19 files changed, 438 insertions, 85 deletions
diff --git a/sca-cpp/trunk/modules/edit/ssl-start b/sca-cpp/trunk/modules/edit/ssl-start index 53803e4ba0..576fa39463 100755 --- a/sca-cpp/trunk/modules/edit/ssl-start +++ b/sca-cpp/trunk/modules/edit/ssl-start @@ -30,6 +30,7 @@ jsprefix=`echo "import os; print os.path.realpath('$here/../js')" | python` # Configure server with virtual hosting ../../modules/http/httpd-conf tmp sca-store.com 8090 htdocs +../../modules/http/httpd-event-conf tmp ../../modules/http/vhost-conf tmp apps htdocs ../../modules/http/httpd-ssl-conf tmp 8453 ../../modules/http/vhost-ssl-conf tmp diff --git a/sca-cpp/trunk/modules/edit/start b/sca-cpp/trunk/modules/edit/start index 7d259314bf..6125ba02bf 100755 --- a/sca-cpp/trunk/modules/edit/start +++ b/sca-cpp/trunk/modules/edit/start @@ -25,6 +25,7 @@ jsprefix=`echo "import os; print os.path.realpath('$here/../js')" | python` # Configure server with virtual hosting ../../modules/http/httpd-conf tmp sca-store.com 8090 htdocs +../../modules/http/httpd-event-conf tmp ../../modules/http/vhost-conf tmp apps htdocs # Configure Python component support diff --git a/sca-cpp/trunk/modules/python/driver.hpp b/sca-cpp/trunk/modules/python/driver.hpp index 79897b0c5e..a5d554172b 100644 --- a/sca-cpp/trunk/modules/python/driver.hpp +++ b/sca-cpp/trunk/modules/python/driver.hpp @@ -35,26 +35,26 @@ namespace tuscany { namespace python { -const value evalDriverLoop(PyObject* script, istream& in, ostream& out) { +const value evalDriverLoop(PyObject* script, istream& in, ostream& out, PythonRuntime& py) { scheme::promptForInput(scheme::evalInputPrompt, out); value input = scheme::readValue(in); if (isNil(input)) return input; - const failable<value> output = evalScript(input, script); + const failable<value> output = evalScript(input, script, py); scheme::announceOutput(scheme::evalOutputPrompt, out); scheme::userPrint(content(output), out); - return evalDriverLoop(script, in, out); + return evalDriverLoop(script, in, out, py); } const bool evalDriverRun(const char* path, istream& in, ostream& out) { PythonRuntime py; scheme::setupDisplay(out); ifstream is(path); - failable<PyObject*> script = readScript(moduleName(path), path, is); + failable<PyObject*> script = readScript(moduleName(path), path, is, py); if (!hasContent(script)) return true; - evalDriverLoop(content(script), in, out); - Py_DECREF(content(script)); + evalDriverLoop(content(script), in, out, py); + releaseScript(content(script), py); return true; } diff --git a/sca-cpp/trunk/modules/python/eval.hpp b/sca-cpp/trunk/modules/python/eval.hpp index f106ff1659..a1685d11ff 100644 --- a/sca-cpp/trunk/modules/python/eval.hpp +++ b/sca-cpp/trunk/modules/python/eval.hpp @@ -37,23 +37,53 @@ namespace tuscany { namespace python { +class PythonThreadIn; +class PythonThreadOut; +class PythonRuntimeLock; + /** * Represent a Python runtime. */ + class PythonRuntime { public: PythonRuntime() { debug("python::pythonruntime"); - if (Py_IsInitialized()) - return; - Py_InitializeEx(0); - const char* arg0 = ""; - PySys_SetArgv(0, const_cast<char**>(&arg0)); + pthread_mutex_init(&modulemx, NULL); + + // Initialize the Python interpreter + if (!Py_IsInitialized()) { + debug("python::pythonruntime::initialize"); + Py_InitializeEx(0); + + // Set default interpreter args + const char* arg0 = ""; + PySys_SetArgv(0, const_cast<char**>(&arg0)); + +#ifdef WANT_THREADS + // Initialize the Python thread support + PyEval_InitThreads(); + + // Release Python lock + PyEval_ReleaseLock(); +#endif + } + } ~PythonRuntime() { debug("python::~pythonruntime"); } + +private: + +#ifdef WANT_THREADS + pthread_mutex_t modulemx; +#endif + + friend class PythonThreadIn; + friend class PythonThreadOut; + friend class PythonRuntimeLock; }; /** @@ -83,22 +113,90 @@ const string lastError() { } /** + * Represent a lock on the Python runtime. + */ +class PythonRuntimeLock { +public: + PythonRuntimeLock(PythonRuntime* py) : py(py) { +#ifdef WANT_THREADS + pthread_mutex_lock(&py->modulemx); +#endif + } + + ~PythonRuntimeLock() { +#ifdef WANT_THREADS + pthread_mutex_unlock(&py->modulemx); +#endif + } + +private: + PythonRuntime* py; +}; + +/** + * Represent a thread calling into the Python interpreter. + */ +class PythonThreadIn { +public: + PythonThreadIn(PythonRuntime* py) : py(py) { +#ifdef WANT_THREADS + //debug("python::gil::ensure"); + gstate = PyGILState_Ensure(); +#endif + } + + ~PythonThreadIn() { +#ifdef WANT_THREADS + //debug("python::gil::release"); + PyGILState_Release(gstate); +#endif + } + +private: + PythonRuntime* py; + PyGILState_STATE gstate; +}; + +/** + * Represent a thread calling out of the Python interpreter. + */ +class PythonThreadOut { +public: + PythonThreadOut(PythonRuntime* py) : py(py) { +#ifdef WANT_THREADS + //tstate = PyEval_SaveThread(); +#endif + } + + ~PythonThreadOut() { +#ifdef WANT_THREADS + //PyEval_RestoreThread(tstate); +#endif + } + +private: + PythonRuntime* py; + PyThreadState* tstate; +}; + +/** * Declare conversion functions. */ -PyObject* valueToPyObject(const value& v); -const value pyObjectToValue(PyObject *o); -PyObject* valuesToPyTuple(const list<value>& v); -const list<value> pyTupleToValues(PyObject* o); +PyObject* valueToPyObject(const value& v, PythonRuntime* py); +const value pyObjectToValue(PyObject *o, PythonRuntime* py); +PyObject* valuesToPyTuple(const list<value>& v, PythonRuntime* py); +const list<value> pyTupleToValues(PyObject* o, PythonRuntime* py); /** * Callable python type used to represent a lambda expression. */ typedef struct { - PyObject_HEAD - lambda<value(const list<value>&)> func; + PyObject_HEAD + lambda<value(const list<value>&)>* func; + PythonRuntime* py; } pyLambda; -PyObject *mkPyLambda(const lambda<value(const list<value>&)>& l); +PyObject *mkPyLambda(const lambda<value(const list<value>&)>& l, PythonRuntime* py); void pyLambda_dealloc(PyObject* self) { debug(self, "python::pylambda_dealloc"); @@ -112,12 +210,17 @@ const string pyRepr(PyObject* o) { return s; } +const value pyLambda_callout(const pyLambda* pyl, const list<value>& args, PythonRuntime* py) { + PythonThreadOut pyout(py); + return (*(pyl->func))(args); +} + PyObject* pyLambda_call(PyObject* self, PyObject* args, unused PyObject* kwds) { debug("python::call"); - const pyLambda* pyl = (pyLambda*)self; - const value result = pyl->func(pyTupleToValues(args)); + const pyLambda* pyl = (const pyLambda*)self; + const value result = pyLambda_callout(pyl, pyTupleToValues(args, pyl->py), pyl->py); debug(result, "python::call::result"); - PyObject *pyr = valueToPyObject(result); + PyObject *pyr = valueToPyObject(result, pyl->py); return pyr; } @@ -148,53 +251,89 @@ PyObject* pyLambda_getattr(PyObject *self, PyObject *attrname) { const pyLambda* pyl = (pyLambda*)self; debug(name, "python::getattr::name"); - PyObject* pyr = mkPyLambda(pyProxy(name, pyl->func)); + PyObject* pyr = mkPyLambda(pyProxy(name, *(pyl->func)), pyl->py); return pyr; } -PyTypeObject pyLambda_type = { - PyObject_HEAD_INIT(0) - 0, - "lambda", - sizeof(pyLambda), - 0, - (destructor)pyLambda_dealloc, - 0, 0, 0, 0, 0, 0, 0, 0, 0, - (ternaryfunc)pyLambda_call, - 0, - (binaryfunc)pyLambda_getattr, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0 + PyTypeObject pyLambda_type = { + PyVarObject_HEAD_INIT(NULL, 0) + "lambda", /*tp_name*/ + sizeof(pyLambda), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)pyLambda_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + (ternaryfunc)pyLambda_call, /*tp_call*/ + 0, /*tp_str*/ + (binaryfunc)pyLambda_getattr, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + 0, /*tp_init*/ + 0, /*tp_alloc*/ + 0, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ + 0, /*tp_bases*/ + 0, /*tp_mro*/ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0, /*tp_weaklist*/ + 0, /*tp_del*/ + 0 /*tp_version_tag*/ }; + /** * Create a new python object representing a lambda expression. */ -PyObject *mkPyLambda(const lambda<value(const list<value>&)>& l) { - pyLambda* pyl = NULL; - pyl = PyObject_New(pyLambda, &pyLambda_type); - if (pyl != NULL) - pyl->func = l; +PyObject *mkPyLambda(const lambda<value(const list<value>&)>& l, PythonRuntime* py) { + pyLambda* pyl = PyObject_New(pyLambda, &pyLambda_type); + if (pyl != NULL) { + pyl->func = new (gc_new<lambda<value(const list<value>&)> >()) lambda<value(const list<value>&)>(l); + pyl->py = py; + } debug(pyl, "python::mkpylambda"); - return (PyObject *)pyl; + return (PyObject*)pyl; } /** * Convert a list of values to a python list. */ -PyObject* valuesToPyListHelper(PyObject* l, const list<value>& v) { +PyObject* valuesToPyListHelper(PyObject* l, const list<value>& v, PythonRuntime* py) { if (isNil(v)) return l; - PyObject* pyv = valueToPyObject(car(v)); + PyObject* pyv = valueToPyObject(car(v), py); PyList_Append(l, pyv); Py_DECREF(pyv); - return valuesToPyListHelper(l, cdr(v)); + return valuesToPyListHelper(l, cdr(v), py); } -PyObject* valuesToPyTuple(const list<value>& v) { - PyObject* pyl = valuesToPyListHelper(PyList_New(0), v); +PyObject* valuesToPyTuple(const list<value>& v, PythonRuntime* py) { + PyObject* pyl = valuesToPyListHelper(PyList_New(0), v, py); PyObject* pyt = PyList_AsTuple(pyl); Py_DECREF(pyl); return pyt; @@ -203,12 +342,12 @@ PyObject* valuesToPyTuple(const list<value>& v) { /** * Convert a value to a python object. */ -PyObject* valueToPyObject(const value& v) { +PyObject* valueToPyObject(const value& v, PythonRuntime* py) { switch (type(v)) { case value::List: - return valuesToPyTuple(v); + return valuesToPyTuple(v, py); case value::Lambda: - return mkPyLambda(v); + return mkPyLambda(v, py); case value::Symbol: return PyString_FromString(c_str(string("'") + v)); case value::String: { @@ -228,14 +367,14 @@ PyObject* valueToPyObject(const value& v) { * Convert a python tuple to a list of values. */ -const list<value> pyTupleToValuesHelper(PyObject* o, const size_t i, const size_t size) { +const list<value> pyTupleToValuesHelper(PyObject* o, const size_t i, const size_t size, PythonRuntime* py) { if (i == size) return list<value>(); - return cons(pyObjectToValue(PyTuple_GetItem(o, i)), pyTupleToValuesHelper(o, i + 1, size)); + return cons(pyObjectToValue(PyTuple_GetItem(o, i), py), pyTupleToValuesHelper(o, i + 1, size, py)); } -const list<value> pyTupleToValues(PyObject* o) { - return pyTupleToValuesHelper(o, 0, PyTuple_Size(o)); +const list<value> pyTupleToValues(PyObject* o, PythonRuntime* py) { + return pyTupleToValuesHelper(o, 0, PyTuple_Size(o), py); } /** @@ -243,8 +382,9 @@ const list<value> pyTupleToValues(PyObject* o) { */ struct pyCallable { PyObject* func; + PythonRuntime* py; - pyCallable(PyObject* func) : func(func) { + pyCallable(PyObject* func, PythonRuntime* py) : func(func), py(py) { Py_INCREF(func); } @@ -253,9 +393,10 @@ struct pyCallable { } const value operator()(const list<value>& args) const { - PyObject* pyargs = valuesToPyTuple(args); + PythonThreadIn pyin(py); + PyObject* pyargs = valuesToPyTuple(args, py); PyObject* result = PyObject_CallObject(func, pyargs); - const value v = pyObjectToValue(result); + const value v = pyObjectToValue(result, py); Py_DECREF(pyargs); Py_DECREF(result); return v; @@ -265,7 +406,7 @@ struct pyCallable { /** * Convert a python object to a value. */ -const value pyObjectToValue(PyObject *o) { +const value pyObjectToValue(PyObject *o, PythonRuntime* py) { if (PyString_Check(o)) { char* s = NULL; Py_ssize_t l = 0; @@ -283,9 +424,9 @@ const value pyObjectToValue(PyObject *o) { if (PyFloat_Check(o)) return value((double)PyFloat_AsDouble(o)); if (PyTuple_Check(o)) - return pyTupleToValues(o); + return pyTupleToValues(o, py); if (PyCallable_Check(o)) - return lambda<value(const list<value>&)>(pyCallable(o)); + return lambda<value(const list<value>&)>(pyCallable(o, py)); return value(); } @@ -299,7 +440,8 @@ const string moduleName(const string& path) { /** * Evaluate an expression against a script provided as a python object. */ -const failable<value> evalScript(const value& expr, PyObject* script) { +const failable<value> evalScript(const value& expr, PyObject* script, PythonRuntime& py) { + PythonThreadIn pyin(&py); // Get the requested function PyObject* func = PyObject_GetAttrString(script, c_str(car<value>(expr))); @@ -320,7 +462,7 @@ const failable<value> evalScript(const value& expr, PyObject* script) { } // Convert args to python objects - PyObject* args = valuesToPyTuple(cdr<value>(expr)); + PyObject* args = valuesToPyTuple(cdr<value>(expr), &py); // Call the function PyObject* result = PyObject_CallObject(func, args); @@ -330,7 +472,7 @@ const failable<value> evalScript(const value& expr, PyObject* script) { return mkfailure<value>(string("Function call failed: ") + car<value>(expr) + " : " + lastError()); // Convert python result to a value - const value v = pyObjectToValue(result); + const value v = pyObjectToValue(result, &py); Py_DECREF(result); return v; } @@ -338,7 +480,9 @@ const failable<value> evalScript(const value& expr, PyObject* script) { /** * Read a python script from an input stream. */ -const failable<PyObject*> readScript(const string& name, const string& path, istream& is) { +const failable<PyObject*> readScript(const string& name, const string& path, istream& is, PythonRuntime& py) { + PythonThreadIn pyin(&py); + const list<string> ls = streamList(is); ostringstream os; write(ls, os); @@ -346,19 +490,31 @@ const failable<PyObject*> readScript(const string& name, const string& path, ist if (code == NULL) return mkfailure<PyObject*>(string("Couldn't compile script: ") + path + " : " + lastError()); PyObject* mod = PyImport_ExecCodeModuleEx(const_cast<char*>(c_str(name)), code, const_cast<char*>(c_str(path))); - if (mod == NULL) + if (mod == NULL) { + Py_DECREF(code); return mkfailure<PyObject*>(string("Couldn't import module: ") + path + " : " + lastError()); + } + Py_DECREF(code); return mod; } /** + * Release a python script. + */ +const failable<bool> releaseScript(PyObject* script, PythonRuntime& py) { + PythonThreadIn pyin(&py); + Py_DECREF(script); + return true; +} + +/** * Evaluate an expression against a script provided as an input stream. */ -const failable<value> evalScript(const value& expr, istream& is) { - failable<PyObject*> script = readScript("script", "script.py", is); +const failable<value> evalScript(const value& expr, istream& is, PythonRuntime& py) { + failable<PyObject*> script = readScript("script", "script.py", is, py); if (!hasContent(script)) return mkfailure<value>(reason(script)); - return evalScript(expr, content(script)); + return evalScript(expr, content(script), py); } } diff --git a/sca-cpp/trunk/modules/python/mod-python.cpp b/sca-cpp/trunk/modules/python/mod-python.cpp index 8561a1fbf4..24e0b3bcb0 100644 --- a/sca-cpp/trunk/modules/python/mod-python.cpp +++ b/sca-cpp/trunk/modules/python/mod-python.cpp @@ -39,23 +39,37 @@ namespace modeval { /** * Apply a lifecycle start or restart event. */ +struct pythonLifecycle { + python::PythonRuntime& py; + pythonLifecycle(python::PythonRuntime& py) : py(py) { + } + const value operator()(const list<value>& params) const { + const value func = car(params); + if (func == "pythonRuntime") + return (gc_ptr<value>)(value*)(void*)&py; + return lambda<value(const list<value>&)>(); + } +}; + const value applyLifecycle(unused const list<value>& params) { // Create a Python runtime - new (gc_new<python::PythonRuntime>()) python::PythonRuntime(); + python::PythonRuntime& py = *(new (gc_new<python::PythonRuntime>()) python::PythonRuntime()); - // Return a nil function as we don't need to handle the stop event - return failable<value>(lambda<value(const list<value>&)>()); + // Return the function to invoke on subsequent events + return failable<value>(lambda<value(const list<value>&)>(pythonLifecycle(py))); } /** * Evaluate a Python component implementation and convert it to an applicable * lambda function. */ -const failable<lambda<value(const list<value>&)> > evalImplementation(const string& path, const value& impl, const list<value>& px, unused const lambda<value(const list<value>&)>& lifecycle) { +const failable<lambda<value(const list<value>&)> > evalImplementation(const string& path, const value& impl, const list<value>& px, const lambda<value(const list<value>&)>& lifecycle) { const string itype(elementName(impl)); - if (contains(itype, ".python")) - return modpython::evalImplementation(path, impl, px); + if (contains(itype, ".python")) { + const void* p = (gc_ptr<value>)lifecycle(mklist<value>("pythonRuntime")); + return modpython::evalImplementation(path, impl, px, *(python::PythonRuntime*)p); + } if (contains(itype, ".cpp")) return modcpp::evalImplementation(path, impl, px); return mkfailure<lambda<value(const list<value>&)> >(string("Unsupported implementation type: ") + itype); diff --git a/sca-cpp/trunk/modules/python/mod-python.hpp b/sca-cpp/trunk/modules/python/mod-python.hpp index 0121779530..a4d77775a5 100644 --- a/sca-cpp/trunk/modules/python/mod-python.hpp +++ b/sca-cpp/trunk/modules/python/mod-python.hpp @@ -45,12 +45,13 @@ namespace modpython { struct applyImplementation { PyObject* impl; const list<value> px; - applyImplementation(PyObject* impl, const list<value>& px) : impl(impl), px(px) { + python::PythonRuntime& py; + applyImplementation(PyObject* impl, const list<value>& px, python::PythonRuntime& py) : impl(impl), px(px), py(py) { } const value operator()(const list<value>& params) const { const value expr = append<value>(params, px); debug(expr, "modeval::python::applyImplementation::input"); - const failable<value> res = python::evalScript(expr, impl); + const failable<value> res = python::evalScript(expr, impl, py); const value val = !hasContent(res)? mklist<value>(value(), reason(res)) : mklist<value>(content(res)); debug(val, "modeval::python::applyImplementation::result"); return val; @@ -61,16 +62,16 @@ struct applyImplementation { * Evaluate a Python component implementation and convert it to an applicable * lambda function. */ -const failable<lambda<value(const list<value>&)> > evalImplementation(const string& path, const value& impl, const list<value>& px) { +const failable<lambda<value(const list<value>&)> > evalImplementation(const string& path, const value& impl, const list<value>& px, python::PythonRuntime& py) { const string spath(attributeValue("script", impl)); const string fpath(path + spath); ifstream is(fpath); if (fail(is)) return mkfailure<lambda<value(const list<value>&)> >(string("Could not read implementation: ") + fpath); - const failable<PyObject*> script = python::readScript(python::moduleName(spath), fpath, is); + const failable<PyObject*> script = python::readScript(python::moduleName(spath), fpath, is, py); if (!hasContent(script)) return mkfailure<lambda<value(const list<value>&)> >(reason(script)); - return lambda<value(const list<value>&)>(applyImplementation(content(script), px)); + return lambda<value(const list<value>&)>(applyImplementation(content(script), px, py)); } } diff --git a/sca-cpp/trunk/modules/python/python-test.cpp b/sca-cpp/trunk/modules/python/python-test.cpp index 41889e6d0e..bc275f27c7 100644 --- a/sca-cpp/trunk/modules/python/python-test.cpp +++ b/sca-cpp/trunk/modules/python/python-test.cpp @@ -27,6 +27,8 @@ #include "stream.hpp" #include "string.hpp" #include "driver.hpp" +#include "parallel.hpp" +#include "perf.hpp" namespace tuscany { namespace python { @@ -40,14 +42,15 @@ bool testEvalExpr() { PythonRuntime py; istringstream is(testPythonAdd); - failable<PyObject*> script = readScript("script", "script.py", is); + failable<PyObject*> script = readScript("script", "script.py", is, py); assert(hasContent(script)); const value exp = mklist<value>("add", 2, 3); - const failable<value> r = evalScript(exp, content(script)); + const failable<value> r = evalScript(exp, content(script), py); assert(hasContent(r)); assert(content(r) == value(5)); + releaseScript(content(script), py); return true; } @@ -74,7 +77,7 @@ bool testEvalLambda() { const value trl = mklist<value>("testReturnLambda"); istringstream trlis(testReturnLambda); - const failable<value> trlv = evalScript(trl, trlis); + const failable<value> trlv = evalScript(trl, trlis, py); assert(hasContent(trlv)); assert(isLambda(content(trlv))); @@ -83,18 +86,179 @@ bool testEvalLambda() { istringstream tclis(testCallLambda); const value tcl = mklist<value>("testCallLambda", content(trlv), 2, 3); - const failable<value> tclv = evalScript(tcl, tclis); + const failable<value> tclv = evalScript(tcl, tclis, py); assert(hasContent(tclv)); assert(content(tclv) == value(6)); istringstream tcelis(testCallLambda); const value tcel = mklist<value>("testCallLambda", lambda<value(const list<value>&)>(mult), 3, 4); - const failable<value> tcelv = evalScript(tcel, tcelis); + const failable<value> tcelv = evalScript(tcel, tcelis, py); assert(hasContent(tcelv)); assert(content(tcelv) == value(12)); return true; } +struct testEvalReadAdd { + PythonRuntime& py; + testEvalReadAdd(PythonRuntime& py) : py(py) { + } + const bool operator()() const { + istringstream is(testPythonAdd); + failable<PyObject*> script = readScript("script", "script.py", is, py); + assert(hasContent(script)); + + const value exp = mklist<value>("add", 2, 3); + const failable<value> r = evalScript(exp, content(script), py); + assert(hasContent(r)); + assert(content(r) == value(5)); + + releaseScript(content(script), py); + return true; + } +}; + +struct testEvalAdd { + PyObject* script; + PythonRuntime& py; + testEvalAdd(PyObject* script, PythonRuntime& py) : script(script), py(py) { + } + const bool operator()() const { + const value exp = mklist<value>("add", 2, 3); + const failable<value> r = evalScript(exp, script, py); + assert(hasContent(r)); + assert(content(r) == value(5)); + return true; + } +}; + +bool testEvalPerf() { + gc_scoped_pool pool; + PythonRuntime py; + + const lambda<bool()> erl = lambda<bool()>(testEvalReadAdd(py)); + cout << "Python read + eval test " << time(erl, 5, 10000) << " ms" << endl; + + istringstream is(testPythonAdd); + failable<PyObject*> script = readScript("script", "script.py", is, py); + assert(hasContent(script)); + + const lambda<bool()> el = lambda<bool()>(testEvalAdd(content(script), py)); + cout << "Python eval test " << time(el, 5, 10000) << " ms" << endl; + + releaseScript(content(script), py); + return true; +} + +#ifdef WANT_THREADS + +struct testReadEvalAddLoop { + PythonRuntime& py; + testReadEvalAddLoop(PythonRuntime& py) : py(py) { + } + const bool operator()() const { + for (int i = 0; i < 100; i++) { + istringstream is(testPythonAdd); + failable<PyObject*> script = readScript("script", "script.py", is, py); + assert(hasContent(script)); + + const value exp = mklist<value>("add", 2, 3); + const failable<value> r = evalScript(exp, content(script), py); + assert(hasContent(r)); + assert(content(r) == value(5)); + + releaseScript(content(script), py); + } + return true; + } +}; + +struct testEvalAddLoop { + PyObject* script; + PythonRuntime& py; + testEvalAddLoop(PyObject* script, PythonRuntime& py) : script(script), py(py) { + } + const bool operator()() const { + for (int i = 0; i < 100; i++) { + const value exp = mklist<value>("add", 2, 3); + const failable<value> r = evalScript(exp, script, py); + assert(hasContent(r)); + assert(content(r) == value(5)); + } + return true; + } +}; + +const list<future<bool> > submitReadEvals(worker& w, const int max, const int i, PythonRuntime& py) { + if (i == max) + return list<future<bool> >(); + const lambda<bool()> func = lambda<bool()>(testReadEvalAddLoop(py)); + return cons(submit(w, func), submitReadEvals(w, max, i + 1, py)); +} + +const list<future<bool> > submitEvals(worker& w, const int max, const int i, PyObject* script, PythonRuntime& py) { + if (i == max) + return list<future<bool> >(); + const lambda<bool()> func = lambda<bool()>(testEvalAddLoop(script, py)); + return cons(submit(w, func), submitEvals(w, max, i + 1, script, py)); +} + +bool checkEvalResults(const list<future<bool> > r) { + if (isNil(r)) + return true; + assert(car(r) == true); + return checkEvalResults(cdr(r)); +} + +struct testReadEvalThreads { + worker& w; + const int max; + PythonRuntime& py; + testReadEvalThreads(worker& w, const int max, PythonRuntime& py) : w(w), max(max), py(py) { + } + const bool operator()() const { + const list<future<bool> > r(submitReadEvals(w, max, 0, py)); + checkEvalResults(r); + return true; + } +}; + +struct testEvalThreads { + worker& w; + const int max; + PyObject* script; + PythonRuntime& py; + testEvalThreads(worker& w, const int max, PyObject* script, PythonRuntime& py) : w(w), max(max), script(script), py(py) { + } + const bool operator()() const { + const list<future<bool> > r(submitEvals(w, max, 0, script, py)); + checkEvalResults(r); + return true; + } +}; + +bool testThreads() { + gc_scoped_pool pool; + PythonRuntime py; + + const int max = 100; + worker w(max); + + const lambda<bool()> elr = lambda<bool()>(testReadEvalThreads(w, max, py)); + 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); + assert(hasContent(script)); + + const lambda<bool()> el = lambda<bool()>(testEvalThreads(w, max, content(script), py)); + cout << "Python eval thread test " << time(el, 1, 1) / 10000.0 << " ms" << endl; + + releaseScript(content(script), py); + return true; +} + +#endif + } } @@ -103,6 +267,10 @@ int main() { tuscany::python::testEvalExpr(); tuscany::python::testEvalLambda(); + tuscany::python::testEvalPerf(); +#ifdef WANT_THREADS + tuscany::python::testThreads(); +#endif tuscany::cout << "OK" << tuscany::endl; return 0; diff --git a/sca-cpp/trunk/modules/python/server-test b/sca-cpp/trunk/modules/python/server-test index 0932413ffd..ecde5ca8ad 100755 --- a/sca-cpp/trunk/modules/python/server-test +++ b/sca-cpp/trunk/modules/python/server-test @@ -19,6 +19,7 @@ # Setup ../http/httpd-conf tmp localhost 8090 ../server/htdocs +../http/httpd-event-conf tmp ../server/server-conf tmp ./python-conf tmp cat >>tmp/conf/httpd.conf <<EOF diff --git a/sca-cpp/trunk/modules/python/wiring-test b/sca-cpp/trunk/modules/python/wiring-test index 22666c3925..4dd3ca7228 100755 --- a/sca-cpp/trunk/modules/python/wiring-test +++ b/sca-cpp/trunk/modules/python/wiring-test @@ -23,6 +23,7 @@ curl_prefix=`cat $here/../http/curl.prefix` # Setup ../http/httpd-conf tmp localhost 8090 ../server/htdocs +../http/httpd-event-conf tmp ../server/server-conf tmp ./python-conf tmp cat >>tmp/conf/httpd.conf <<EOF diff --git a/sca-cpp/trunk/samples/loan-python/start b/sca-cpp/trunk/samples/loan-python/start index e7aa7d86ca..499a48cc4a 100755 --- a/sca-cpp/trunk/samples/loan-python/start +++ b/sca-cpp/trunk/samples/loan-python/start @@ -18,6 +18,7 @@ # under the License. ../../modules/http/httpd-conf tmp localhost 8090 htdocs +../../modules/http/httpd-event-conf tmp ../../modules/server/server-conf tmp ../../modules/python/python-conf tmp cat >>tmp/conf/httpd.conf <<EOF diff --git a/sca-cpp/trunk/samples/relay-python/start b/sca-cpp/trunk/samples/relay-python/start index c156e43a52..e9d9d2d51f 100755 --- a/sca-cpp/trunk/samples/relay-python/start +++ b/sca-cpp/trunk/samples/relay-python/start @@ -18,6 +18,7 @@ # under the License. ../../modules/http/httpd-conf tmp localhost 8090 htdocs +../../modules/http/httpd-event-conf tmp ../../modules/server/server-conf tmp ../../modules/python/python-conf tmp cat >>tmp/conf/httpd.conf <<EOF diff --git a/sca-cpp/trunk/samples/store-cluster/server-conf b/sca-cpp/trunk/samples/store-cluster/server-conf index babf2f2ef3..f65ba37d3a 100755 --- a/sca-cpp/trunk/samples/store-cluster/server-conf +++ b/sca-cpp/trunk/samples/store-cluster/server-conf @@ -24,6 +24,7 @@ set -x # Configure an app server ../../modules/http/httpd-conf $root sca-store.com $port/80 htdocs +../../modules/http/httpd-event-conf $root ../../modules/http/vhost-conf $root domains htdocs ../../modules/server/server-conf $root ../../modules/python/python-conf $root diff --git a/sca-cpp/trunk/samples/store-cluster/server-ssl-conf b/sca-cpp/trunk/samples/store-cluster/server-ssl-conf index 56ca5edc8c..83628bbacd 100755 --- a/sca-cpp/trunk/samples/store-cluster/server-ssl-conf +++ b/sca-cpp/trunk/samples/store-cluster/server-ssl-conf @@ -25,6 +25,7 @@ set -x # Configure an SSL-enabled app server ../../modules/http/httpd-conf $root sca-store.com $port htdocs +../../modules/http/httpd-event-conf $root ../../modules/http/vhost-conf $root domains htdocs tar -C tmp/ssl -c `../../modules/http/ssl-cert-find tmp/ssl` | tar -C $root -x diff --git a/sca-cpp/trunk/samples/store-python/ssl-start b/sca-cpp/trunk/samples/store-python/ssl-start index 60b9bb5ace..e639b538d8 100755 --- a/sca-cpp/trunk/samples/store-python/ssl-start +++ b/sca-cpp/trunk/samples/store-python/ssl-start @@ -20,6 +20,7 @@ ../../modules/http/ssl-ca-conf tmp localhost ../../modules/http/ssl-cert-conf tmp localhost ../../modules/http/httpd-conf tmp localhost 8090 htdocs +../../modules/http/httpd-event-conf tmp ../../modules/http/httpd-ssl-conf tmp 8453 ../../modules/http/open-auth-conf tmp ../../modules/http/passwd-auth-conf tmp foo foo diff --git a/sca-cpp/trunk/samples/store-python/start b/sca-cpp/trunk/samples/store-python/start index 8df7875634..b4ca1461fd 100755 --- a/sca-cpp/trunk/samples/store-python/start +++ b/sca-cpp/trunk/samples/store-python/start @@ -18,6 +18,7 @@ # under the License. ../../modules/http/httpd-conf tmp localhost 8090 htdocs +../../modules/http/httpd-event-conf tmp ../../modules/server/server-conf tmp ../../modules/python/python-conf tmp cat >>tmp/conf/httpd.conf <<EOF diff --git a/sca-cpp/trunk/samples/store-python/uec2-start b/sca-cpp/trunk/samples/store-python/uec2-start index 84c170e596..53428be0bf 100755 --- a/sca-cpp/trunk/samples/store-python/uec2-start +++ b/sca-cpp/trunk/samples/store-python/uec2-start @@ -31,6 +31,7 @@ sudo ../../ubuntu/ip-redirect-all 443 8453 ../../modules/http/ssl-ca-conf tmp $host ../../modules/http/ssl-cert-conf tmp $host ../../modules/http/httpd-conf tmp $host 8090/80 htdocs +../../modules/http/httpd-event-conf tmp ../../modules/http/httpd-ssl-conf tmp 8453/443 ../../modules/server/server-conf tmp ../../modules/python/python-conf tmp diff --git a/sca-cpp/trunk/samples/store-vhost/ssl-start b/sca-cpp/trunk/samples/store-vhost/ssl-start index ddff91eafb..3a6bb82bd8 100755 --- a/sca-cpp/trunk/samples/store-vhost/ssl-start +++ b/sca-cpp/trunk/samples/store-vhost/ssl-start @@ -24,6 +24,7 @@ ../../modules/http/ssl-cert-conf tmp sca-store.com server ../../modules/http/ssl-cert-conf tmp *.sca-store.com vhost ../../modules/http/httpd-conf tmp sca-store.com 8090 htdocs +../../modules/http/httpd-event-conf tmp ../../modules/http/vhost-conf tmp domains htdocs ../../modules/http/httpd-ssl-conf tmp 8453 ../../modules/http/vhost-ssl-conf tmp diff --git a/sca-cpp/trunk/samples/store-vhost/start b/sca-cpp/trunk/samples/store-vhost/start index c8bb6854f8..38661e711c 100755 --- a/sca-cpp/trunk/samples/store-vhost/start +++ b/sca-cpp/trunk/samples/store-vhost/start @@ -18,6 +18,7 @@ # under the License. ../../modules/http/httpd-conf tmp sca-store.com 8090 htdocs +../../modules/http/httpd-event-conf tmp ../../modules/http/vhost-conf tmp domains htdocs ../../modules/server/server-conf tmp ../../modules/python/python-conf tmp diff --git a/sca-cpp/trunk/samples/store-vhost/uec2-start b/sca-cpp/trunk/samples/store-vhost/uec2-start index e8b30af0dc..f7208b7403 100755 --- a/sca-cpp/trunk/samples/store-vhost/uec2-start +++ b/sca-cpp/trunk/samples/store-vhost/uec2-start @@ -33,6 +33,7 @@ sudo ../../ubuntu/ip-redirect-all 443 8453 ../../modules/http/ssl-cert-conf tmp $host server ../../modules/http/ssl-cert-conf tmp "*.$host" vhost ../../modules/http/httpd-conf tmp $host 8090/80 htdocs +../../modules/http/httpd-event-conf tmp ../../modules/http/vhost-conf tmp domains htdocs ../../modules/http/httpd-ssl-conf tmp 8453/443 ../../modules/http/vhost-ssl-conf tmp |