Re: (Another) socket streams library

I was directed to this thread after some work to make GNU libstdc++ expose POSIX pipe semantics at the istream::readsome() level, which probably will show up in release 4.0.1. (Cf. http://gcc.gnu.org/bugzilla/show_bug.cgi?id=21286 ) It started me thinking about how to make an iostream useful when attached to a non-blocking socket. Reading this thread, it seems to me you have stepped in the same trap as most other attempts. There are many, many libraries to make various sources and sinks, including sockets, look like iostreams, but without actually being iostreams. We don't seem to find ourselves using them. For nonblocking socket support to be widely useful, it must be possible to pass such a stream to a library that takes a regular istream& or ostream& argument. This has been characterized as impossible, because iostream semantics are not compatible with non-blocking I/O. While the latter is true, the former is not. The key to the paradox is the expression "out-of-band". The owner of the stream may know things about it, and its underlying socket, that the user of the istream or ostream does not, and can act accordingly. Most particularly, the owner may know that the amount of input or output to be done will not cause any system calls to return EWOULDBLOCK. The next question is, how do we know how much I/O we can do without blocking? It is common for select not to wake up a process for writing on a socket until there is more than (say) 4K of space in the output buffer. Therefore, any use of the socket that will not produce more than 4K of output is safe. An actual TCP "out-of-band" notification from the other end may help, indicating that the last written data have all arrived, proving that a full 64K of buffer space awaits. On input, we must ensure that our override of streambuf::underflow is satisfied by a short read, and that the user of the attached istream will be satisfied with what it actually finds, and won't loop trying to get more. These conditions seem awfully restrictive, but there remain a large class of problems for which they are not *too* restrictive. What remains is to identify and package up all the usable out-of-band notification mechanisms associated with sockets, and try to achieve some abstraction and perhaps even (who knows?) portability. Nathan Myers ncm@cantrip.org

----- Original Message ----- From: "Nathan Myers" <ncm@cantrip.org> To: <boost@lists.boost.org> Sent: Wednesday, May 04, 2005 6:22 AM Subject: [boost] Re: (Another) socket streams library [snip]
It started me thinking about how to make an iostream useful when attached to a non-blocking socket. Reading this thread, it seems to me you have stepped in the same trap as most other attempts. There are many, many libraries to make various sources and sinks, including sockets, look like iostreams, but without actually being iostreams. We don't seem to find ourselves using them.
For nonblocking socket support to be widely useful, it must be possible to pass such a stream to a library that takes a regular istream& or ostream& argument. This has been characterized as impossible, because iostream semantics are not compatible with non-blocking I/O. While the latter is true, the former is not. The key to the paradox is the expression "out-of-band". The owner of the stream may know things about it, and its underlying socket, that the user of the istream or ostream does not, and can act accordingly.
Its possible you have alluded to claims of mine ("blocking signature"). If I understand your sketch; yes its certainly possibly to hide details of async in such a way that an input call on a stream will function in a traditional fashion. The catch (for me) is that such a call is still blocking. The thread that performs the call (operator<<) must wait for the complete object off the stream. I have seen efforts to undermine even this constraint. Setjmp+longjmp was used in such a way that calling threads "leave" the context of an input call and "resume" when the object was complete. At least in my "signal processing" world (telephony) these efforts are wasted. Objects could arrive from several sources at any one time. At application level, i.e. "operator>>( istream &, application_type & )", this would mean that zero or more objects are being received between the call and return sequence for the input operator. At the very least this would be a difficult coding environment. Your architecture (IIUC?) looks fine to me. As you mention there is a large category of problems that it solves. I just wouldnt characterize it as async. Or have I mis-fired? Cheers.

On Wed, May 04, 2005 at 09:07:24AM +1200, Scott Woods wrote:
From: "Nathan Myers" <ncm@cantrip.org>
It started me thinking about how to make an iostream useful when attached to a non-blocking socket. ... For nonblocking socket support to be widely useful, it must be possible to pass such a stream to a library that takes a regular istream& or ostream& argument.
If I understand your sketch; yes its certainly possibly to hide details of async in such a way that an input call on a stream will function in a traditional fashion.
The catch (for me) is that such a call is still blocking. The thread that performs the call (operator<<) must wait for the complete object off the stream.
Not quite. The idea is that operator>> will operate on known text obtained without blocking and without EWOULDBLOCK. I don't recall how one can tell how much is in an incoming socket buffer (nothing very portable, in any case), but it is easy enough to tell if there's at least _something_ there: do a select() with a zero timeout, and see if it says it's ready. (More likely your regular select() loop woke up and told you so.) If so, trigger an underflow() (with sgetc(), say), which will get up-to-a buffer-full. (Make sure the buffer is at least as big as the OS's.) After there's text in the buffer, you can decide if it's enough to merit calling whatever is supposed to extract and operate on it. A special streambuf can provide direct access to the buffer contents, too, so you can check if the input really is terminated. If it's not terminated, you can go back to sleep and wait for more (and for other events too). If it's terminated, you hand it over, and they process it, none the wiser. Of course they have to be willing to stop reading before EOF -- or at least not mess up their internal state if they are fed an EOF at an agreed-upon spot by our complicit streambuf. (We can clean up any fail/eof/bad flags after we get control back.) If you were willing to do threads, of course, there would be no point to a nonblocking socket. To me, the value of nonblocking sockets is how they let you get along with a regular event loop, and avoid everything nasty about threads.
Your architecture (IIUC?) looks fine to me. As you mention there is a large category of problems that it solves. I just wouldnt characterize it as async.
I don't care much how it's labeled, or how it fits into anybody's Grand Unified Theory of I/O. I just want to be able to plumb a nonblocking socket to code that only knows how to talk to a bog-standard istream or an ostream, and have reason to expect it will work right. It doesn't seem like we need to do much to make that possible, at least sometimes. (Another goal is a zero-copy streambuf whose buffer is an mmap page that can be read into or written from without actually copying any bytes from kernel to user space, or back. I half get the impression somebody is working on something like this already. On NetBSD or OpenBSD, BTW, you can do zero-copy pipe and socket I/O that way, too -- so sendfile() is just a library function. I don't know if Linux will ever get that.) Nathan Myers ncm@cantrip.org

Nathan Myers wrote:
After there's text in the buffer, you can decide if it's enough to merit calling whatever is supposed to extract and operate on it.
It seems that if you already have code that does this by directly examining the buffer, there may be little point in dropping back a level of abstraction and then using operator>>. In particular, in a common case, verifying whether input is complete does most of the work of actually extracting it. But still I think something special is needed here, because in the case of integers, for example, theres no particular way to tell whether an integer is complete or not without having some metadata. One thing I've never understood is how extractors are supposed to be written when they require reading two or more sub-objects from the input stream. If reading the first part suceeds, but the second part fails, what happens to the chunk of data that was read? And how do we prevent the stream from being in an indeterminant state due to not knowing how much was read? Perhaps the solution to this problem might present new ideas for solutions to the nonblocking extractor problem. Aaron W. LaFramboise

Aaron W. LaFramboise wrote:
Nathan Myers wrote:
After there's text in the buffer, you can decide if it's enough to merit calling whatever is supposed to extract and operate on it.
It seems that if you already have code that does this by directly examining the buffer, there may be little point in dropping back a level of abstraction and then using operator>>. In particular, in a common case, verifying whether input is complete does most of the work of actually extracting it.
It does actually make a lot of sense if you have a simple way to detect that the buffer had data enough to satisfy whatever extractions you are going to do: may be you know how big your data is going to be or may be the lenght is encoded in the buffer, or may be that the encoded data never cross a line and you can detect an end of line. If by simple examination of the buffer you can decide that an extraction step won't block, you go ahead and call an upper layer that will do the extraction using standard>> operators. This is has the benefict that high level code need not to be aware of blocking/non-blocking- In fact i think that iostream should be considered a way to convert a sequence of characters to live objects, *not* a way to do input output (probably not even streambuffers should be considered the lowest i/o mechanism, as they take care of some locale conversion). The simplest way to use them would be to read the wole byte stream in memory, build an iostream on top and then do the deserialization. Deserializing while reading at well known buoundaries should be considered an optimization that let's you pipeline the two operations.
But still I think something special is needed here, because in the case of integers, for example, theres no particular way to tell whether an integer is complete or not without having some metadata.
One thing I've never understood is how extractors are supposed to be written when they require reading two or more sub-objects from the input stream. If reading the first part suceeds, but the second part fails, what happens to the chunk of data that was read? And how do we prevent the stream from being in an indeterminant state due to not knowing how much was read? Perhaps the solution to this problem might present new ideas for solutions to the nonblocking extractor problem.
The simples solution is to make always sure you can't read a partial object. If you can't don't pipeline. A more complex solution would be to have some kind of roll back: save the whole stream state (i.e. even the buffered data), deserialize, and if it fails (i.e. an exception is thrown in the object constructor) rollback, read some more data from the source and try again. As an optimization instead of copying the buffered data you might just remember the position that the deserialization started from and never throw characters away until you commit. You probably want to use a custom buffered stream. I don't think working this way is worth it though. -- Giovanni P. Deretta

On Wed, May 04, 2005 at 12:11:41AM -0500, Aaron W. LaFramboise wrote:
Nathan Myers wrote:
After there's text in the buffer, you can decide if it's enough to merit calling whatever is supposed to extract and operate on it.
It seems that if you already have code that does this by directly examining the buffer, there may be little point in dropping back a level of abstraction and then using operator>>. In particular, in a common case, verifying whether input is complete does most of the work of actually extracting it.
Imagine that you want to use somebody's library that can parse a "{}"-delimited language like Javascript. It wants its input from an istream& or (more likely, I hope) streambuf*. You can scan the incoming text for matching brackets, and the bracket that matches the first opening bracket delimits a unit. The only real work you're doing is skipping comments and string literals. (Similarly, perhaps, for XML.) The size of the unit to parse is not restricted to the size of your buffer, but there might be a maximum size you care to handle, for security/DOS if nothing else. Then there's Giovanni's example of line delimiters, which may be a more common use. I can recognize newlines, but don't care to reproduce even the code to parse numbers, and don't want to copy each line all over creation just to get the numbers out; I'd rather parse them right from the buffer the text first landed in.
One thing I've never understood is how extractors are supposed to be written when they require reading two or more sub-objects from the input stream. If reading the first part suceeds, but the second part fails, what happens to the chunk of data that was read? And how do we prevent the stream from being in an indeterminant state due to not knowing how much was read? Perhaps the solution to this problem might present new ideas for solutions to the nonblocking extractor problem.
Or vice versa. The old libstdc++ istream used to support indefinitely- large pushback, but that's not really what's wanted. What you need is a way get a token from the streambuf that lets you seek the stream back to that point, e.g. when you find failbit set. When the token's dtor is called, the streambuf can discard any accumulated state up to the next place it issued a token. Of course that just takes a clever streambuf, and doesn't need any help from the standard library. (Unfortunately streampos can't be that token; no dtor.) A less elegant scheme is possible: you might have a streambuf that saves _everything_, until told to discard whatever came before some point, e.g. the current position when you know you have a good parse. It can pubseek() back to that point and to any point after. Of course, once it has seeked (sought?) back there, you need to know what to do next. I am finding it hard to think of what one might do. Skip to the next start delimiter? You could do that without seeking first. Try a different LR(n) parse-table production? Maybe, but that's a bit obscure. Nathan Myers ncm@cantrip.org

On Tue, 2005-05-03 at 20:55 -0700, Nathan Myers wrote:
On Wed, May 04, 2005 at 09:07:24AM +1200, Scott Woods wrote:
From: "Nathan Myers" <ncm@cantrip.org>
(Another goal is a zero-copy streambuf whose buffer is an mmap page that can be read into or written from without actually copying any bytes from kernel to user space, or back.
That would be impressive! Unfortunately I don't think it is theoretically possible ;-). Under normal conditions the interface device driver copies from the hardware device buffer to kernel space. The data passes up the stack until it is copied from kernel space to user space for a total of 2 copies. you would also get two copies on the other side ( mmap ). It is certainly possible to eliminate one copy on each side.
I half get the impression somebody is working on something like this already. On NetBSD or OpenBSD, BTW, you can do zero-copy pipe and socket I/O that way, too -- so sendfile() is just a library function. I don't know if Linux will ever get that.)
I believe Doug Schmidt has done something on this but just on sockets. IIRC it involved writing his own device drive and use on Data Link Layer access to sockets to copy directly from the hardware buffer to user space. The down side of this is you now need your IP stack also in user space. /ikh _______________________________________________________________________ This email has been scanned for all known viruses by the MessageLabs Email Security System. _______________________________________________________________________

On Wed, May 04, 2005 at 02:46:05PM +0100, Iain K. Hanson wrote:
On Tue, 2005-05-03 at 20:55 -0700, Nathan Myers wrote:
On Wed, May 04, 2005 at 09:07:24AM +1200, Scott Woods wrote:
From: "Nathan Myers" <ncm@cantrip.org>
(Another goal is a zero-copy streambuf whose buffer is an mmap page that can be read into or written from without actually copying any bytes from kernel to user space, or back.
That would be impressive! Unfortunately I don't think it is theoretically possible ;-). Under normal conditions the interface device driver copies from the hardware device buffer to kernel space. The data passes up the stack until it is copied from kernel space to user space for a total of 2 copies. you would also get two copies on the other side ( mmap ). It is certainly possible to eliminate one copy on each side.
Copying from the device to kernel memory is unavoidable, in general, but typically only costs bus bandwidth, not CPU cycles. The copy from kernel to user space can be avoided if the user's buffer is an anonymously-mmap()ped page that hasn't been written in, because one page is as good as another. Similarly for output -- although of course it's OK to have written it! Then, though, if it _hasn't_ been touched, it might be a kernel buffer that the user code only inspected (or didn't) and just wants passed along. (That's how NetBSD UVM works, IIUC.)
I half get the impression somebody is working on something like this already. On NetBSD or OpenBSD, BTW, you can do zero-copy pipe and socket I/O that way, too -- so sendfile() is just a library function. I don't know if Linux will ever get that.)
I believe Doug Schmidt has done something on this but just on sockets. IIRC it involved writing his own device drive and use on Data Link Layer access to sockets to copy directly from the hardware buffer to user space. The down side of this is you now need your IP stack also in user space.
An IP stack in user space would kill latency and probably throughput, obviating gains from avoiding copies. But a cool project anyway. Maybe Hurd can use it. :-) Boost.iostream seems to have something like I described, allowing the parsing of regular files with zero-copy. Probably that ought to be slurped into GNU libstdc++ filebuf proper. However, having it in Boost (too) makes it portable, e.g. to older g++ releases. Nathan Myers ncm@cantrip.org

On Wed, 2005-05-04 at 08:52 -0700, Nathan Myers wrote:
On Wed, May 04, 2005 at 02:46:05PM +0100, Iain K. Hanson wrote:
On Tue, 2005-05-03 at 20:55 -0700, Nathan Myers wrote:
On Wed, May 04, 2005 at 09:07:24AM +1200, Scott Woods wrote:
From: "Nathan Myers" <ncm@cantrip.org>
(Another goal is a zero-copy streambuf whose buffer is an mmap page that can be read into or written from without actually copying any bytes from kernel to user space, or back.
That would be impressive! Unfortunately I don't think it is theoretically possible ;-). Under normal conditions the interface device driver copies from the hardware device buffer to kernel space. The data passes up the stack until it is copied from kernel space to user space for a total of 2 copies. you would also get two copies on the other side ( mmap ). It is certainly possible to eliminate one copy on each side.
Copying from the device to kernel memory is unavoidable, in general, but typically only costs bus bandwidth, not CPU cycles. The copy from kernel to user space can be avoided if the user's buffer is an anonymously-mmap()ped page that hasn't been written in, because one page is as good as another.
I don't know sufficient about the implementation of mmap and its relationship with swap system and buffer cache and the IP stack buffers to know whether this would work as you intend.
Similarly for output -- although of course it's OK to have written it! Then, though, if it _hasn't_ been touched, it might be a kernel buffer that the user code only inspected (or didn't) and just wants passed along. (That's how NetBSD UVM works, IIUC.)
You will still at a minimum have another kernel to device copy as previously stated. Another problem is that mmap files *I think* need to be seek'able.
I believe Doug Schmidt has done something on this but just on sockets. IIRC it involved writing his own device drive and use on Data Link Layer access to sockets to copy directly from the hardware buffer to user space. The down side of this is you now need your IP stack also in user space.
An IP stack in user space would kill latency and probably throughput, obviating gains from avoiding copies. But a cool project anyway. Maybe Hurd can use it. :-)
I think that depends on the process priority and what else is running on the system. But certainly a very interesting concept ;-).
Boost.iostream seems to have something like I described, allowing the parsing of regular files with zero-copy. Probably that ought to be slurped into GNU libstdc++ filebuf proper. However, having it in Boost (too) makes it portable, e.g. to older g++ releases.
I have not yet looked at boost iostreams but it is on my todo list :-(. /ikh _______________________________________________________________________ This email has been scanned for all known viruses by the MessageLabs Email Security System. _______________________________________________________________________

On Wed, May 04, 2005 at 06:20:06PM +0100, Iain K. Hanson wrote:
Nathan Myers wrote:
Another goal is a zero-copy streambuf whose buffer is an mmap page that can be read into or written from without actually copying any bytes from kernel to user space, or back.
You will still at a minimum have another kernel to device copy as previously stated. Another problem is that mmap files *I think* need to be seek()able.
When speaking of zero-copy I/O, it is conventional not to count the act of moving bits between the wire and memory. In principle, it's true, one could conceive of operating on the bytes in real time without ever storing them. However, most people start and stop counting copies at the point where the data has landed in a kernel buffer, ready to DMA to or from a device. To mmap a file, it must be seekable, but that's not what I was describing. On NetBSD as on Linux, if a page of memory has been obtained via "anonymous" mmap, it is not actually mapping a file, it's just an page of physical memory handed over to the caller to write in, that may be returned to the system any time, independently of any other page. (On some systems, e.g. Solarix, you pretend to map /dev/zero, but that's just for tidiness.) Under UVM, if you have a page or run of pages mapped, and pass a pointer to the beginning of it to a system call, the kernel can claim those physical memory pages and map them into kernel space as regular buffers. Or, it can pick kernel buffer pages and expose them to that range in your address space, in place of whatever was there, all without copying bytes, What you see there is what the kernel wants you to see. It looks as if it copied from its buffer to yours, but you are really seeing its actual buffer. This is what is normally described as zero-copy I/O. It's quite an elegant way to rescue the apparently archaic read() and write() model of I/O from ignominy. The only problem is that fooling around with page maps can itself be quite expensive on a multiprocessor system. Nathan Myers ncm@cantrip.org

Hi Nathan, ----- Original Message ----- From: "Nathan Myers" <ncm@cantrip.org> To: <boost@lists.boost.org> Sent: Wednesday, May 04, 2005 3:55 PM Subject: Re: [boost] Re: (Another) socket streams library [snip]
The catch (for me) is that such a call is still blocking. The thread that performs the call (operator<<) must wait for the complete object off the stream.
Not quite. The idea is that operator>> will operate on known text obtained without blocking and without EWOULDBLOCK. I don't recall how one can tell how much is in an incoming socket buffer (nothing
ioctlsocket( socket, FIONREAD, &available ) Yep - non-portable.
very portable, in any case), but it is easy enough to tell if there's at least _something_ there: do a select() with a zero timeout, and see if it says it's ready. (More likely your regular select() loop woke up and told you so.) If so, trigger an underflow() (with sgetc(), say), which will get up-to-a buffer-full. (Make sure the buffer is at least as big as the OS's.) After there's text in the buffer, you can decide if it's enough to merit calling whatever is supposed to extract and operate on it.
I assume the caller (of operator>>) is "paused"?
A special streambuf can provide direct access to the buffer contents, too, so you can check if the input really is terminated. If it's not
What constitutes "really is terminated"? Are you parsing the stream in some way?
terminated, you can go back to sleep and wait for more (and for other events too). If it's terminated, you hand it over, and they process it, none the wiser. Of course they have to be willing to stop reading before EOF -- or at least not mess up their internal state if they are fed an EOF at an agreed-upon spot by our complicit streambuf. (We can clean up any fail/eof/bad flags after we get control back.)
We are at cross-purposes. The processing that you describe is very much what I have running in a production framework. Its just that the parts are moved around as a response to the "fundamental law"; there cannot be any "operator>>".
I don't care much how it's labeled, or how it fits into anybody's Grand Unified Theory of I/O. I just want to be able to plumb a nonblocking socket to code that only knows how to talk to a bog-standard istream or an ostream, and have reason to expect it
One day the name might be interesting, i.e. not today:-) An istream (i.e. specifically operator>>) blocks the calling thread until the object is complete. Application code in "truly async" software can never be blocked. I use quotes for "truly async" to acknowledge that its just a label for a certain category of software (e.g. telephony signaling systems). There are other categories. The code you want to plumb to a non-blocking socket is in one of those other categories. Cheers.

Scott, On Fri, May 06, 2005 at 08:51:43AM +1200, Scott Woods wrote:
From: "Nathan Myers" <ncm@cantrip.org>
Scott:
The catch (for me) is that such a call is still blocking. The thread that performs the call (operator<<) must wait for the complete object off the stream.
Not quite. The idea is that operator>> will operate on known text obtained without blocking and without EWOULDBLOCK. I don't recall how one can tell how much is in an incoming socket buffer (nothing
ioctlsocket( socket, FIONREAD, &available )
Ewwww, Win32. On Linux, documented as ioctl(fd, SIOCINQ, &available) [cf. tcp(7)], although SIOCINQ seems to be the same number as FIONREAD: 0x541B. :-) On the BSDs it seems to be documented as FIONREAD also. Thus, not entirely unportable; everybody seems to offer a way to get it, almost the same way.
very portable, in any case), but it is easy enough to tell if there's at least _something_ there: do a select() with a zero timeout, and see if it says it's ready. (More likely your regular select() loop woke up and told you so.) If so, trigger an underflow() (with sgetc(), say), which will get up-to-a buffer-full. (Make sure the buffer is at least as big as the OS's.) After there's text in the buffer, you can decide if it's enough to merit calling whatever is supposed to extract and operate on it.
I assume the caller (of operator>>) is "paused"?
I don't know what that means. If you're running and pawing at your streambuf, you're not paused by any definition I know of. The notional op>> hasn't been entered yet. You're deciding, first, whether there's enough stuff there to merit that.
A special streambuf can provide direct access to the buffer contents, too, so you can check if the input really is terminated. If it's not
What constitutes "really is terminated"? Are you parsing the stream in some way?
I prefer to say examining. (Parsing implies a grammar.) Parsing is something our notional op>> might do after we determine that it can run to completion without getting an EOF for EWOULDBLOCK. Does looking for an outermost matching "}", skipping comments and string literals, count as parsing? I don't think the answer matters. What matters is how you can use, in your async program, library Q that takes its input from an istream&.
terminated, you can go back to sleep and wait for more (and for other events too). If it's terminated, you hand it over, and they process it, none the wiser. Of course they have to be willing to stop reading before EOF -- or at least not mess up their internal state if they are fed an EOF at an agreed-upon spot by our complicit streambuf. (We can clean up any fail/eof/bad flags after we get control back.)
We are at cross-purposes. The processing that you describe is very much what I have running in a production framework. Its just that the parts are moved around as a response to the "fundamental law"; there cannot be any "operator>>".
If there can't be any operator>>, there's hardly any point to attaching the socket to a streambuf at all. I seriously doubt you are running anything like I have described. I *am* talking about calling op>>.
I don't care much how it's labeled, or how it fits into anybody's Grand Unified Theory of I/O. I just want to be able to plumb a nonblocking socket to code that only knows how to talk to a bog-standard istream or an ostream, and have reason to expect it
An istream (i.e. specifically operator>>) blocks the calling thread until the object is complete. Application code in "truly async" software can never be blocked.
All functions "block" the calling thread until they complete, so that definition doesn't mean anything. If you can determine that your notional op>> won't need more bytes than are certain to be available immediately, then it doesn't block, it executes and returns. If you make a mistake, the system call to obtain more bytes fails, reporting EWOULDBLOCK, your op>> sees EOF, and returns. Either way nobody has been blocked in any meaningful sense. I don't know from "truly async". I don't see why it was mentioned at all, or what it has to do with this thread. Nathan Myers ncm@cantrip.org

On Thu, 2005-05-05 at 20:16 -0700, Nathan Myers wrote:
Scott,
On Fri, May 06, 2005 at 08:51:43AM +1200, Scott Woods wrote:
From: "Nathan Myers" <ncm@cantrip.org>
Scott:
The catch (for me) is that such a call is still blocking. The thread that performs the call (operator<<) must wait for the complete object off the stream.
Not quite. The idea is that operator>> will operate on known text obtained without blocking and without EWOULDBLOCK. I don't recall how one can tell how much is in an incoming socket buffer (nothing
ioctlsocket( socket, FIONREAD, &available )
Ewwww, Win32.
On Linux, documented as ioctl(fd, SIOCINQ, &available) [cf. tcp(7)], although SIOCINQ seems to be the same number as FIONREAD: 0x541B. :-) On the BSDs it seems to be documented as FIONREAD also. Thus, not entirely unportable; everybody seems to offer a way to get it, almost the same way.
Yes. this is true of many options including ioctl, fnctl and socket options. they way to make it portable for the user is to spell them all socket_option and let the library take care of the implementation. /ikh _______________________________________________________________________ This email has been scanned for all known viruses by the MessageLabs Email Security System. _______________________________________________________________________

