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