From: David Gravereaux on
Hi,

I'm writing a GPIB channel driver extension and was wondering what the
proper error code I should return for a timeout from a blocking read?

I was thinking EWOULDBLOCK seems correct, but I'm not sure. The read
call, Receive() <http://linux-gpib.sourceforge.net/doc_html/r2741.html>
can return a status
<http://linux-gpib.sourceforge.net/doc_html/r634.html> that indicates a
timeout. If the timeout is set to near nothing
<http://linux-gpib.sourceforge.net/doc_html/r2137.html>, seems identical
to a socket set to non-blocking and should return the same transient
error which, in fact, really isn't an error, just we're at the end of
the data which should properly end a [read] call that internally is
recursive. Yes?

static int
GpibInputProc (
ClientData instanceData, /* The GPIB device state. */
char *buf, /* Where to store data. */
int toRead, /* Maximum number of bytes to read. */
int *errorCodePtr) /* Where to store errno codes. */
{
GpibInfo *infoPtr = (GpibInfo *) instanceData;
*errorCodePtr = 0;

Receive(infoPtr->board, infoPtr->addr, buf, (long)toRead,
infoPtr->term);

if (ThreadIbsta() && ERR) {
TranslateGpibErr2Tcl(infoPtr->chan, ThreadIberr());
*errorCodePtr = Tcl_GetErrno();
return -1;
} else if (ThreadIbsta() && TIMO) {
/* TODO: not sure on this error code */
Tcl_SetErrno(EWOULDBLOCK);
*errorCodePtr = Tcl_GetErrno();
return -1;
} else {
/* return how much we read */
return ThreadIbcnt();
}
}


I wouldn't be asking such a silly question if I had this completed
enough to run it ;)

--


From: Donal K. Fellows on
On 2 July, 20:52, David Gravereaux <davyg...(a)pobox.com> wrote:
> I'm writing a GPIB channel driver extension and was wondering what the
> proper error code I should return for a timeout from a blocking read?

That sounds dodgy. Surely a read on a blocking channel should not
return until it has something definite to report, whether data or
error? (EWOULDBLOCK is exactly right when not blocking.)

Donal.
From: David Gravereaux on
On 07/02/2010 02:03 PM, Donal K. Fellows wrote:
> On 2 July, 20:52, David Gravereaux <davyg...(a)pobox.com> wrote:
>> I'm writing a GPIB channel driver extension and was wondering what the
>> proper error code I should return for a timeout from a blocking read?
>
> That sounds dodgy. Surely a read on a blocking channel should not
> return until it has something definite to report, whether data or
> error? (EWOULDBLOCK is exactly right when not blocking.)
>
> Donal.


By blocking, I meant the GPIB library call, not the Tcl channel. I
don't want blocking at the Tcl level. A real blocking read locks the
GPIB buss from other devices using it to communicate with the
controller. I'll allow it (I guess), but it can never work in a system
of multiple units. The channel itself will be non-blocking by using low
timeout values to the blocking Receive() call in the GPIB library.

There is a background read call, ibrda(), but looks a bit complicated
(at this time) as well as it not being part of the 'multi-device' API.

I REALLY don't want my Tk controls to freeze during I/O which is a big
problem with this arcane 1978(!) IEEE488.2 way of moving bits.

Ok, EWOULDBLOCK is good then, Thanks.
--


From: Craig on
The Receive call sounds like a combination of a select call with a timeout
followed by a read.

A posix select call would return 0 with no error on a timeout and the read would
never occur.
If the read really were blocking and you attempted a read after a timeout, it
would block and this driver would hang.

Were I a user of this code, i don't think i'd want an error returned on a
timeout (which, btw, seems quite different from EWOULDBLOCK semantics, since a
timeout on a select allows the app to block for a defined period of time, while
EWOULDBLOCK is returned from a NON-BLOCKING read call, when it would block.)

Since i don't understand how channel drivers are s'posed to work, it isn't clear
if returning an error is the only way to return out-of-band information. What
about a return code of -2? If that's not possible, then I can understand your
quandary, because none of the read call errors really map to what's happening.
Are you limited to returning read call errors?

What is it that drives the call to GpibInputProc? what is it's response to an
error or zero bytes returned?

craig

