1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 <2023> 2024 | Index | 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 <2023> 2024 |
<== Date ==> | <== Thread ==> |
---|
Subject: | asynInterposeEos/StreamDevice: "read from low-level driver returned 1" and EAGAIN/EWOULDBLOCK |
From: | Érico Nogueira Rolim via Tech-talk <tech-talk at aps.anl.gov> |
To: | "tech-talk at aps.anl.gov" <tech-talk at aps.anl.gov> |
Date: | Wed, 5 Apr 2023 14:12:34 +0000 |
Hi!
I am assisting with development of an IOC for a custom device that speaks SCPI over TCP, using StreamDevice and drvAsynIPPortConfigure. We were investigating how to detect that the device had been disconnected or turned off, for which we found a solution by using an asynRecord, along with the disconnectOnReadTimeout option, as suggested in [1].
However, while debugging these options, we enabled WARNINGS with asynSetTraceMask for our port, and were faced with the following warning:
2023/04/04 17:32:32.122 BPMRFFE read from low-level driver returned 1
Investigating this warning message, I found it belonged to the asynInterposeEos interface, which I understand is what StreamDevice uses to handle its InTerminator.
For a better picture of our setup, the protocol file contains:
OutTerminator = CR LF; InTerminator = CR LF;
inPIDTdAC { out "GET:PID:Td:AC?"; in "%f"; }
And the IOC running under strace (with some filtering enabled) looked like:
[pid 1310] poll([{fd=4, events=POLLOUT}], 1, 100) = 1 ([{fd=4, revents=POLLOUT}]) [pid 1310] sendto(4, "GET:PID:Td:AC?\r\n", 16, 0, NULL, 0) = 16 [pid 1310] poll([{fd=4, events=POLLIN}], 1, 1000) = 1 ([{fd=4, revents=POLLIN}]) [pid 1310] recvfrom(4, "0", 2048, 0, NULL, NULL) = 1 [pid 1310] poll([{fd=4, events=POLLIN}], 1, 100) = 1 ([{fd=4, revents=POLLIN}]) [pid 1310] recvfrom(4, "\r\n", 2048, 0, NULL, NULL) = 2 [pid 1310] poll([{fd=4, events=POLLIN}], 1, 1) = 0 (Timeout) [pid 1310] recvfrom(4, 0x561122ff95f0, 2048, 0, NULL, NULL) = -1 EAGAIN (Resource temporarily unavailable) 2023/04/04 17:32:32.122 BPMRFFE read from low-level driver returned 1
In reading back the strace, we realized a few things:
- The drvAsynIPPort code called recv() even when poll() returned a timeout, which seems non-ideal. However, looking at the
code [2], it would seem to have been done to simplify the case for systems that don't support poll (nor select, seeing as asyn includes an emulation of poll based on select). Is that correct?
- The conditional in [3] is used to determine if we should disconnect from the device. It seems to rely on EWOULDBLOCK being the same as EAGAIN (since recv/recvfrom can return either of them [4]), which is not a guarantee -- though I don't know if it's actually the case for any platform. I wouldn't be surprised if a lot of code (in general and EPICS code specifically) relies on this assumption, but the Linux manuals recommend against it explicitly as well [5] (under ERRORS).
- asynInterposeEos's readIt is calling the underlying IPPort's read() function even though it should have matched with the
end of string already (rereading [6] made me realize this happens because of StreamDevice's input flushing); this makes it so it returns asynTimeout to StreamDevice, which I assume deals with it just fine. However, since it's flushing the input with pasynUser->timeout=0,
does it make sense for the "read from low-level driver returned 1" message to be a warning? It can easily pollute the warning output if one has a lot of SCAN records... Perhaps the message can be disabled or turned into
an ASYN_TRACE_FLOW if pasynUser->timeout==0 && status==asynTimeout ?
[1] https://epics.anl.gov/tech-talk/2019/msg00297.php
[4]
https://pubs.opengroup.org/onlinepubs/007904875/functions/recvfrom.html
[5]
https://man7.org/linux/man-pages/man2/recv.2.html
[6]
https://epics-modules.github.io/master/asyn/R4-35/RELEASE_NOTES.html
Thank you,
Érico
Aviso Legal: Esta mensagem e seus anexos podem conter informações confidenciais e/ou de uso restrito. Observe atentamente seu conteúdo e considere eventual consulta ao remetente antes de copiá-la, divulgá-la ou distribuí-la. Se você recebeu esta mensagem por engano, por favor avise o remetente e apague-a imediatamente.
Disclaimer: This email and its attachments may contain confidential and/or privileged information. Observe its content carefully and consider possible querying to the sender before copying, disclosing or distributing it. If you have received this email by mistake, please notify the sender and delete it immediately.