Re: [Libevent-users] Re: IOCP writes
William Ahern wrote: I admittedly don't no anything about IOCP. What I do no is that it doesn't make sense to use any other function call then send() or sendto() to write out UDP data. So whatever API your writing around IOCP, it should short-circuit for UDP writes; just call send() to sendto(). But, that's all I'll say for now, since eventually I'm just going to look foolish for my lack of IOCP knowledge. Well, I think here in lack of knowledge has led you to point out something that I simply hadn't thought of because I've been thinking about everything in terms of IOCP. ___ Libevent-users mailing list Libevent-users@monkey.org http://monkey.org/mailman/listinfo/libevent-users
Re: [Libevent-users] Re: IOCP writes
On Thu, Feb 22, 2007 at 09:01:00PM +, Toby Douglass wrote: > However, I've just realized that it may make no difference. > > Writing to a UDP socket should never block; agreed. > > However, that multiple concurrent writes (one socket, many writer > threads) can occur, and so the internal mechanics of the IOCP API must > support that behaviour (assume we have enough bandwidth and the write > rate is low enough that we're not dropping packets). > > If I only have a single overlapped structure for writes, I cannot > support that behaviour. > > So I have to malloc the overlapped structure per write (or have the user > pass one in). I admittedly don't no anything about IOCP. What I do no is that it doesn't make sense to use any other function call then send() or sendto() to write out UDP data. So whatever API your writing around IOCP, it should short-circuit for UDP writes; just call send() to sendto(). But, that's all I'll say for now, since eventually I'm just going to look foolish for my lack of IOCP knowledge. ___ Libevent-users mailing list Libevent-users@monkey.org http://monkey.org/mailman/listinfo/libevent-users
Re: [Libevent-users] Re: IOCP writes
On Thu, Feb 22, 2007 at 08:26:22PM +, Toby Douglass wrote: > >Likely what the NIC can push out and what the link can > >handle is different, so trying to cater to the output buffer is a futile > >excercise, as far as I can see. > > So, the final implication is that users will ONLY ever perform serial > writes on a socket, no matter what it is? I'm not following. What I was trying to say is that I suspect the NIC will push packets onto the network faster than the network can handle. Meaning, trying not to overflow the local buffer doesn't buy you anything. Example: If the NIC is on a 100BaseT, but the gateway is on a T3, even if you didn't overflow the UDP stack locally, you'd still get tons of packet loss at the gateway, because it couldn't possibly forward them all onto the T3. In other words, trying to limit your send rate by using the local buffer as a throttle doesn't make sense; the local buffer is almost never the bottleneck, unless you've still got a USR Sportster on a serial cable ;) So, at the end of the day, to send UDP packets all you need to do is call send() or sendto(). No IOCP, no polling, no nothing. Everything goes out as discrete units, so you don't need anything worry about concurrent thread access or anything like that, either. You're socket writes will never get interleaved, since that's simply not the way UDP works at any level (protocol, implementation, or API). ___ Libevent-users mailing list Libevent-users@monkey.org http://monkey.org/mailman/listinfo/libevent-users
Re: [Libevent-users] Re: IOCP writes
Toby Douglass wrote: William Ahern wrote: On Thu, Feb 22, 2007 at 01:43:48PM -, Toby Douglass wrote: However, the example I had in mind (which is similar) is P2P apps, which use writes on a single local UDP socket to send peering information to peers. They would benefit from async writes on that socket. Writing to a UDP socket should never block, period. If the output buffer is full, and you write another message, it should force the stack to drop a message. Good point. I'd forgotten about that. However, I've just realized that it may make no difference. Writing to a UDP socket should never block; agreed. However, that multiple concurrent writes (one socket, many writer threads) can occur, and so the internal mechanics of the IOCP API must support that behaviour (assume we have enough bandwidth and the write rate is low enough that we're not dropping packets). If I only have a single overlapped structure for writes, I cannot support that behaviour. So I have to malloc the overlapped structure per write (or have the user pass one in). ___ Libevent-users mailing list Libevent-users@monkey.org http://monkey.org/mailman/listinfo/libevent-users
Re: [Libevent-users] Re: IOCP writes
William Ahern wrote: On Thu, Feb 22, 2007 at 01:43:48PM -, Toby Douglass wrote: However, the example I had in mind (which is similar) is P2P apps, which use writes on a single local UDP socket to send peering information to peers. They would benefit from async writes on that socket. Writing to a UDP socket should never block, period. If the output buffer is full, and you write another message, it should force the stack to drop a message. Good point. I'd forgotten about that. But, that could just as well have happened on the wire, so what's the difference? It would be more reliable not to fail locally if you could avoid it. The fact it *could* happen on the wire doesn't give us license to drop things when we could have avoided it. Likely what the NIC can push out and what the link can handle is different, so trying to cater to the output buffer is a futile excercise, as far as I can see. So, the final implication is that users will ONLY ever perform serial writes on a socket, no matter what it is? ___ Libevent-users mailing list Libevent-users@monkey.org http://monkey.org/mailman/listinfo/libevent-users
Re: [Libevent-users] Re: IOCP writes
On Thu, Feb 22, 2007 at 01:43:48PM -, Toby Douglass wrote: > > From: "Toby Douglass" <[EMAIL PROTECTED]> > >> As it is, it's easy to support serial writes with IOCP, it's supporting > >> multiple concurrent writes which is awkward for a convenient-to-use API > >> over IOCP - and this I would think is absolutely required for some uses > >> of UDP sockets. > > > I haven't tried any UDP async socket stuff, not with IOCPs nor anything. > > Tell us how it goes! > > Well, it's something I've rarely needed to do - in fact, only for P2P VOIP. > > However, the example I had in mind (which is similar) is P2P apps, which > use writes on a single local UDP socket to send peering information to > peers. They would benefit from async writes on that socket. Writing to a UDP socket should never block, period. If the output buffer is full, and you write another message, it should force the stack to drop a message. But, that could just as well have happened on the wire, so what's the difference? Likely what the NIC can push out and what the link can handle is different, so trying to cater to the output buffer is a futile excercise, as far as I can see. > > Still, I think I'm missing the point of multiple > > concurrent writes - wouldn't the output be undefined? > > Ah, no, because the destination on a UDP socket will be specified for each > write. For a TCP socket, your concern is correct, multiple async writes > would only be useful if each write was independent of every other write, > so the ordering of dispatch didn't matter. (We would also need to assume > each send() function call wrote its payload atomically with regard to > other send() function calls, which I think is true, although I don't know > that it is actually guaranteed). It is guaranteed. You may get truncation or fragmentation, but a UDP fragment is still a logical, discrete unit. ___ Libevent-users mailing list Libevent-users@monkey.org http://monkey.org/mailman/listinfo/libevent-users
[Libevent-users] Re: IOCP writes
From: "Toby Douglass" <[EMAIL PROTECTED]> I wrote: > On a related note, did someone say that the event handle in the overlapped > structure used by the IO functions (ReadFile, etc) is not actually used? > > If that's actually untouched, I could use it for my own purposes. The > alternative is probably a malloc() per write operation :-/ As it is, it's easy to support serial writes with IOCP, it's supporting multiple concurrent writes which is awkward for a convenient-to-use API over IOCP - and this I would think is absolutely required for some uses of UDP sockets. I haven't tried any UDP async socket stuff, not with IOCPs nor anything. Tell us how it goes! Still, I think I'm missing the point of multiple concurrent writes - wouldn't the output be undefined? -- felix: lightweight threads, HOFs and game scripting. svn co https://svn.sourceforge.net/svnroot/felix/felix/trunk felix ___ Libevent-users mailing list Libevent-users@monkey.org http://monkey.org/mailman/listinfo/libevent-users
[Libevent-users] Re: IOCP writes
> From: "Toby Douglass" <[EMAIL PROTECTED]> >> As it is, it's easy to support serial writes with IOCP, it's supporting >> multiple concurrent writes which is awkward for a convenient-to-use API >> over IOCP - and this I would think is absolutely required for some uses >> of UDP sockets. > I haven't tried any UDP async socket stuff, not with IOCPs nor anything. > Tell us how it goes! Well, it's something I've rarely needed to do - in fact, only for P2P VOIP. However, the example I had in mind (which is similar) is P2P apps, which use writes on a single local UDP socket to send peering information to peers. They would benefit from async writes on that socket. > Still, I think I'm missing the point of multiple > concurrent writes - wouldn't the output be undefined? Ah, no, because the destination on a UDP socket will be specified for each write. For a TCP socket, your concern is correct, multiple async writes would only be useful if each write was independent of every other write, so the ordering of dispatch didn't matter. (We would also need to assume each send() function call wrote its payload atomically with regard to other send() function calls, which I think is true, although I don't know that it is actually guaranteed). ___ Libevent-users mailing list Libevent-users@monkey.org http://monkey.org/mailman/listinfo/libevent-users
Re: [Libevent-users] Re: IOCP writes
On Thu, Feb 22, 2007 at 12:09:18AM +0100, Rhythmic Fistman wrote: > Issuing simultaneous asynchronous reads and writes on socket is a tiny bit > rare and special. Are you sure that's what you want to do? If so, great - > io completion queues can handle it. Bu-ut if libevent was modelled on the > unix > select-style interfaces, most of which don't easily support this kind of > thing, > how is this situation cropping up, assuming that this is just an IOCP port > of libevent? Almost all of my use of libevent involves simultaneous reads/writes, for relays which filter streams on-the-fly, in both directions. It was tricky at first, but over the course of several revisions it all settled out. *sigh* Someday I'll have to muster up the energy to change the name, because on this list its just damn confusing, but my buffered-IO implementation is in libevnet: http://www.25thandclement.com/~william/projects/libevnet.html Specifically, see src/bufio/socket.c and the functions bufio_socket_event_run bufio_socket_event_mod bufio_socket_event_del bufio_socket_event_add bufio_socket_poll_handler bufio_sink_poll_handler Cancellations were tricky. Also, what I fail to see in most async libraries is logic to handle re-entrancy from recursive callbacks. That's what the FRAME_PUSH/FRAME_POP calls are all about. evdns.c fails in this respect, last time I looked, as does c-ares; they'll just segfault. My lookup API, built around c-ares, works around the c-ares problem w/ what I consider an abysmal hack; I'm looking to maybe fork the guts into libevnet because my re-entrancy patches were rejected. Anyhow, lookup.c does much, much more than c-ares, ADNS, or evdns, combined. ___ Libevent-users mailing list Libevent-users@monkey.org http://monkey.org/mailman/listinfo/libevent-users
[Libevent-users] Re: IOCP writes
Rhythmic Fistman wrote: On 2/22/07, Toby Douglass <[EMAIL PROTECTED]> wrote: Yup. I'll be passing in a struct which contains that overlapped as its first member. When it comes back to be, I'll cast the overlapped pointer to my struct type. I think this means though I need a malloc per write, since I have to create the overlapped structure. That's bad, since the point of this is high throughput. I don't think malloc's going to eat that much into your io-bound code's performance, but if you're worried about it just reuse the same overlapped structure instead of re-mallocing it. I don't want to have to be in a situation where I have to cache my allocations - it's extra code to write and debug and it impacts upon the cleanliness and simplicity of the design. It's a shame, really - with serial async writes, the only malloc you do is up front, once, when the socket is handed over to the API. ___ Libevent-users mailing list Libevent-users@monkey.org http://monkey.org/mailman/listinfo/libevent-users
[Libevent-users] Re: IOCP writes
Rhythmic Fistman wrote: From: "Toby Douglass" <[EMAIL PROTECTED]> If that's actually untouched, I could use it for my own purposes. The alternative is probably a malloc() per write operation :-/ You shouldn't have to touch that stuff. What are you trying to do? Keep state on a per read/write basis. Currently I keep state on a per socket basis, but that's not enough to let you know which of an arbitrary number of writes has just completed. However, I'm not going to use the abovementioned rather awful method (which I only considered from lack of alternatives) because I'm going to hijack the OVERLAPPED pointer, which is the right way to do this (or the least wrong way). Issuing simultaneous asynchronous reads and writes on socket is a tiny bit rare and special. I agree, but there are so many possible users people are going to want to do it. Also, it's common enough I think - HTTP with keep-alive, you could want to implement that using async IO for both the read and the write on the socket. Are you sure that's what you want to do? If so, great - io completion queues can handle it. Bu-ut if libevent was modelled on the unix select-style interfaces, most of which don't easily support this kind of thing, how is this situation cropping up, assuming that this is just an IOCP port of libevent? That's a wider question. I'm simply implementing a dead-easy-to-use API on IOCP. The unixy case is trickier - I think only kqueues can handle two separate read/write readiness requests being queued up in separate invocations. With all the other interfaces (epoll, event ports, select) you can request read AND write readiness notification, but you have to do with the one system call (the select interface makes this obvious, the other less so). UNIX, I know athing. Well, not quite true, I know POSIX somewhat, but true enough here for the better IO mechanisms. ___ Libevent-users mailing list Libevent-users@monkey.org http://monkey.org/mailman/listinfo/libevent-users
[Libevent-users] Re: IOCP writes
Rhythmic Fistman wrote: I don't think you should be passing the same overlapped structure twice to WSARecv/Send. I'm pretty sure that the overlapped isn't "yours" until GetQueuedCompletionStatus says so. Try a unique overlapped structure for each overlappable call. Don't worry, I'm not re-using overlapped's like that. I've had just the one overlapped struct till now, because I only did reads, and you only have one read outstanding at a time. ___ Libevent-users mailing list Libevent-users@monkey.org http://monkey.org/mailman/listinfo/libevent-users
[Libevent-users] Re: IOCP writes
Rhythmic Fistman wrote: From: "Toby Douglass" <[EMAIL PROTECTED]> I've realised, though, that if you issue a write on a socket which currently has an outstanding reading, when the IOCP completes, you don't immediately know which operation has completed. You use two different OVERLAPPED structures. The pointers returned by GetQueuedCompletionStatus will be different. Yup. I'll be passing in a struct which contains that overlapped as its first member. When it comes back to be, I'll cast the overlapped pointer to my struct type. I think this means though I need a malloc per write, since I have to create the overlapped structure. That's bad, since the point of this is high throughput. The obvious answer is to use select() to check the socket when an IOCP completes, but that's very awkward, because of the race conditions, for the other operation could complete in the time between the IOCP complete and select() and you have multiple threads calling GQCS concurrently. Locking would be required, which would be Bad. That's doesn't sound right..., IOCP type progs really shouldn't need select. Quite right. ___ Libevent-users mailing list Libevent-users@monkey.org http://monkey.org/mailman/listinfo/libevent-users
[Libevent-users] Re: IOCP writes
From: "Toby Douglass" <[EMAIL PROTECTED]> >> I've realised, though, that if you issue a write on a socket which >> currently has an outstanding reading, when the IOCP completes, you don't >> immediately know which operation has completed. > > Obviously I used the completion key. Actually, that's wrong. On a related note, did someone say that the event handle in the overlapped structure used by the IO functions (ReadFile, etc) is not actually used? If that's actually untouched, I could use it for my own purposes. The alternative is probably a malloc() per write operation :-/ You shouldn't have to touch that stuff. What are you trying to do? Issuing simultaneous asynchronous reads and writes on socket is a tiny bit rare and special. Are you sure that's what you want to do? If so, great - io completion queues can handle it. Bu-ut if libevent was modelled on the unix select-style interfaces, most of which don't easily support this kind of thing, how is this situation cropping up, assuming that this is just an IOCP port of libevent? The unixy case is trickier - I think only kqueues can handle two separate read/write readiness requests being queued up in separate invocations. With all the other interfaces (epoll, event ports, select) you can request read AND write readiness notification, but you have to do with the one system call (the select interface makes this obvious, the other less so). -- felix: lightweight threads, HOFs and game scripting. svn co https://svn.sourceforge.net/svnroot/felix/felix/trunk felix ___ Libevent-users mailing list Libevent-users@monkey.org http://monkey.org/mailman/listinfo/libevent-users
[Libevent-users] Re: IOCP writes
From: "Toby Douglass" <[EMAIL PROTECTED]> > I'm adding support for IOCP writes. > > I've realised, though, that if you issue a write on a socket which > currently has an outstanding reading, when the IOCP completes, you don't > immediately know which operation has completed. Obviously I used the completion key. I didn't see it immediately because I'm already using that for something else, bah, hambug. I don't think you should be passing the same overlapped structure twice to WSARecv/Send. I'm pretty sure that the overlapped isn't "yours" until GetQueuedCompletionStatus says so. Try a unique overlapped structure for each overlappable call. -- felix: lightweight threads, HOFs and game scripting. svn co https://svn.sourceforge.net/svnroot/felix/felix/trunk felix ___ Libevent-users mailing list Libevent-users@monkey.org http://monkey.org/mailman/listinfo/libevent-users
[Libevent-users] Re: IOCP writes
From: "Toby Douglass" <[EMAIL PROTECTED]> I'm adding support for IOCP writes. I've realised, though, that if you issue a write on a socket which currently has an outstanding reading, when the IOCP completes, you don't immediately know which operation has completed. You use two different OVERLAPPED structures. The pointers returned by GetQueuedCompletionStatus will be different. The obvious answer is to use select() to check the socket when an IOCP completes, but that's very awkward, because of the race conditions, for the other operation could complete in the time between the IOCP complete and select() and you have multiple threads calling GQCS concurrently. Locking would be required, which would be Bad. That's doesn't sound right..., IOCP type progs really shouldn't need select. RF -- felix: lightweight threads, HOFs and game scripting. svn co https://svn.sourceforge.net/svnroot/felix/felix/trunk felix ___ Libevent-users mailing list Libevent-users@monkey.org http://monkey.org/mailman/listinfo/libevent-users