David Gravereaux wrote:
> Hi,
>
> I'm writing a GPIB channel driver extension and was wondering what the
> proper error code I should return for a timeout from a blocking read?
>
> I was thinking EWOULDBLOCK seems correct, but I'm not sure. The read
> call, Receive() <http://linux-gpib.sourceforge.net/doc_html/r2741.html>
> can return a status
> <http://linux-gpib.sourceforge.net/doc_html/r634.html> that indicates a
> timeout. If the timeout is set to near nothing
> <http://linux-gpib.sourceforge.net/doc_html/r2137.html>, seems identical
> to a socket set to non-blocking and should return the same transient
> error which, in fact, really isn't an error, just we're at the end of
> the data which should properly end a [read] call that internally is
> recursive. Yes?
>
> static int
> GpibInputProc (
> ClientData instanceData, /* The GPIB device state. */
> char *buf, /* Where to store data. */
> int toRead, /* Maximum number of bytes to read. */
> int *errorCodePtr) /* Where to store errno codes. */
> {
> GpibInfo *infoPtr = (GpibInfo *) instanceData;
> *errorCodePtr = 0;
>
> Receive(infoPtr->board, infoPtr->addr, buf, (long)toRead,
> infoPtr->term);
>
> if (ThreadIbsta() && ERR) {
> TranslateGpibErr2Tcl(infoPtr->chan, ThreadIberr());
> *errorCodePtr = Tcl_GetErrno();
> return -1;
> } else if (ThreadIbsta() && TIMO) {
> /* TODO: not sure on this error code */
> Tcl_SetErrno(EWOULDBLOCK);
> *errorCodePtr = Tcl_GetErrno();
> return -1;
> } else {
> /* return how much we read */
> return ThreadIbcnt();
> }
> }
>
>
> I wouldn't be asking such a silly question if I had this completed
> enough to run it ;)
>
From: tom.rmadilo on
On Jul 2, 2:52 pm, Craig <ask...(a)somewhere.net> wrote:
> The Receive call sounds like a combination of a select call with a timeout
> followed by a read.
>
> A posix select call would return 0 with no error on a timeout and the read would
> never occur.
> If the read really were blocking and you attempted a read after a timeout, it
> would block and this driver would hang.
>
> Were I a user of this code, i don't think i'd want an error returned on a
> timeout (which, btw, seems quite different from EWOULDBLOCK semantics, since a
> timeout on a select allows the app to block for a defined period of time, while
> EWOULDBLOCK is returned from a NON-BLOCKING read call, when it would block.)
>
> Since i don't understand how channel drivers are s'posed to work, it isn't clear
> if returning an error is the only way to return out-of-band information. What
> about a return code of -2? If that's not possible, then I can understand your
> quandary, because none of the read call errors really map to what's happening.
> Are you limited to returning read call errors?
>
> What is it that drives the call to GpibInputProc? what is it's response to an
> error or zero bytes returned?
>
> craig
>
>
>
> David Gravereaux wrote:
> > Hi,
>
> > I'm writing a GPIB channel driver extension and was wondering what the
> > proper error code I should return for a timeout from a blocking read?
>
> > I was thinking EWOULDBLOCK seems correct, but I'm not sure.  The read
> > call, Receive() <http://linux-gpib.sourceforge.net/doc_html/r2741.html>
> > can return a status
> > <http://linux-gpib.sourceforge.net/doc_html/r634.html> that indicates a
> > timeout.  If the timeout is set to near nothing
> > <http://linux-gpib.sourceforge.net/doc_html/r2137.html>, seems identical
> > to a socket set to non-blocking and should return the same transient
> > error which, in fact, really isn't an error, just we're at the end of
> > the data which should properly end a [read] call that internally is
> > recursive.  Yes?
>
> > static int
> > GpibInputProc (
> >     ClientData instanceData,       /* The GPIB device state. */
> >     char *buf,                     /* Where to store data. */
> >     int toRead,                    /* Maximum number of bytes to read. */
> >     int *errorCodePtr)             /* Where to store errno codes. */
> > {
> >     GpibInfo *infoPtr = (GpibInfo *) instanceData;
> >     *errorCodePtr = 0;
>
> >     Receive(infoPtr->board, infoPtr->addr, buf, (long)toRead,
> > infoPtr->term);
>
> >     if (ThreadIbsta() && ERR) {
> >    TranslateGpibErr2Tcl(infoPtr->chan, ThreadIberr());
> >    *errorCodePtr = Tcl_GetErrno();
> >    return -1;
> >     } else if (ThreadIbsta() && TIMO) {
> >    /* TODO: not sure on this error code */
> >    Tcl_SetErrno(EWOULDBLOCK);
> >    *errorCodePtr = Tcl_GetErrno();
> >    return -1;
> >     } else {
> >    /* return how much we read */
> >    return ThreadIbcnt();
> >     }
> > }
>
> > I wouldn't be asking such a silly question if I had this completed
> > enough to run it ;)

Note that blocking means that the OS would put the process/thread to
sleep until some future date.

With select() which includes a timeout value you can block for a
finite amount of time, or return earlier if one of the read-fds, write-
fds or error-fds becomes available. If you don't specify any rfds,
wfds or efds, but specify a time value, you get a sleep function,
similar to [after].

Select() is not available at the Tcl script level, so you can't
combine an event with a timeout. This is very different from setting
an cancel event timer and then setting a read/write event callback.
There is no documentation on what happens if a read/write event fires
and lasts beyond the cancel event. Given the lack of documentation,
testing becomes harder: what is expected? Who knows. In general the
semantics of a cancel event timer is that if the event has not
completed, the cancel event kicks in. What do you do with any data
which has accumulated prior to the timeout? Or do you delay execution
of the cancel event which might send unexpected signals: canceling
something which has already happened. Or do you dismiss the event? A
subsequent block will defeat the purpose of the cancel event. Select()
itself creates the exact same situation. One solution is the self-pipe
trick: http://cr.yp.to/docs/selfpipe.html .