support async processing

This commit is contained in:
Michael Davidsaver
2013-03-30 15:47:34 -04:00
parent d3a298cd7c
commit 67fe8ad82f
3 changed files with 85 additions and 4 deletions

View File

@ -216,6 +216,7 @@ static long process_record(dbCommon *prec)
{
pyDevice *priv = prec->dpvt;
PyGILState_STATE pystate;
long pact = prec->pact;
if(!priv || !priv->support)
return 0;
@ -227,6 +228,10 @@ static long process_record(dbCommon *prec)
PyErr_Clear();
}
/* always clear PACT if it was initially set */
if(pact)
prec->pact = 0;
PyGILState_Release(pystate);
return 0;
}

View File

@ -9,6 +9,7 @@
#include <dbCommon.h>
#include <dbAccess.h>
#include <dbStaticLib.h>
#include <recSup.h>
#include <dbScan.h>
#include "pydevsup.h"
@ -132,21 +133,81 @@ static PyObject* pyRecord_scan(pyRecord *self, PyObject *args, PyObject *kws)
if(!PyObject_IsTrue(sync)) {
scanOnce(prec);
Py_RETURN_NONE;
} else {
long ret;
setCausePyRecord(prec, reason);
Py_BEGIN_ALLOW_THREADS {
dbScanLock(prec);
dbProcess(prec);
ret = dbProcess(prec);
dbScanUnlock(prec);
} Py_END_ALLOW_THREADS
clearCausePyRecord(prec);
return PyLong_FromLong(ret);
}
}
static PyObject *pyRecord_asyncStart(pyRecord *self)
{
dbCommon *prec=self->entry.precnode->precord;
epicsUInt8 pact = prec->pact;
if(!isPyRecord(prec)) {
PyErr_SetString(PyExc_RuntimeError, "Not a Python Device record");
return NULL;
}
prec->pact = 1;
return PyLong_FromLong(pact);
}
static PyObject *pyRecord_asyncFinish(pyRecord *self, PyObject *args, PyObject *kws)
{
long pact, ret;
dbCommon *prec = self->entry.precnode->precord;
static char* names[] = {"reason", NULL};
PyObject *reason = Py_None;
if(!PyArg_ParseTupleAndKeywords(args, kws, "|O", names, &reason))
return NULL;
if(!isPyRecord(prec)) {
PyErr_SetString(PyExc_RuntimeError, "Not a Python Device record");
return NULL;
}
Py_RETURN_NONE;
Py_INCREF(self);
setCausePyRecord(prec, reason);
Py_BEGIN_ALLOW_THREADS {
rset *rsup = prec->rset;
dbScanLock(prec);
pact = prec->pact;
if(pact) {
ret = (*rsup->process)(prec);
/* Out devsup always clears PACT if initially set */
}
dbScanUnlock(prec);
} Py_END_ALLOW_THREADS
clearCausePyRecord(prec);
if(!pact) {
PyErr_SetString(PyExc_ValueError, "Python Device record was not active");
return NULL;
}
Py_DECREF(self);
return PyLong_FromLong(ret);
}
static PyMethodDef pyRecord_methods[] = {
@ -159,8 +220,11 @@ static PyMethodDef pyRecord_methods[] = {
{"scan", (PyCFunction)pyRecord_scan, METH_VARARGS|METH_KEYWORDS,
"scan(sync=False)\nScan this record. If sync is False then"
"a scan request is queued. If sync is True then the record"
"is scannined immidately on the current thread."
},
"is scannined immidately on the current thread."},
{"asyncStart", (PyCFunction)pyRecord_asyncStart, METH_NOARGS,
"Begin an asynchronous action. Record must be locked!"},
{"asyncFinish", (PyCFunction)pyRecord_asyncFinish, METH_VARARGS|METH_KEYWORDS,
"Complete an asynchronous action. Record must *not* be locked!"},
{NULL, NULL, 0, NULL}
};

View File

@ -1,12 +1,23 @@
import weakref
import threading, time
from devsup.hooks import addHook
insts = {}
def done(obj):
print obj,'Expires'
_tracking = {}
def track(obj):
W = weakref.ref(obj, done)
print 'track',obj,'with',W
_tracking[id(obj)] = W
class Driver(threading.Thread):
def __init__(self, name):
super(Driver,self).__init__()
track(self)
self.name = name
self._lock = threading.Lock()
self._recs = set()
@ -48,6 +59,7 @@ def addDrv(name):
class Device(object):
def __init__(self, rec, drv):
track(self)
self.driver, self.record = drv, rec
self.driver.addrec(self)
self.val = rec.field('VAL')