Post by David SchwartzPost by Steffen DETTMERand a blocking write should return as soon as at
least one byte has been written.
No. A blocking write should block until all the requested data cen be
written.
ahh, interesting. Why should it?
Because this is what most people want it to do.
This is acceptable for Perl, but not for C :-) Even if most
people would want a write contradicting its man page, I'd still
consider it wrong :)
Post by David SchwartzIf you tried to write two bytes, why would you want to wait
until the first one could be written but not wait until the
second one could be written? It just doesn't make much sense.
If the first byte (or any part of the buffer) could be written
instantly or (e.g. if no select returned ready before :)) after
some amount of time waited, write should return to give the
calling application the control.
I looked up write(2) on opengroup.org and found a page that
surprised me :)
The information on opengroup.org tell `The write() function shall
attempt to write nbyte bytes from the buffer...'. My man page
tell `write writes up to count bytes to the file...'. My man
page claims to be conforming to `SVr4, SVID, POSIX, X/OPEN,
4.3BSD'. The opengroup.org page distinguishes write semantics
based on what the fd is kind of (file, FIFO, STREAM, ...) which
IMHO cannot be correct because it destroys the abstraction.
It would be a pitty if some implementations would follow the
opengroup.org description and change the write semantics,
woulnd't it?
on this page, there are more `violations of file abstractions',
someone could get the impression that the `regular files on a
ext2 file system' or alike would be most true of the world, for
instance `The read() function reads data previously written to a
file.'. This is simply not true:
***@trinida:~ # md5sum tmp
fcbb60277dee9a96ec9c2fbfa47a478d tmp
***@trinida:~ # dd of=/dev/urandom if=tmp count=100 bs=1
100+0 records in
100+0 records out
***@trinida:~ # dd if=/dev/urandom of=tmp count=100 bs=1
100+0 records in
100+0 records out
***@trinida:~ # md5sum tmp
5cdceb17716e1dd4441f9bd4027fd75e tmp
:-)
When the file is /dev/urandom (a random number generator device
at least on linux), it shall NOT return the data previously
written. For devices (and sockets :)), I think this is obvious.
anyway.
Post by David SchwartzThere is some code out there that assumes that a blocking write
will fully complete unless there is an error. This code is, as
you point out, broken.
However, a 'read' that blocked after some data was received
would be broken.
ahh, ok, yes. I think, this is somewhat `symetric' for read and
write.
Post by David SchwartzPost by Steffen DETTMERcorrect implementation needs to guarantee that. If queue
discarding is possible, a flag must be stored (or so) to make
read return EAGAIN or whatever (probably causing most code to
break anyway, because noone expects EAGAIN after select > 0 :-)).
That's simply impossible to do. The problem is that there is no
unambiguous way to figure out whether an operation is the one
1) A thread calls 'select'.
2) That thread later calls 'read'.
If the 'select' changes the semantics of the 'read', then if the thread
didn't know that some other code called 'select' earlier, the later
read-calling code can break.
If some other thread called read (or another function), of course
before the next read a select must be called again. Only for the
next read guarantees may be made, not for the 103th read called
after the second reboot :)
I think, the API must behave in the same way independently
whether used by multiple threads or a single one, if possible.
Of course, care must be taken when e.g. two threads call select
on the same file descriptor and so on. Many ways to get it very
complex, hum...
Post by David SchwartzPost by Steffen DETTMEROf course, it probably isn't the best idea to rely on that,
maybe some embedded highly size optimised lib makes the one
or other compromise or so... :)
There are known implementations that perform some data
integrity checks at 'recv' time, so a 'select' hit that results
in the data being dropped later can lead to 'recvmsg' blocking.
I think, select simply cannot work on the low layer that may have
data that may not be valid because of pending integrity checks.
select must work on the same buffer as read (which gets
integrity checked data only).
Post by David SchwartzYou can argue that these implementations are deficient, but I
think that argument would be inconsistent. This behavior is
accepted with 'accept', and it's precisely the same issue.
mmm... my manpage talks about select and read (and select and
write), but not about accept. So I think this means for accept no
guarantees are made. My accept man page states clearly `To ensure
that accept never blocks, the passed socket s needs to have the
O_NONBLOCK flag set'.
I think, read and accept in conjunction with select simply have
different semantics. Is that right?
Post by David SchwartzPost by Steffen DETTMERThe statement `to see if a read will not block' does not
sound very concrete or formally. For instance, only the next
read can be in scope and probably only if no other call
(recv, write, don't know) is performed on this fd - I guess.
The problem is that it becomes very hard to figure out what an
"other call" is. What about 'setsockopt'? If you don't even
know what you're asking for, you wouldn't even know if you had
it. ;)
setsockopt gets a filedescriptor (socket) as parameter, so it
counts as other call. Maybe there are problematic calls, right,
or sockets/files shared through fork(), where processes may
influence each other, so that it might look for one process that
behavior would be strange, but maybe in fact it is as expected
just confusing because of the other processes actions.
I think best is to avoid such constructions, seems to be very
difficult to handle...
Post by David SchwartzPost by Steffen DETTMERYes, and additionally, there may be implementations supporting a
select function but at the same time not even conforming the
standard, I think such `TCP stacks' exist.
BTW, which standard would it be, `4.4BSD'?
I'm talking about The Single Unix Specification or The Open Group Base
Specification.
http://www.opengroup.org/onlinepubs/009695399/functions/FD_SET.html
This is reasonably clear that 'select' reports current status, just as
functions like 'stat' do. They provide no more of a future guarantee than
functions like 'stat' do.
Thanks for the link. My man page and my linux boxes here do not
comply to it (fortunality :)). But what a pitty that there are
multiple selects. I though, for sockets or select some agreement
(as 4.4BSD) would be commonly accepted. Now there is some Single
Unix doing it differently and POSIX got a pselect... What a
pitty.
(If `Portable Operating System Interface for Unix' and `Single
Unix' contradict, maybe it had better been called `Yet another
Unix' or so grpmf...)
So a BSD/Linux/POSIX compliant program working on a
BSD/Linux/POSIX compliant select won't work on a Single Unix
compliant OS.
That would mean as I understand it, that a program needs to know
whether it runs on e.g. Solaris (Single Unix) or Linux (POSIX) to
know how to use select? Is this really true? Or did I just
misunderstood?
This just shows that I have no clue about standards (I though SUS
would be `POSIX compliant' and BSD and linux would comply in
large parts).
Post by David SchwartzPost by Steffen DETTMERmmm... If the man page tells that `a read will not block' (which,
BTW, is also told for write, but not for accept), I think the
possible subsequent operations are defined: read or write.
Why include "write" in the claim that a read will not block?
Sorry, I meant, the `a read will not block' when the fd is
listed in readfds - similarily this is told for write: `write will
not block' when the fd is listed in writefds.
Post by David SchwartzWhat about "setsockopt"?
I don't know if it could block, I think theoretically such option
may exist. Usually, I would expect it not to block (regradless
whether select was called or not). I don't know when someone
would call select before setsockopt (as you surely noted I'm not
so experienced in all those details).
I think, after setsockopt usually someone could simply reinvoke
select to check if read should be called (or whatever). I would
not even call select before setsockopt, only before read.
Actually, my code calls setsockopt only `at the begining' after
accept without any select. Is this wrong?
Post by David SchwartzIn any event, only Windows has documentation that uses that
kind of language. I think it was just sloppiness, as the select
function on Windows was a hack job just to support
compatability with existing Berkeley sockets implementations.
:-)
Similarily for other TCP/IP stacks, maybe for embedded devices.
Or for linux vs. Single Unix as it turned out...
Post by David SchwartzPost by Steffen DETTMERA file is always ready. There is never anything to wait
for.
I disagree here. Files may not be ready, because NFS Server
may not be responsing, a USB stick may be slow, a FTP file
system may need to dialup an ISDN line, the FIFO or STDIN
could be empty, the harddisk may be busy and need some
milliseconds to read in the requested blocks --- or the file
could be a device or a socket :)
Nevertheless, it's ready and cannot be waited for. With slow
file systems, they generally try to perfectly mimic the
semantics of fast file systems. An empty file is still ready to
be read right now, to report correctly that it is empty.
But select on STDIN usually works (on linux) - is this linux
specific? I would consider it almost useless, if select couldn't
be called on STDIN because STDIN could be a `fast file system'!
Does this also mean that select wouldn't work as I expect it when
reading a e.g. ext2 filesystem from a slow media, let's say NFS
loop back, USB Stick or floppy disk? I assumed it would work, but
now as you pointed to it I find no statement about in the man
pages... :(
Post by David SchwartzPost by Steffen DETTMERmmm... beside I'd consider a program expecting write to block
until all data has been written already broken, I see your point,
ok... So you say that theoretically it is guaranteed that read
won't block after select but practically there will always be a
risk to have an implementation not fulfilling this guarantee,
right?
No, it's not guranteed even theoretically. The 'select'
function is simply a status-reporting function that does not
and cannot guarantee what will happen in the future.
sorry, I don't get this. I'm afraid that this become a kind of
circle :)
For me, select technically reports the state of a buffer. Of
course it could be implemented with a one byte buffer or maybe
even without any buffer but a flag (or set of flags). Anyway. So
lets say it is a buffer.
Because the access to the buffer is limited by the same API, I
think it should be able to guarantee. If the buffer is empties,
by a file truncation or so, either this could be unnoticed
(meaning, that the read returns the data, as it happens when
using fread buffers) or EOF would be returned - nonblocking in
any case. The status of the buffers encapsultated and hidden in
the implementation won't change in the future except through the
implementation - and this could be catched to make read at least
return an error instead of block. Actually, what happens with the
`source' of the data for this buffer (file, tcp, udp) does not
matter at all.
Without any buffers (or flags), select cannot be implemented of
course, because it is required to limit/control the access to it
(or at least to get reliable information/notification about to
set a flag).
So I would conclude that it is a status-reporting function but
also could guarantee. What do I miss?
Post by David SchwartzAssuming it will is as serious a bug as checking permissions
with something like 'access' and then assuming the information
must still be valid in the future.
but access makes no statement at all about blocking/nonblocking
future calls? Also, I would assume that the information of access
will be valid in future as long as no other call will be made to
this resource (e.g. a chown via NFS or simply that the file would
be removed by another process - which require calls to this
resource, e.g. a remote unlink or so). Maybe access is a slightly
different topic?
Post by David SchwartzPost by Steffen DETTMERIs that not to say that if select() says it's ready to
read, I'm guaranteed my next read() won't block?
Nope. To say that, it would have to say "will not block".
Instead it says "would not block". This refers to a
hypothetical concurrent call not blocking at some instant
in-between when you called 'select' and when it returned.
I think `will not block' wouldn't be said correctly because it is
not required to even call read at all, and if it would not be
called it couldn't be said whether it blocks or does not block,
but may english is far away from being good enough to understand
such specifics correctly.
However, the `hypothetical concurrent call' IMHO is hypothetical
:) - maybe some `hypothetical sequential call' was meant, could
this be the case? I'm not sure if the word sequential is right,
maybe proximate, successive or even `in direct succession'?
At least the discussion IMHO shows that specs are not clear and
using APIs correctly is a challenge, because of those doubts the
best practice is to explicitely use non-blocking fds and that the
best documentation is no replacement for deep testing :-)
oki,
Steffen
About Ingenico Throughout the world businesses rely on Ingenico for secure and expedient electronic transaction acceptance. Ingenico products leverage proven technology, established standards and unparalleled ergonomics to provide optimal reliability, versatility and usability. This comprehensive range of products is complemented by a global array of services and partnerships, enabling businesses in a number of vertical sectors to accept transactions anywhere their business takes them.
www.ingenico.com This message may contain confidential and/or privileged information. If you are not the addressee or authorized to receive this for the addressee, you must not use, copy, disclose or take any action based on this message or any information herein. If you have received this message in error, please advise the sender immediately by reply e-mail and delete this message. Thank you for your cooperation.
About Ingenico Throughout the world businesses rely on Ingenico for secure and expedient electronic transaction acceptance. Ingenico products leverage proven technology, established standards and unparalleled ergonomics to provide optimal reliability, versatility and usability. This comprehensive range of products is complemented by a global array of services and partnerships, enabling businesses in a number of vertical sectors to accept transactions anywhere their business takes them.
www.ingenico.com This message may contain confidential and/or privileged information. If you are not the addressee or authorized to receive this for the addressee, you must not use, copy, disclose or take any action based on this message or any information herein. If you have received this message in error, please advise the sender immediately by reply e-mail and delete this message. Thank you for your cooperation.
______________________________________________________________________
OpenSSL Project http://www.openssl.org
User Support Mailing List openssl-users-MCmKBN63+***@public.gmane.org
Automated List Manager majordomo-MCmKBN63+***@public.gmane.org