* David Schwartz wrote on Wed, Aug 29, 2007 at 08:07 -0700: > > > > and 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 :) > If 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: [EMAIL PROTECTED]:~ # md5sum tmp fcbb60277dee9a96ec9c2fbfa47a478d tmp [EMAIL PROTECTED]:~ # dd of=/dev/urandom if=tmp count=100 bs=1 100+0 records in 100+0 records out [EMAIL PROTECTED]:~ # dd if=/dev/urandom of=tmp count=100 bs=1 100+0 records in 100+0 records out [EMAIL PROTECTED]:~ # 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. > There 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. > > correct 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 > that's not supposed to block. Consider: > > 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... > > Of 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). > You 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? > > The 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... > > Yes, 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). > > mmm... 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. > What 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? > In 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... > > > A 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... :( > > mmm... 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? > Assuming 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? About the other mail from Yves: > > > Is 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@openssl.org Automated List Manager [EMAIL PROTECTED]