Hi Nathan, ----- Original Message ----- From: "Nathan Myers" <ncm@cantrip.org> To: <boost@lists.boost.org> Sent: Friday, May 06, 2005 3:16 PM Subject: Re: [boost] Re: (Another) socket streams library [snip]
The catch (for me) is that such a call is still blocking. The thread that performs the call (operator<<) must wait for the complete object off the stream.
Not quite. The idea is that operator>> will operate on known text obtained without blocking and without EWOULDBLOCK. I don't recall how one can tell how much is in an incoming socket buffer (nothing
ioctlsocket( socket, FIONREAD, &available )
Ewwww, Win32.
On Linux, documented as ioctl(fd, SIOCINQ, &available) [cf. tcp(7)], although SIOCINQ seems to be the same number as FIONREAD: 0x541B. :-) On the BSDs it seems to be documented as FIONREAD also. Thus, not entirely unportable; everybody seems to offer a way to get it, almost the same way.
I had agreed with you. Determining the value of "available" is non-portable.
see if it says it's ready. (More likely your regular select() loop woke up and told you so.) If so, trigger an underflow() (with sgetc(), say), which will get up-to-a buffer-full. (Make sure the buffer is at least as big as the OS's.) After there's text in the buffer, you can decide if it's enough to merit calling whatever is supposed to extract and operate on it.
I assume the caller (of operator>>) is "paused"?
I don't know what that means. If you're running and pawing at your streambuf, you're not paused by any definition I know of. The notional op>> hasn't been entered yet. You're deciding, first, whether there's enough stuff there to merit that.
Somewhere there is some traditional stream code that includes calls to opertor>>. What is that code doing while you determine when there is enough stuff?
A special streambuf can provide direct access to the buffer contents, too, so you can check if the input really is terminated. If it's not
What constitutes "really is terminated"? Are you parsing the stream in some way?
I prefer to say examining. (Parsing implies a grammar.) Parsing is something our notional op>> might do after we determine that it can run to completion without getting an EOF for EWOULDBLOCK. Does looking for an outermost matching "}", skipping comments and string literals, count as parsing? I don't think the answer matters. What matters is how you can use, in your async program, library Q that takes its input from an istream&.
"Examining" then.
terminated, you can go back to sleep and wait for more (and for other events too). If it's terminated, you hand it over, and they process it, none the wiser. Of course they have to be willing to stop reading before EOF -- or at least not mess up their internal state if they are fed an EOF at an agreed-upon spot by our complicit streambuf. (We can clean up any fail/eof/bad flags after we get control back.)
We are at cross-purposes. The processing that you describe is very much what I have running in a production framework. Its just that the parts are moved around as a response to the "fundamental law"; there cannot be any "operator>>".
If there can't be any operator>>, there's hardly any point to attaching the socket to a streambuf at all. I seriously doubt you are running anything like I have described. I *am* talking about calling op>>.
As I said, I am running something that has many of the parts. The plumbing and names are different. The standout difference is use of op>>.
I don't know from "truly async". I don't see why it was mentioned at all, or what it has to do with this thread.
Good point. Cheers.

