Files
pyDevSup/pyIocApp/setup.c
Michael Davidsaver c4a1c7deea delay registering second cleanupPy()
until just _before_ exitDatabase, to ensure
that cleanup happens _after_ devSup detach().

Still allows devSup build() the opportunity
to add epicsAtExit() which happen between
cac cleanup and our cleanup.
2019-05-06 11:36:48 -07:00

154 lines
3.3 KiB
C

/* Global interpreter setup
*/
/* python has its own ideas about which version to support */
#undef _POSIX_C_SOURCE
#undef _XOPEN_SOURCE
#include <Python.h>
#ifdef HAVE_NUMPY
#include <numpy/ndarrayobject.h>
#endif
#include <stdio.h>
#include <epicsVersion.h>
#include <dbCommon.h>
#include <dbAccess.h>
#include <dbStaticLib.h>
#include <dbScan.h>
#include <initHooks.h>
#include <epicsThread.h>
#include <epicsExit.h>
#include <alarm.h>
#include "pydevsup.h"
static void cleanupPy(void *junk)
{
/* safe because exit hooks are only run once, from a single thread */
static int done;
if(done) return;
done = 1;
PyThreadState *state = PyGILState_GetThisThreadState();
PyEval_RestoreThread(state);
if(PyRun_SimpleString("import devsup\n"
"devsup._fini(iocMain=True)\n"
)) {
PyErr_Print();
PyErr_Clear();
}
Py_Finalize(); // calls python atexit hooks
}
static void extendPath(PyObject *list,
const char *base,
const char *archdir)
{
PyObject *mod, *ret;
mod = PyImport_ImportModule("os.path");
if(!mod)
return;
ret = PyObject_CallMethod(mod, "join", "sss", base, PYDIR, archdir);
if(ret && !PySequence_Contains(list, ret)) {
PyList_Insert(list, 0, ret);
}
Py_XDECREF(ret);
Py_DECREF(mod);
if(PyErr_Occurred()) {
PyErr_Print();
PyErr_Clear();
}
}
static void insertDefaultPath(PyObject *list)
{
const char *basedir, *pydevdir, *top, *arch;
basedir = getenv("EPICS_BASE");
if(!basedir)
basedir = XEPICS_BASE;
pydevdir = getenv("PYDEV_BASE");
if(!pydevdir)
pydevdir = XPYDEV_BASE;
top = getenv("TOP");
arch = getenv("ARCH");
if(!arch)
arch = XEPICS_ARCH;
assert(PyList_Check(list));
assert(PySequence_Check(list));
extendPath(list, basedir, arch);
extendPath(list, pydevdir, arch);
if(top)
extendPath(list, top, arch);
}
static void setupPyPath(void)
{
PyObject *mod, *path = NULL;
mod = PyImport_ImportModule("sys");
if(mod)
path = PyObject_GetAttrString(mod, "path");
Py_XDECREF(mod);
if(path) {
PyObject *cur;
char cwd[PATH_MAX];
insertDefaultPath(path);
/* prepend current directory */
if(getcwd(cwd, sizeof(cwd)-1)) {
cwd[sizeof(cwd)-1] = '\0';
cur = PyString_FromString(cwd);
if(cur)
PyList_Insert(path, 0, cur);
Py_XDECREF(cur);
}
}
Py_XDECREF(path);
}
static void cleanupPrep(initHookState state)
{
/* register a second time to better our chances of running
* first on exit. eg. before cacExitHandler()
*/
if(state==initHookAfterInitDevSup)
epicsAtExit(&cleanupPy, NULL);
}
static void pySetupReg(void)
{
Py_InitializeEx(0);
PyEval_InitThreads();
setupPyPath();
if(PyRun_SimpleString("import devsup\n"
"devsup._init(iocMain=True)\n"
)) {
PyErr_Print();
PyErr_Clear();
}
(void)PyEval_SaveThread();
/* register first time to ensure cleanupPy is run at least once */
epicsAtExit(&cleanupPy, NULL);
initHookRegister(&cleanupPrep);
}
#include <epicsExport.h>
epicsExportRegistrar(pySetupReg);