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

View File

@ -9,6 +9,7 @@
#include <dbCommon.h> #include <dbCommon.h>
#include <dbAccess.h> #include <dbAccess.h>
#include <dbStaticLib.h> #include <dbStaticLib.h>
#include <recSup.h>
#include <dbScan.h> #include <dbScan.h>
#include "pydevsup.h" #include "pydevsup.h"
@ -132,21 +133,81 @@ static PyObject* pyRecord_scan(pyRecord *self, PyObject *args, PyObject *kws)
if(!PyObject_IsTrue(sync)) { if(!PyObject_IsTrue(sync)) {
scanOnce(prec); scanOnce(prec);
Py_RETURN_NONE;
} else { } else {
long ret;
setCausePyRecord(prec, reason); setCausePyRecord(prec, reason);
Py_BEGIN_ALLOW_THREADS { Py_BEGIN_ALLOW_THREADS {
dbScanLock(prec); dbScanLock(prec);
dbProcess(prec); ret = dbProcess(prec);
dbScanUnlock(prec); dbScanUnlock(prec);
} Py_END_ALLOW_THREADS } Py_END_ALLOW_THREADS
clearCausePyRecord(prec); 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[] = { static PyMethodDef pyRecord_methods[] = {
@ -159,8 +220,11 @@ static PyMethodDef pyRecord_methods[] = {
{"scan", (PyCFunction)pyRecord_scan, METH_VARARGS|METH_KEYWORDS, {"scan", (PyCFunction)pyRecord_scan, METH_VARARGS|METH_KEYWORDS,
"scan(sync=False)\nScan this record. If sync is False then" "scan(sync=False)\nScan this record. If sync is False then"
"a scan request is queued. If sync is True then the record" "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} {NULL, NULL, 0, NULL}
}; };

View File

@ -1,12 +1,23 @@
import weakref
import threading, time import threading, time
from devsup.hooks import addHook from devsup.hooks import addHook
insts = {} 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): class Driver(threading.Thread):
def __init__(self, name): def __init__(self, name):
super(Driver,self).__init__() super(Driver,self).__init__()
track(self)
self.name = name self.name = name
self._lock = threading.Lock() self._lock = threading.Lock()
self._recs = set() self._recs = set()
@ -48,6 +59,7 @@ def addDrv(name):
class Device(object): class Device(object):
def __init__(self, rec, drv): def __init__(self, rec, drv):
track(self)
self.driver, self.record = drv, rec self.driver, self.record = drv, rec
self.driver.addrec(self) self.driver.addrec(self)
self.val = rec.field('VAL') self.val = rec.field('VAL')