Hi Érico,
StreamDevice expects an error when reading to flush the input and does not
complain. But I am not so sure if asynOctet finds it "normal" to get a timeout
error when pasynUser->timeout == 0. Maybe you are right and it should expect
that and not print a warning in that case.
Dirk
On Wed, 2023-04-05 at 14:12 +0000, Érico Nogueira Rolim via Tech-talk wrote:
> 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
> [2] https://github.com/epics-modules/asyn/blob/891c1f17860a82603eeceb84767975e8dd005218/asyn/drvAsynSerial/drvAsynIPPort.c#L758
> [3] https://github.com/epics-modules/asyn/blob/891c1f17860a82603eeceb84767975e8dd005218/asyn/drvAsynSerial/drvAsynIPPort.c#L799
> [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.
- References:
- asynInterposeEos/StreamDevice: "read from low-level driver returned 1" and EAGAIN/EWOULDBLOCK Érico Nogueira Rolim via Tech-talk
- Navigate by Date:
- Prev:
asynInterposeEos/StreamDevice: "read from low-level driver returned 1" and EAGAIN/EWOULDBLOCK Érico Nogueira Rolim via Tech-talk
- Next:
RE: asynInterposeEos/StreamDevice: "read from low-level driver returned 1" and EAGAIN/EWOULDBLOCK Mark Rivers via Tech-talk
- 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
- Navigate by Thread:
- Prev:
asynInterposeEos/StreamDevice: "read from low-level driver returned 1" and EAGAIN/EWOULDBLOCK Érico Nogueira Rolim via Tech-talk
- Next:
RE: asynInterposeEos/StreamDevice: "read from low-level driver returned 1" and EAGAIN/EWOULDBLOCK Mark Rivers via Tech-talk
- 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
|