On Mon, May 09, 2005 at 09:31:25AM +1200, Scott Woods wrote:
Hi Nathan, From: "Nathan Myers" <ncm@cantrip.org>
ioctlsocket( socket, FIONREAD, &available ) // w32
On Linux, documented as ioctl(fd, SIOCINQ, &available) [cf. tcp(7)], although SIOCINQ seems to be the same number as FIONREAD: 0x541B. :-) On the BSDs it seems to be documented as FIONREAD also. Thus, not entirely unportable; everybody seems to offer a way to get it, almost the same way.
I had agreed with you. Determining the value of "available" is non-portable.
No. What we have discovered is that determining the value of "available" really *is* portable, by any definition that allows Boost itself to be called portable. That's good.
see if it says it's ready. (More likely your regular select() loop woke up and told you so.) If so, trigger an underflow() (with sgetc(), say), which will get up-to-a buffer-full. (Make sure the buffer is at least as big as the OS's.) After there's text in the buffer, you can decide if it's enough to merit calling whatever is supposed to extract and operate on it.
I assume the caller (of operator>>) is "paused"?
I don't know what that means. If you're running and pawing at your streambuf, you're not paused by any definition I know of. The notional op>> hasn't been entered yet. You're deciding, first, whether there's enough stuff there to merit that.
Somewhere there is some traditional stream code that includes calls to opertor>>. What is that code doing while you determine when there is enough stuff?
What is any function "doing" that hasn't been called? Maybe a more concrete example would make things clearer. You have a real-time program running that watches several sockets, and maybe some hardware gadgets. It can't afford to block on any operation on any of the sockets, because then it will miss events on the other sockets or gadgets, so all the sockets are set non-blocking. On one of the sockets, somebody sends you XML documents. You don't know how to parse XML, or want to know; your program just needs a data structure to be built from the XML text. You have a library that understands XML, and can build a tree for you, and validate against a (pre-loaded) schema, the whole mess. The library takes an istream& (or, equivalently, a streambuf*). All you know about the library is that it will read until it sees a "</document>" tag, and then return a tree structure describing what it found. You know that if you give it a buffer already containing that magic "</document>" tag, it won't end up invoking the streambuf's underflow() (which would return EOF anyway), and when it returns the stream will be positioned right after that tag. So, whenever select() or what-have-you says the socket is readable, you have your boost-nonblocking-socket-streambuf gather up whatever is immediately available from it. You look at what it got to see if the magic tag is there. If you find it, you call your XML parser, which runs to completion without blocking, then you stash away the tree. Then (parsed or didn't) you go back to your event loop. (What is the XML library "doing" now? Who cares? You got your tree without doing any blocking system calls, and now you are ready for more events.) What do we need from this boost-nonblocking-socket-streambuf? At minimum, we need to see what it has in its buffer (i.e. begin()/end()), and we need for that buffer to grow as large as necessary until we can hand it to some library to be drained. (Maybe it's backed by a std::deque<char>.) Beyond that, it would be nice for it to abstract the calls to open and jimmy the socket. None of this is rocket science. Nathan Myers ncm@cantrip.org

Nathan Myers wrote:
What do we need from this boost-nonblocking-socket-streambuf? At minimum, we need to see what it has in its buffer (i.e. begin()/end()), and we need for that buffer to grow as large as necessary until we can hand it to some library to be drained. (Maybe it's backed by a std::deque<char>.) Beyond that, it would be nice for it to abstract the calls to open and jimmy the socket. None of this is rocket science.
I am concerned that this is only compatible with algorithms where the total amount of data to be read in a single operation is small enough to fit into a reasonable amount of buffer memory, and that this encourages dubious code by having very different interfaces for the very similar operations of /examining the data/ and /examining the data and removing the data from the buffer/. What do you think about an alternate scheme that requires the parser to be aware of the non-blocking interface of a stream? Add a would-block condition to the streambuf that is like EOF except it just means you're out of data, and add a mechanism for unlimited (and efficient) push-backs. Perhaps the istream might translate this into a blockbit flag and a mechanism to do this rollback automatically when extraction fails due to blockbit. Aaron W. LaFramboise
participants (5)
-
Aaron W. LaFramboise
-
Giovanni P. Deretta
-
Iain K. Hanson
-
Nathan Myers
-
Scott Woods