thread safe processing reason
Use TLS to ensure that concurrent scanners don't see our reason.
This commit is contained in:
@ -6,6 +6,7 @@
|
||||
#include <Python.h>
|
||||
|
||||
#include <epicsVersion.h>
|
||||
#include <epicsThread.h>
|
||||
#include <assert.h>
|
||||
#include <dbCommon.h>
|
||||
#include <dbStaticLib.h>
|
||||
@ -35,8 +36,6 @@ typedef struct {
|
||||
int rawsupport;
|
||||
|
||||
IOSCANPVT scan;
|
||||
|
||||
PyObject *reason;
|
||||
} pyDevice;
|
||||
|
||||
static long parse_link(dbCommon *prec, const char* src)
|
||||
@ -131,11 +130,13 @@ static long detach_common(dbCommon *prec)
|
||||
static long process_common(dbCommon *prec)
|
||||
{
|
||||
pyDevice *priv = prec->dpvt;
|
||||
PyObject *reason = priv->reason;
|
||||
PyObject *reason = epicsThreadPrivateGet(pyDevReasonID);
|
||||
PyObject *ret;
|
||||
|
||||
if(!reason)
|
||||
reason = Py_None;
|
||||
else
|
||||
epicsThreadPrivateSet(pyDevReasonID, NULL);
|
||||
|
||||
ret = PyObject_CallMethod(priv->support, "process", "OO", priv->pyrecord, reason);
|
||||
if(!ret)
|
||||
@ -165,11 +166,6 @@ static long report(int lvl)
|
||||
obj = priv->scanobj ? priv->scanobj : Py_None;
|
||||
printf("IOSCAN: ");
|
||||
PyObject_Print(obj, stdout, 0);
|
||||
|
||||
if(priv->reason) {
|
||||
printf("Leftover reason!: ");
|
||||
PyObject_Print(priv->reason, stdout, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
PyGILState_Release(pystate);
|
||||
@ -351,26 +347,6 @@ static long process_record2(dbCommon *prec)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int setReasonPyRecord(dbCommon *prec, PyObject *reason)
|
||||
{
|
||||
pyDevice *priv=prec->dpvt;
|
||||
if(!isPyRecord(prec) || !priv || priv->reason)
|
||||
return 0;
|
||||
Py_INCREF(reason);
|
||||
priv->reason = reason;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int clearReasonPyRecord(dbCommon *prec)
|
||||
{
|
||||
pyDevice *priv=prec->dpvt;
|
||||
if(!isPyRecord(prec) || !priv || !priv->reason)
|
||||
return 0;
|
||||
Py_DECREF(priv->reason);
|
||||
priv->reason = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static dsxt pydevsupExt = {&add_record, &del_record};
|
||||
|
||||
@ -438,8 +414,7 @@ void pyDBD_cleanup(void)
|
||||
|
||||
Py_XDECREF(priv->support);
|
||||
Py_XDECREF(priv->pyrecord);
|
||||
Py_XDECREF(priv->reason);
|
||||
priv->support = priv->pyrecord = priv->reason = NULL;
|
||||
priv->support = priv->pyrecord = NULL;
|
||||
|
||||
free(priv);
|
||||
}
|
||||
|
@ -190,7 +190,7 @@ static PyObject* pyRecord_scan(pyRecord *self, PyObject *args, PyObject *kws)
|
||||
} else {
|
||||
long ret=-1;
|
||||
int ran=0;
|
||||
setReasonPyRecord(prec, reason);
|
||||
epicsThreadPrivateSet(pyDevReasonID, reason);
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS {
|
||||
|
||||
@ -206,7 +206,7 @@ static PyObject* pyRecord_scan(pyRecord *self, PyObject *args, PyObject *kws)
|
||||
|
||||
} Py_END_ALLOW_THREADS
|
||||
|
||||
clearReasonPyRecord(prec);
|
||||
epicsThreadPrivateSet(pyDevReasonID, NULL);
|
||||
|
||||
if(ran)
|
||||
return PyLong_FromLong(ret);
|
||||
@ -247,7 +247,7 @@ static PyObject *pyRecord_asyncFinish(pyRecord *self, PyObject *args, PyObject *
|
||||
|
||||
Py_INCREF(self); /* necessary? */
|
||||
|
||||
setReasonPyRecord(prec, reason);
|
||||
epicsThreadPrivateSet(pyDevReasonID, reason);
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS {
|
||||
rset *rsup = prec->rset;
|
||||
@ -262,7 +262,7 @@ static PyObject *pyRecord_asyncFinish(pyRecord *self, PyObject *args, PyObject *
|
||||
|
||||
} Py_END_ALLOW_THREADS
|
||||
|
||||
clearReasonPyRecord(prec);
|
||||
epicsThreadPrivateSet(pyDevReasonID, NULL);
|
||||
|
||||
if(!pact) {
|
||||
PyErr_SetString(PyExc_ValueError, "Python Device record was not active");
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef PYDEVSUP_H
|
||||
#define PYDEVSUP_H
|
||||
|
||||
#include <epicsThread.h>
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
#define PyInt_FromLong PyLong_FromLong
|
||||
#define PyInt_AsLong PyLong_AsLong
|
||||
@ -23,4 +25,6 @@ int canIOScanRecord(dbCommon *);
|
||||
int setReasonPyRecord(dbCommon *, PyObject *);
|
||||
int clearReasonPyRecord(dbCommon *);
|
||||
|
||||
extern epicsThreadPrivateId pyDevReasonID;
|
||||
|
||||
#endif // PYDEVSUP_H
|
||||
|
@ -29,6 +29,8 @@ typedef struct {
|
||||
const char * const name;
|
||||
} pystate;
|
||||
|
||||
epicsThreadPrivateId pyDevReasonID;
|
||||
|
||||
#define INITST(hook) {initHook ## hook, #hook }
|
||||
static pystate statenames[] = {
|
||||
INITST(AtIocBuild),
|
||||
@ -284,6 +286,8 @@ static void cleanupPy(void *junk)
|
||||
pyField_cleanup();
|
||||
|
||||
Py_Finalize();
|
||||
|
||||
epicsThreadPrivateDelete(pyDevReasonID);
|
||||
}
|
||||
|
||||
/* Initialize the interpreter environment
|
||||
@ -384,6 +388,8 @@ static void pySetupReg(void)
|
||||
{
|
||||
PyGILState_STATE state;
|
||||
|
||||
pyDevReasonID = epicsThreadPrivateCreate();
|
||||
|
||||
setupPyInit();
|
||||
iocshRegister(&codeDef, &codeRun);
|
||||
iocshRegister(&fileDef, &fileRun);
|
||||
|
Reference in New Issue
Block a user