rework to separate out python module
Remove the magic from the magic _db* modules. Combine as one 'devsup._dbapi'. libpyDevSup exists only to bootstrap python interpreter in IOCs.
This commit is contained in:
@ -1,35 +1,31 @@
|
||||
TOP=../..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
PYMODULE = NO
|
||||
include $(TOP)/configure/CONFIG_PY
|
||||
#----------------------------------------
|
||||
# ADD MACRO DEFINITIONS AFTER THIS LINE
|
||||
#=============================
|
||||
|
||||
#=============================
|
||||
# Build the IOC application
|
||||
INSTALL_SHRLIB = $(PY_INSTALL_DIR)/devsup
|
||||
|
||||
LIBRARY = pyDevSup$(PY_LD_VER)
|
||||
LOADABLE_LIBRARY_HOST += _dbapi
|
||||
|
||||
SHRLIB_VERSION = 0
|
||||
TARGETS += $(COMMON_DIR)/pyDevSupCommon.dbd
|
||||
DBDDEPENDS_FILES += pyDevSupCommon.dbd$(DEP)
|
||||
|
||||
DBD += pyDevSup.dbd
|
||||
pyDevSupCommon_DBD += base.dbd
|
||||
|
||||
pyDevSup$(PY_LD_VER)_SYS_LIBS += python$(PY_LD_VER)
|
||||
dbapi_CPPFLAGS += -DXEPICS_ARCH=\"$(T_A)\"
|
||||
dbapi_CPPFLAGS += -DXPYDEV_BASE=\"$(abspath $(INSTALL_LOCATION))\"
|
||||
dbapi_CPPFLAGS += -DXEPICS_BASE=\"$(EPICS_BASE)\"
|
||||
dbapi_CPPFLAGS += -DPYDIR=\"python$(PY_VER)\"
|
||||
|
||||
setup_CPPFLAGS += -DXEPICS_ARCH=\"$(T_A)\"
|
||||
setup_CPPFLAGS += -DXPYDEV_BASE=\"$(abspath $(INSTALL_LOCATION))\"
|
||||
setup_CPPFLAGS += -DXEPICS_BASE=\"$(EPICS_BASE)\"
|
||||
setup_CPPFLAGS += -DPYDIR=\"python$(PY_VER)\"
|
||||
_dbapi_SRCS += dbapi.c
|
||||
_dbapi_SRCS += dbrec.c
|
||||
_dbapi_SRCS += dbfield.c
|
||||
_dbapi_SRCS += dbdset.c
|
||||
|
||||
pyDevSup$(PY_LD_VER)_SRCS += setup.c
|
||||
pyDevSup$(PY_LD_VER)_SRCS += dbbase.c
|
||||
pyDevSup$(PY_LD_VER)_SRCS += dbrec.c
|
||||
pyDevSup$(PY_LD_VER)_SRCS += dbfield.c
|
||||
pyDevSup$(PY_LD_VER)_SRCS += dbdset.c
|
||||
|
||||
pyDevSup$(PY_LD_VER)_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
_dbapi_SRCS += pyDevSupCommon_registerRecordDeviceDriver.cpp
|
||||
|
||||
PY += devsup/__init__.py
|
||||
PY += devsup/_nullapi.py
|
||||
|
@ -1,6 +1,3 @@
|
||||
/* Global interpreter setup
|
||||
*/
|
||||
|
||||
/* python has its own ideas about which version to support */
|
||||
#undef _POSIX_C_SOURCE
|
||||
#undef _XOPEN_SOURCE
|
||||
@ -21,9 +18,13 @@
|
||||
#include <epicsThread.h>
|
||||
#include <epicsExit.h>
|
||||
#include <alarm.h>
|
||||
#include <iocsh.h>
|
||||
#include <iocInit.h>
|
||||
|
||||
#include "pydevsup.h"
|
||||
|
||||
extern int pyDevSupCommon_registerRecordDeviceDriver(DBBASE *pbase);
|
||||
|
||||
typedef struct {
|
||||
const initHookState state;
|
||||
const char * const name;
|
||||
@ -102,6 +103,20 @@ void pyfile(const char* file)
|
||||
PyGILState_Release(state);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static const iocshArg argCode = {"python code", iocshArgString};
|
||||
static const iocshArg argFile = {"file", iocshArgString};
|
||||
|
||||
static const iocshArg* const codeArgs[] = {&argCode};
|
||||
static const iocshArg* const fileArgs[] = {&argFile};
|
||||
|
||||
static const iocshFuncDef codeDef = {"py", 1, codeArgs};
|
||||
static const iocshFuncDef fileDef = {"pyfile", 1, fileArgs};
|
||||
|
||||
static void codeRun(const iocshArgBuf *args){py(args[0].sval);}
|
||||
static void fileRun(const iocshArgBuf *args){pyfile(args[0].sval);}
|
||||
|
||||
initHookState pyInitLastState = (initHookState)-1;
|
||||
|
||||
static void pyhook(initHookState state)
|
||||
@ -137,28 +152,127 @@ fail:
|
||||
PyGILState_Release(gilstate);
|
||||
}
|
||||
|
||||
static
|
||||
PyObject *py_iocsh(PyObject *unused, PyObject *args, PyObject *kws)
|
||||
{
|
||||
int ret;
|
||||
static char* names[] = {"script", "cmd", NULL};
|
||||
char *script=NULL, *cmd=NULL;
|
||||
|
||||
if(!PyArg_ParseTupleAndKeywords(args, kws, "|ss", names, &script, &cmd))
|
||||
return NULL;
|
||||
|
||||
if(!(!script ^ !cmd)) {
|
||||
PyErr_SetString(PyExc_ValueError, "iocsh requires a script file name or command string");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS {
|
||||
if(script)
|
||||
ret = iocsh(script);
|
||||
else
|
||||
ret = iocshCmd(cmd);
|
||||
} Py_END_ALLOW_THREADS
|
||||
|
||||
return PyInt_FromLong(ret);
|
||||
}
|
||||
|
||||
static
|
||||
PyObject *py_dbReadDatabase(PyObject *unused, PyObject *args, PyObject *kws)
|
||||
{
|
||||
long status;
|
||||
static char* names[] = {"name", "fp", "path", "sub", NULL};
|
||||
char *fname=NULL, *path=NULL, *sub=NULL;
|
||||
int fd=-1;
|
||||
|
||||
if(!PyArg_ParseTupleAndKeywords(args, kws, "|siss", names, &fname, &fd, &path, &sub))
|
||||
return NULL;
|
||||
|
||||
if(!((!fname) ^ (fd<0))) {
|
||||
PyErr_SetString(PyExc_ValueError, "dbReadDatabase requires a file name or descriptor");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS {
|
||||
if(fname)
|
||||
status = dbReadDatabase(&pdbbase, fname, path, sub);
|
||||
else {
|
||||
FILE *ff = fdopen(fd, "r");
|
||||
status = dbReadDatabaseFP(&pdbbase, ff, path, sub);
|
||||
// dbReadDatabaseFP() has called fclose()
|
||||
}
|
||||
} Py_END_ALLOW_THREADS
|
||||
|
||||
if(status) {
|
||||
char buf[30];
|
||||
errSymLookup(status, buf, sizeof(buf));
|
||||
PyErr_SetString(PyExc_RuntimeError, buf);
|
||||
return NULL;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static
|
||||
PyObject *py_iocInit(PyObject *unused)
|
||||
{
|
||||
Py_BEGIN_ALLOW_THREADS {
|
||||
iocInit();
|
||||
} Py_END_ALLOW_THREADS
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static
|
||||
PyObject *py_pyDevSupCommon(PyObject *unused)
|
||||
{
|
||||
Py_BEGIN_ALLOW_THREADS {
|
||||
pyDevSupCommon_registerRecordDeviceDriver(pdbbase);
|
||||
} Py_END_ALLOW_THREADS
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static struct PyMethodDef dbapimethod[] = {
|
||||
{"iocsh", (PyCFunction)py_iocsh, METH_VARARGS|METH_KEYWORDS,
|
||||
"Execute IOC shell script or command"},
|
||||
{"dbReadDatabase", (PyCFunction)py_dbReadDatabase, METH_VARARGS|METH_KEYWORDS,
|
||||
"Load EPICS database file"},
|
||||
{"iocInit", (PyCFunction)py_iocInit, METH_NOARGS,
|
||||
"Initialize IOC"},
|
||||
{"_dbd_setup", (PyCFunction)pyDBD_setup, METH_NOARGS, ""},
|
||||
{"_dbd_rrd_base", (PyCFunction)py_pyDevSupCommon, METH_NOARGS, ""},
|
||||
{"_dbd_cleanup", (PyCFunction)pyDBD_cleanup, METH_NOARGS, ""},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
static struct PyModuleDef dbapimodule = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"_dbapi",
|
||||
"devsup._dbapi",
|
||||
NULL,
|
||||
-1,
|
||||
NULL
|
||||
&dbapimethod
|
||||
};
|
||||
#endif
|
||||
|
||||
/* initialize "magic" builtin module */
|
||||
PyMODINIT_FUNC init_dbapi(void)
|
||||
{
|
||||
PyObject *mod = NULL, *hookdict;
|
||||
PyObject *mod = NULL, *hookdict, *vertup, *obj;
|
||||
pystate *st;
|
||||
|
||||
pyDevReasonID = epicsThreadPrivateCreate();
|
||||
|
||||
iocshRegister(&codeDef, &codeRun);
|
||||
iocshRegister(&fileDef, &fileRun);
|
||||
initHookRegister(&pyhook);
|
||||
|
||||
import_array();
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
mod = PyModule_Create(&dbapimodule);
|
||||
#else
|
||||
mod = Py_InitModule("_dbapi", NULL);
|
||||
mod = Py_InitModule("devsup._dbapi", dbapimethod);
|
||||
#endif
|
||||
if(!mod)
|
||||
goto fail;
|
||||
@ -178,43 +292,6 @@ PyMODINIT_FUNC init_dbapi(void)
|
||||
}
|
||||
}
|
||||
|
||||
if(pyField_prepare(mod))
|
||||
goto fail;
|
||||
if(pyRecord_prepare(mod))
|
||||
goto fail;
|
||||
|
||||
MODINIT_RET(mod);
|
||||
|
||||
fail:
|
||||
fprintf(stderr, "Failed to initialize builtin _dbapi module!\n");
|
||||
Py_XDECREF(mod);
|
||||
MODINIT_RET(NULL);
|
||||
}
|
||||
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
static struct PyModuleDef constantsmodule = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"_dbconstants",
|
||||
NULL,
|
||||
-1,
|
||||
NULL
|
||||
};
|
||||
#endif
|
||||
|
||||
/* initialize "magic" builtin module */
|
||||
PyMODINIT_FUNC init_dbconstants(void)
|
||||
{
|
||||
PyObject *mod = NULL, *vertup;
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
mod = PyModule_Create(&constantsmodule);
|
||||
#else
|
||||
mod = Py_InitModule("_dbconstants", NULL);
|
||||
#endif
|
||||
if(!mod)
|
||||
MODINIT_RET(NULL);
|
||||
|
||||
PyModule_AddIntMacro(mod, NO_ALARM);
|
||||
PyModule_AddIntMacro(mod, MINOR_ALARM);
|
||||
PyModule_AddIntMacro(mod, MAJOR_ALARM);
|
||||
@ -277,150 +354,24 @@ PyMODINIT_FUNC init_dbconstants(void)
|
||||
if(vertup)
|
||||
PyModule_AddObject(mod, "pydevver", vertup);
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION>=7)
|
||||
obj = PyCapsule_New(pdbbase, "pdbbase", NULL);
|
||||
#else
|
||||
obj = PyCObject_FromVoidPtrAndDesc(pdbbase, "pdbbase", NULL);
|
||||
#endif
|
||||
if(!obj)
|
||||
goto fail;
|
||||
PyModule_AddObject(mod, "pdbbase", obj);
|
||||
|
||||
if(pyField_prepare(mod))
|
||||
goto fail;
|
||||
if(pyRecord_prepare(mod))
|
||||
goto fail;
|
||||
|
||||
MODINIT_RET(mod);
|
||||
}
|
||||
|
||||
static void cleanupPy(void *junk)
|
||||
{
|
||||
PyThreadState *state = PyGILState_GetThisThreadState();
|
||||
|
||||
PyEval_RestoreThread(state);
|
||||
|
||||
/* special "fake" hook for shutdown */
|
||||
pyhook((initHookState)9999);
|
||||
|
||||
pyDBD_cleanup();
|
||||
|
||||
pyField_cleanup();
|
||||
|
||||
Py_Finalize();
|
||||
|
||||
epicsThreadPrivateDelete(pyDevReasonID);
|
||||
}
|
||||
|
||||
/* Initialize the interpreter environment
|
||||
*/
|
||||
static void setupPyInit(void)
|
||||
{
|
||||
PyImport_AppendInittab("_dbapi", init_dbapi);
|
||||
PyImport_AppendInittab("_dbconstants", init_dbconstants);
|
||||
PyImport_AppendInittab("_dbbase", init_dbbase);
|
||||
|
||||
Py_Initialize();
|
||||
PyEval_InitThreads();
|
||||
|
||||
(void)PyEval_SaveThread();
|
||||
|
||||
epicsAtExit(&cleanupPy, NULL);
|
||||
}
|
||||
|
||||
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");
|
||||
fail:
|
||||
fprintf(stderr, "Failed to initialize builtin _dbapi module!\n");
|
||||
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);
|
||||
MODINIT_RET(NULL);
|
||||
}
|
||||
|
||||
|
||||
#include <iocsh.h>
|
||||
|
||||
static const iocshArg argCode = {"python code", iocshArgString};
|
||||
static const iocshArg argFile = {"file", iocshArgString};
|
||||
|
||||
static const iocshArg* const codeArgs[] = {&argCode};
|
||||
static const iocshArg* const fileArgs[] = {&argFile};
|
||||
|
||||
static const iocshFuncDef codeDef = {"py", 1, codeArgs};
|
||||
static const iocshFuncDef fileDef = {"pyfile", 1, fileArgs};
|
||||
|
||||
static void codeRun(const iocshArgBuf *args){py(args[0].sval);}
|
||||
static void fileRun(const iocshArgBuf *args){pyfile(args[0].sval);}
|
||||
|
||||
static void pySetupReg(void)
|
||||
{
|
||||
PyGILState_STATE state;
|
||||
|
||||
pyDevReasonID = epicsThreadPrivateCreate();
|
||||
|
||||
setupPyInit();
|
||||
iocshRegister(&codeDef, &codeRun);
|
||||
iocshRegister(&fileDef, &fileRun);
|
||||
initHookRegister(&pyhook);
|
||||
|
||||
state = PyGILState_Ensure();
|
||||
init_dbapi();
|
||||
setupPyPath();
|
||||
if(PyErr_Occurred()) {
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
}
|
||||
PyGILState_Release(state);
|
||||
}
|
||||
|
||||
#include <epicsExport.h>
|
||||
epicsExportRegistrar(pySetupReg);
|
@ -1,136 +0,0 @@
|
||||
|
||||
/* python has its own ideas about which version to support */
|
||||
#undef _POSIX_C_SOURCE
|
||||
#undef _XOPEN_SOURCE
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#include <epicsVersion.h>
|
||||
#include <dbCommon.h>
|
||||
#include <dbStaticLib.h>
|
||||
#include <dbAccess.h>
|
||||
#include <initHooks.h>
|
||||
#include <iocsh.h>
|
||||
#include <iocInit.h>
|
||||
|
||||
#include "pydevsup.h"
|
||||
|
||||
static
|
||||
PyObject *py_iocsh(PyObject *unused, PyObject *args, PyObject *kws)
|
||||
{
|
||||
int ret;
|
||||
static char* names[] = {"script", "cmd", NULL};
|
||||
char *script=NULL, *cmd=NULL;
|
||||
|
||||
if(!PyArg_ParseTupleAndKeywords(args, kws, "|ss", names, &script, &cmd))
|
||||
return NULL;
|
||||
|
||||
if(!(!script ^ !cmd)) {
|
||||
PyErr_SetString(PyExc_ValueError, "iocsh requires a script file name or command string");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS {
|
||||
if(script)
|
||||
ret = iocsh(script);
|
||||
else
|
||||
ret = iocshCmd(cmd);
|
||||
} Py_END_ALLOW_THREADS
|
||||
|
||||
return PyInt_FromLong(ret);
|
||||
}
|
||||
|
||||
static
|
||||
PyObject *py_dbReadDatabase(PyObject *unused, PyObject *args, PyObject *kws)
|
||||
{
|
||||
long status;
|
||||
static char* names[] = {"name", "fp", "path", "sub", NULL};
|
||||
char *fname=NULL, *path=NULL, *sub=NULL;
|
||||
int fd=-1;
|
||||
|
||||
if(!PyArg_ParseTupleAndKeywords(args, kws, "|siss", names, &fname, &fd, &path, &sub))
|
||||
return NULL;
|
||||
|
||||
if(!((!fname) ^ (fd<0))) {
|
||||
PyErr_SetString(PyExc_ValueError, "dbReadDatabase requires a file name or descriptor");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS {
|
||||
if(fname)
|
||||
status = dbReadDatabase(&pdbbase, fname, path, sub);
|
||||
else {
|
||||
FILE *ff = fdopen(fd, "r");
|
||||
status = dbReadDatabaseFP(&pdbbase, ff, path, sub);
|
||||
fclose(ff);
|
||||
}
|
||||
} Py_END_ALLOW_THREADS
|
||||
|
||||
if(status) {
|
||||
char buf[30];
|
||||
errSymLookup(status, buf, sizeof(buf));
|
||||
PyErr_SetString(PyExc_RuntimeError, buf);
|
||||
return NULL;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static
|
||||
PyObject *py_iocInit(PyObject *unused)
|
||||
{
|
||||
Py_BEGIN_ALLOW_THREADS {
|
||||
iocInit();
|
||||
} Py_END_ALLOW_THREADS
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static struct PyMethodDef dbbasemethods[] = {
|
||||
{"iocsh", (PyCFunction)py_iocsh, METH_VARARGS|METH_KEYWORDS,
|
||||
"Execute IOC shell script or command"},
|
||||
{"dbReadDatabase", (PyCFunction)py_dbReadDatabase, METH_VARARGS|METH_KEYWORDS,
|
||||
"Load EPICS database file"},
|
||||
{"iocInit", (PyCFunction)py_iocInit, METH_NOARGS,
|
||||
"Initialize IOC"},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
static struct PyModuleDef dbbasemodule = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"_dbbase",
|
||||
NULL,
|
||||
-1,
|
||||
&dbbasemethods
|
||||
};
|
||||
#endif
|
||||
|
||||
/* initialize "magic" builtin module */
|
||||
PyMODINIT_FUNC init_dbbase(void)
|
||||
{
|
||||
PyObject *mod = NULL, *obj = NULL;
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
mod = PyModule_Create(&dbbasemodule);
|
||||
#else
|
||||
mod = Py_InitModule("_dbbase", dbbasemethods);
|
||||
#endif
|
||||
if(!mod)
|
||||
goto fail;
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION>=7)
|
||||
obj = PyCapsule_New(pdbbase, "pdbbase", NULL);
|
||||
#else
|
||||
obj = PyCObject_FromVoidPtrAndDesc(pdbbase, "pdbbase", NULL);
|
||||
#endif
|
||||
if(!obj)
|
||||
goto fail;
|
||||
PyModule_AddObject(mod, "pdbbase", obj);
|
||||
|
||||
MODINIT_RET(mod);
|
||||
fail:
|
||||
Py_XDECREF(obj);
|
||||
Py_XDECREF(mod);
|
||||
fprintf(stderr, "Failed to initialize builtin _dbbase module!\n");
|
||||
MODINIT_RET(NULL);
|
||||
}
|
@ -19,6 +19,8 @@
|
||||
#include <dbScan.h>
|
||||
#include <cantProceed.h>
|
||||
#include <registryFunction.h>
|
||||
#include <iocshRegisterCommon.h>
|
||||
#include <registryCommon.h>
|
||||
#include <aSubRecord.h>
|
||||
|
||||
#include "pydevsup.h"
|
||||
@ -471,8 +473,28 @@ int canIOScanRecord(dbCommon *prec)
|
||||
return !!priv->scanobj;
|
||||
}
|
||||
|
||||
static
|
||||
const dset* pydsets[] = {
|
||||
&pydevsupComSpec.com,
|
||||
&pydevsupComIn.com,
|
||||
&pydevsupComOut.com,
|
||||
};
|
||||
|
||||
static const char* pydsetnames[] = {
|
||||
"pydevsupComSpec",
|
||||
"pydevsupComIn",
|
||||
"pydevsupComOut",
|
||||
};
|
||||
|
||||
PyObject* pyDBD_setup(PyObject *unused)
|
||||
{
|
||||
registerDevices(pdbbase, NELEMENTS(pydsets), pydsetnames, pydsets);
|
||||
registryFunctionAdd("python_asub", (REGISTRYFUNCTION)&python_asub);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
/* Called with GIL locked */
|
||||
void pyDBD_cleanup(void)
|
||||
PyObject* pyDBD_cleanup(PyObject *unused)
|
||||
{
|
||||
ELLNODE *cur;
|
||||
inshutdown = 1;
|
||||
@ -497,12 +519,5 @@ void pyDBD_cleanup(void)
|
||||
|
||||
free(priv);
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
#include <epicsExport.h>
|
||||
|
||||
epicsExportAddress(dset, pydevsupComSpec);
|
||||
epicsExportAddress(dset, pydevsupComIn);
|
||||
epicsExportAddress(dset, pydevsupComOut);
|
||||
|
||||
epicsRegisterFunction(python_asub);
|
||||
|
@ -569,12 +569,3 @@ int pyField_prepare(PyObject *module)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pyField_cleanup(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for(i=0; i<=DBF_MENU; i++) {
|
||||
Py_XDECREF(dbf2np[i]);
|
||||
dbf2np[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -1,28 +1,68 @@
|
||||
try:
|
||||
import _dbapi
|
||||
HAVE_DBAPI = True
|
||||
except ImportError:
|
||||
import devsup._nullapi as _dbapi
|
||||
HAVE_DBAPI = False
|
||||
import os
|
||||
import atexit
|
||||
import tempfile
|
||||
|
||||
try:
|
||||
from _dbconstants import *
|
||||
except ImportError:
|
||||
EPICS_VERSION_STRING = "EPICS 0.0.0.0-0"
|
||||
EPICS_DEV_SNAPSHOT = ""
|
||||
EPICS_SITE_VERSION = "0"
|
||||
EPICS_VERSION = 0
|
||||
EPICS_REVISION = 0
|
||||
EPICS_MODIFICATION = 0
|
||||
EPICS_PATCH_LEVEL = 0
|
||||
from . import _dbapi
|
||||
|
||||
XEPICS_ARCH = "nullos-nullarch"
|
||||
XPYDEV_BASE = "invaliddir"
|
||||
XEPICS_BASE = "invaliddir"
|
||||
|
||||
epicsver = (0,0,0,0,"0","")
|
||||
pydevver = (0,0)
|
||||
|
||||
INVALID_ALARM = UDF_ALARM = 0
|
||||
from ._dbapi import (EPICS_VERSION_STRING,
|
||||
EPICS_DEV_SNAPSHOT,
|
||||
EPICS_SITE_VERSION,
|
||||
EPICS_VERSION,
|
||||
EPICS_REVISION,
|
||||
EPICS_MODIFICATION,
|
||||
EPICS_PATCH_LEVEL,
|
||||
XEPICS_ARCH,
|
||||
XPYDEV_BASE,
|
||||
XEPICS_BASE,
|
||||
epicsver,
|
||||
pydevver,
|
||||
INVALID_ALARM,
|
||||
UDF_ALARM,
|
||||
)
|
||||
|
||||
__all__ = []
|
||||
|
||||
_ready = [False]
|
||||
|
||||
def _init(iocMain=False):
|
||||
if _ready[0]:
|
||||
return
|
||||
_ready[0] = True
|
||||
|
||||
if not iocMain:
|
||||
# we haven't read/register base.dbd
|
||||
_dbapi.dbReadDatabase(os.path.join(XEPICS_BASE, "dbd", "base.dbd"))
|
||||
_dbapi._dbd_rrd_base()
|
||||
|
||||
with tempfile.NamedTemporaryFile() as F:
|
||||
F.write("""
|
||||
device(longin, INST_IO, pydevsupComIn, "Python Device")
|
||||
device(longout, INST_IO, pydevsupComOut, "Python Device")
|
||||
|
||||
device(ai, INST_IO, pydevsupComIn, "Python Device")
|
||||
device(ao, INST_IO, pydevsupComOut, "Python Device")
|
||||
|
||||
device(stringin, INST_IO, pydevsupComIn, "Python Device")
|
||||
device(stringout, INST_IO, pydevsupComOut, "Python Device")
|
||||
|
||||
device(bi, INST_IO, pydevsupComIn, "Python Device")
|
||||
device(bo, INST_IO, pydevsupComOut, "Python Device")
|
||||
|
||||
device(mbbi, INST_IO, pydevsupComIn, "Python Device")
|
||||
device(mbbo, INST_IO, pydevsupComOut, "Python Device")
|
||||
|
||||
device(mbbiDirect, INST_IO, pydevsupComIn, "Python Device")
|
||||
device(mbboDirect, INST_IO, pydevsupComOut, "Python Device")
|
||||
|
||||
device(waveform, INST_IO, pydevsupComIn, "Python Device")
|
||||
device(aai, INST_IO, pydevsupComIn, "Python Device")
|
||||
device(aao, INST_IO, pydevsupComOut, "Python Device")
|
||||
""")
|
||||
F.flush()
|
||||
_dbapi.dbReadDatabase(F.name)
|
||||
_dbapi._dbd_setup()
|
||||
|
||||
@atexit.register
|
||||
def _fini():
|
||||
print("ATEXIT")
|
||||
_dbapi._dbd_cleanup()
|
||||
|
@ -3,10 +3,7 @@ import threading, sys, traceback, time
|
||||
|
||||
from devsup.util import Worker, importmod
|
||||
|
||||
try:
|
||||
import _dbapi
|
||||
except ImportError:
|
||||
import _nullapi as _dbapi
|
||||
from . import _dbapi
|
||||
|
||||
_rec_cache = {}
|
||||
_no_such_field = object()
|
||||
|
@ -4,10 +4,7 @@ import traceback
|
||||
from functools import wraps
|
||||
from collections import defaultdict
|
||||
|
||||
try:
|
||||
import _dbapi
|
||||
except ImportError:
|
||||
import devsup._nullapi as _dbapi
|
||||
from . import _dbapi
|
||||
|
||||
__all__ = [
|
||||
"hooknames",
|
||||
|
@ -7,8 +7,8 @@ import threading, inspect
|
||||
|
||||
_tables = {}
|
||||
|
||||
from devsup.db import IOScanListThread
|
||||
from devsup import INVALID_ALARM, UDF_ALARM
|
||||
from .db import IOScanListThread
|
||||
from . import INVALID_ALARM, UDF_ALARM
|
||||
|
||||
__all__ = [
|
||||
'Parameter',
|
||||
|
@ -1,26 +0,0 @@
|
||||
registrar(pySetupReg)
|
||||
|
||||
device(longin, INST_IO, pydevsupComIn, "Python Device")
|
||||
device(longout, INST_IO, pydevsupComOut, "Python Device")
|
||||
|
||||
device(ai, INST_IO, pydevsupComIn, "Python Device")
|
||||
device(ao, INST_IO, pydevsupComOut, "Python Device")
|
||||
|
||||
device(stringin, INST_IO, pydevsupComIn, "Python Device")
|
||||
device(stringout, INST_IO, pydevsupComOut, "Python Device")
|
||||
|
||||
device(bi, INST_IO, pydevsupComIn, "Python Device")
|
||||
device(bo, INST_IO, pydevsupComOut, "Python Device")
|
||||
|
||||
device(mbbi, INST_IO, pydevsupComIn, "Python Device")
|
||||
device(mbbo, INST_IO, pydevsupComOut, "Python Device")
|
||||
|
||||
device(mbbiDirect, INST_IO, pydevsupComIn, "Python Device")
|
||||
device(mbboDirect, INST_IO, pydevsupComOut, "Python Device")
|
||||
|
||||
device(waveform, INST_IO, pydevsupComIn, "Python Device")
|
||||
device(aai, INST_IO, pydevsupComIn, "Python Device")
|
||||
device(aao, INST_IO, pydevsupComOut, "Python Device")
|
||||
|
||||
function(python_asub)
|
||||
|
@ -17,12 +17,10 @@
|
||||
|
||||
initHookState pyInitLastState;
|
||||
|
||||
PyMODINIT_FUNC init_dbbase(void);
|
||||
|
||||
void pyDBD_cleanup(void);
|
||||
PyObject* pyDBD_setup(PyObject *unused);
|
||||
PyObject* pyDBD_cleanup(PyObject *unused);
|
||||
|
||||
int pyField_prepare(PyObject *module);
|
||||
void pyField_cleanup(void);
|
||||
|
||||
int pyRecord_prepare(PyObject *module);
|
||||
|
||||
|
@ -10,6 +10,25 @@ include $(TOP)/configure/CONFIG_PY
|
||||
#=============================
|
||||
# Build the IOC application
|
||||
|
||||
USR_CPPFLAGS += -I$(TOP)/devsupApp/src
|
||||
|
||||
LIBRARY = pyDevSup$(PY_LD_VER)
|
||||
|
||||
SHRLIB_VERSION = 0
|
||||
|
||||
DBD += pyDevSup.dbd
|
||||
|
||||
pyDevSup$(PY_LD_VER)_SYS_LIBS += python$(PY_LD_VER)
|
||||
|
||||
pyDevSup$(PY_LD_VER)_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
setup_CPPFLAGS += -DXEPICS_ARCH=\"$(T_A)\"
|
||||
setup_CPPFLAGS += -DXPYDEV_BASE=\"$(abspath $(INSTALL_LOCATION))\"
|
||||
setup_CPPFLAGS += -DXEPICS_BASE=\"$(EPICS_BASE)\"
|
||||
setup_CPPFLAGS += -DPYDIR=\"python$(PY_VER)\"
|
||||
|
||||
pyDevSup$(PY_LD_VER)_SRCS += setup.c
|
||||
|
||||
PROD_IOC = softIocPy$(PY_VER)
|
||||
PRODNAME = $(addsuffix $(EXE),$(PROD))
|
||||
|
||||
|
1
pyIocApp/pyDevSup.dbd
Normal file
1
pyIocApp/pyDevSup.dbd
Normal file
@ -0,0 +1 @@
|
||||
registrar(pySetupReg)
|
133
pyIocApp/setup.c
Normal file
133
pyIocApp/setup.c
Normal file
@ -0,0 +1,133 @@
|
||||
/* 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)
|
||||
{
|
||||
PyThreadState *state = PyGILState_GetThisThreadState();
|
||||
|
||||
PyEval_RestoreThread(state);
|
||||
|
||||
/* special "fake" hook for shutdown */
|
||||
//pyhook((initHookState)9999);
|
||||
|
||||
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 pySetupReg(void)
|
||||
{
|
||||
PyGILState_STATE state;
|
||||
|
||||
Py_Initialize();
|
||||
PyEval_InitThreads();
|
||||
|
||||
setupPyPath();
|
||||
|
||||
if(PyRun_SimpleString("import devsup\n"
|
||||
"devsup._init(True)\n"
|
||||
)) {
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
}
|
||||
|
||||
(void)PyEval_SaveThread();
|
||||
|
||||
epicsAtExit(&cleanupPy, NULL);
|
||||
}
|
||||
|
||||
#include <epicsExport.h>
|
||||
epicsExportRegistrar(pySetupReg);
|
3
test.cmd
3
test.cmd
@ -3,7 +3,6 @@
|
||||
py "import logging"
|
||||
py "logging.basicConfig(level=logging.DEBUG)"
|
||||
|
||||
py "import devsup; print devsup.HAVE_DBAPI"
|
||||
py "import sys; sys.path.insert(0,'${PWD}/testApp')"
|
||||
py "print sys.path"
|
||||
|
||||
@ -23,4 +22,4 @@ dbLoadRecords("db/test6.db","P=tst:,TNAME=tsum")
|
||||
iocInit()
|
||||
|
||||
# Start Reference tracker
|
||||
py "from devsup import disect; disect.periodic(10)"
|
||||
#py "from devsup import disect; disect.periodic(10)"
|
||||
|
Reference in New Issue
Block a user