Skip to content
Snippets Groups Projects
Commit 4c4a3fe5 authored by sjplimp's avatar sjplimp Committed by GitHub
Browse files

Merge pull request #439 from rbberger/python_mixed_use_support

Support mixed Python use by honoring Python GIL
parents ae56b9ad 1544b51d
No related branches found
No related tags found
No related merge requests found
......@@ -37,6 +37,8 @@ Python::Python(LAMMPS *lmp) : Pointers(lmp)
nfunc = 0;
pfuncs = NULL;
external_interpreter = false;
}
/* ---------------------------------------------------------------------- */
......@@ -44,6 +46,7 @@ Python::Python(LAMMPS *lmp) : Pointers(lmp)
Python::~Python()
{
// clean up
PyGILState_STATE gstate = PyGILState_Ensure();
for (int i = 0; i < nfunc; i++) {
delete [] pfuncs[i].name;
......@@ -54,7 +57,12 @@ Python::~Python()
// shutdown Python interpreter
if (pyMain) Py_Finalize();
if (pyMain && !external_interpreter) {
Py_Finalize();
}
else {
PyGILState_Release(gstate);
}
memory->sfree(pfuncs);
}
......@@ -147,27 +155,20 @@ void Python::command(int narg, char **arg)
int ifunc = create_entry(arg[0]);
// one-time initialization of Python interpreter
// Py_SetArgv() enables finding of *.py module files in current dir
// only needed for module load, not for direct file read into __main__
// pymain stores pointer to main module
PyGILState_STATE gstate;
if (pyMain == NULL) {
if (Py_IsInitialized())
error->all(FLERR,"Cannot embed Python when also "
"extending Python with LAMMPS");
external_interpreter = Py_IsInitialized();
Py_Initialize();
//char *arg = (char *) "./lmp";
//PySys_SetArgv(1,&arg);
//PyObject *pName = PyString_FromString("__main__");
//if (!pName) errorX->all(FLERR,"Bad pName");
//PyObject *pModule = PyImport_Import(pName);
//Py_DECREF(pName);
PyEval_InitThreads();
gstate = PyGILState_Ensure();
PyObject *pModule = PyImport_AddModule("__main__");
if (!pModule) error->all(FLERR,"Could not initialize embedded Python");
pyMain = (void *) pModule;
} else {
gstate = PyGILState_Ensure();
}
// send Python code to Python interpreter
......@@ -177,22 +178,44 @@ void Python::command(int narg, char **arg)
if (pyfile) {
FILE *fp = fopen(pyfile,"r");
if (fp == NULL) error->all(FLERR,"Could not open Python file");
if (fp == NULL) {
PyGILState_Release(gstate);
error->all(FLERR,"Could not open Python file");
}
int err = PyRun_SimpleFile(fp,pyfile);
if (err) error->all(FLERR,"Could not process Python file");
if (err) {
PyGILState_Release(gstate);
error->all(FLERR,"Could not process Python file");
}
fclose(fp);
} else if (herestr) {
int err = PyRun_SimpleString(herestr);
if (err) error->all(FLERR,"Could not process Python string");
if (err) {
PyGILState_Release(gstate);
error->all(FLERR,"Could not process Python string");
}
}
// pFunc = function object for requested function
PyObject *pModule = (PyObject *) pyMain;
PyObject *pFunc = PyObject_GetAttrString(pModule,pfuncs[ifunc].name);
if (!pFunc) error->all(FLERR,"Could not find Python function");
if (!PyCallable_Check(pFunc))
if (!pFunc) {
PyGILState_Release(gstate);
error->all(FLERR,"Could not find Python function");
}
if (!PyCallable_Check(pFunc)) {
PyGILState_Release(gstate);
error->all(FLERR,"Python function is not callable");
}
pfuncs[ifunc].pFunc = (void *) pFunc;
// clean-up input storage
......@@ -200,12 +223,14 @@ void Python::command(int narg, char **arg)
delete [] istr;
delete [] format;
delete [] pyfile;
PyGILState_Release(gstate);
}
/* ------------------------------------------------------------------ */
void Python::invoke_function(int ifunc, char *result)
{
PyGILState_STATE gstate = PyGILState_Ensure();
PyObject *pValue;
char *str;
......@@ -215,29 +240,43 @@ void Python::invoke_function(int ifunc, char *result)
int ninput = pfuncs[ifunc].ninput;
PyObject *pArgs = PyTuple_New(ninput);
if (!pArgs) error->all(FLERR,"Could not create Python function arguments");
if (!pArgs) {
PyGILState_Release(gstate);
error->all(FLERR,"Could not create Python function arguments");
}
for (int i = 0; i < ninput; i++) {
int itype = pfuncs[ifunc].itype[i];
if (itype == INT) {
if (pfuncs[ifunc].ivarflag[i]) {
str = input->variable->retrieve(pfuncs[ifunc].svalue[i]);
if (!str)
if (!str) {
PyGILState_Release(gstate);
error->all(FLERR,"Could not evaluate Python function input variable");
}
pValue = PyInt_FromLong(atoi(str));
} else pValue = PyInt_FromLong(pfuncs[ifunc].ivalue[i]);
} else if (itype == DOUBLE) {
if (pfuncs[ifunc].ivarflag[i]) {
str = input->variable->retrieve(pfuncs[ifunc].svalue[i]);
if (!str)
if (!str) {
PyGILState_Release(gstate);
error->all(FLERR,"Could not evaluate Python function input variable");
}
pValue = PyFloat_FromDouble(atof(str));
} else pValue = PyFloat_FromDouble(pfuncs[ifunc].dvalue[i]);
} else if (itype == STRING) {
if (pfuncs[ifunc].ivarflag[i]) {
str = input->variable->retrieve(pfuncs[ifunc].svalue[i]);
if (!str)
if (!str) {
PyGILState_Release(gstate);
error->all(FLERR,"Could not evaluate Python function input variable");
}
pValue = PyString_FromString(str);
} else pValue = PyString_FromString(pfuncs[ifunc].svalue[i]);
} else if (itype == PTR) {
......@@ -250,7 +289,12 @@ void Python::invoke_function(int ifunc, char *result)
// error check with one() since only some procs may fail
pValue = PyObject_CallObject(pFunc,pArgs);
if (!pValue) error->one(FLERR,"Python function evaluation failed");
if (!pValue) {
PyGILState_Release(gstate);
error->one(FLERR,"Python function evaluation failed");
}
Py_DECREF(pArgs);
// function returned a value
......@@ -271,6 +315,8 @@ void Python::invoke_function(int ifunc, char *result)
}
Py_DECREF(pValue);
}
PyGILState_Release(gstate);
}
/* ------------------------------------------------------------------ */
......
......@@ -21,6 +21,7 @@ namespace LAMMPS_NS {
class Python : protected Pointers {
public:
int python_exists;
bool external_interpreter;
Python(class LAMMPS *);
~Python();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment