summaryrefslogtreecommitdiffstats
path: root/sca-cpp
diff options
context:
space:
mode:
authorjsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68>2011-09-05 23:30:31 +0000
committerjsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68>2011-09-05 23:30:31 +0000
commitc298b01922ab03d078f33ec1ceb3e7471277f48c (patch)
treefbeebb3c73b23b841ebe3d1be9cab397e80bf0fd /sca-cpp
parent31ed46ac8dab9abaee7c74b8d8fb53bde49a317e (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')
-rwxr-xr-xsca-cpp/trunk/modules/edit/ssl-start1
-rwxr-xr-xsca-cpp/trunk/modules/edit/start1
-rw-r--r--sca-cpp/trunk/modules/python/driver.hpp12
-rw-r--r--sca-cpp/trunk/modules/python/eval.hpp282
-rw-r--r--sca-cpp/trunk/modules/python/mod-python.cpp26
-rw-r--r--sca-cpp/trunk/modules/python/mod-python.hpp11
-rw-r--r--sca-cpp/trunk/modules/python/python-test.cpp178
-rwxr-xr-xsca-cpp/trunk/modules/python/server-test1
-rwxr-xr-xsca-cpp/trunk/modules/python/wiring-test1
-rwxr-xr-xsca-cpp/trunk/samples/loan-python/start1
-rwxr-xr-xsca-cpp/trunk/samples/relay-python/start1
-rwxr-xr-xsca-cpp/trunk/samples/store-cluster/server-conf1
-rwxr-xr-xsca-cpp/trunk/samples/store-cluster/server-ssl-conf1
-rwxr-xr-xsca-cpp/trunk/samples/store-python/ssl-start1
-rwxr-xr-xsca-cpp/trunk/samples/store-python/start1
-rwxr-xr-xsca-cpp/trunk/samples/store-python/uec2-start1
-rwxr-xr-xsca-cpp/trunk/samples/store-vhost/ssl-start1
-rwxr-xr-xsca-cpp/trunk/samples/store-vhost/start1
-rwxr-xr-xsca-cpp/trunk/samples/store-vhost/uec2-start1
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