Skip to content

Commit

Permalink
Merge pull request #17 from mattgibbs/master
Browse files Browse the repository at this point in the history
Fix deadlocks and improve no-timeout get() calls.
  • Loading branch information
ZLLentz authored May 10, 2022
2 parents 0f92412 + 9606d97 commit eff926b
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 9 deletions.
25 changes: 18 additions & 7 deletions psp/Pv.py
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ def disconnect(self):
self.isconnected = False

def monitor(self, mask=pyca.DBE_VALUE | pyca.DBE_LOG | pyca.DBE_ALARM,
ctrl=None, count=None):
ctrl=None, count=None, wait_for_init=True):
"""
Subscribe to monitor events from the PV channel
Expand All @@ -458,6 +458,11 @@ def monitor(self, mask=pyca.DBE_VALUE | pyca.DBE_LOG | pyca.DBE_ALARM,
count : int, optional
Subsection of waveform record to monitor. By default,
:attr:`.count` is used
wait_for_init : bool, optional
Whether to wait for an initial value to arrive for the PV before
returning. If False, the PV's value and metadata might not be
populated when this function returns. Defaults to True.
See Also
--------
Expand Down Expand Up @@ -485,10 +490,11 @@ def monitor(self, mask=pyca.DBE_VALUE | pyca.DBE_LOG | pyca.DBE_ALARM,
#
# The purpose of this step is to initialize the .value when we call
# .monitor() in an interactive session.
try:
self.get()
except pyca.caexc:
pass
if wait_for_init:
try:
self.get()
except pyca.caexc:
pass

self.ismonitored = True

Expand Down Expand Up @@ -525,7 +531,9 @@ def get(self, count=None, timeout=DEFAULT_TIMEOUT, as_string=False, **kw):
Whether to get the control form information
timeout : float or None, optional
Time to wait for data to be returned. If None, no timeout is used
Time to wait for data to be returned. If None, no timeout is used.
If timeout is None, this method may return None if the PV's
value has not arrived yet.
as_string : bool , optional
Return the value as a string type. For Enum PVs, the default
Expand Down Expand Up @@ -574,6 +582,10 @@ def get(self, count=None, timeout=DEFAULT_TIMEOUT, as_string=False, **kw):
if tmo > 0 and DEBUG != 0:
logprint("got %s\n" % self.value.__str__())

if "value" not in self.data:
# If the timeout was None, there's a chance that the value hasn't arrived yet.
return None

if as_string:
if self.type() == 'DBF_ENUM':
enums = self.get_enum_set(timeout=tmo)
Expand All @@ -584,7 +596,6 @@ def get(self, count=None, timeout=DEFAULT_TIMEOUT, as_string=False, **kw):
'of {:}'.format(self.value, self.name))
else:
return str(self.value)

return self.value

def put(self, value, timeout=DEFAULT_TIMEOUT, **kw):
Expand Down
6 changes: 4 additions & 2 deletions pyca/pyca.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,13 @@ extern "C" {
static PyObject* clear_channel(PyObject* self, PyObject*)
{
capv* pv = reinterpret_cast<capv*>(self);

chid cid = pv->cid;
if (!cid) {
pyca_raise_pyexc_pv("clear_channel", "channel is null", pv);
}
PyThreadState *state = PyEval_SaveThread();
int result = ca_clear_channel(cid);
PyEval_RestoreThread(state);
if (result != ECA_NORMAL) {
pyca_raise_caexc_pv("ca_clear_channel", result, pv);
}
Expand Down Expand Up @@ -124,7 +125,7 @@ extern "C" {
pv->didmon = 0;
Py_RETURN_NONE;
}

PyThreadState *state = PyEval_SaveThread();
evid eid = pv->eid;
if (eid) {
int result = ca_clear_subscription(eid);
Expand All @@ -133,6 +134,7 @@ extern "C" {
}
pv->eid = 0;
}
PyEval_RestoreThread(state);
Py_RETURN_NONE;
}

Expand Down

0 comments on commit eff926b

Please # to comment.