RejectedSoftware Forums

Sign up

TCP "select"?

Does vibe.d's TCP stuff have anything along the lines of the
BSD-style sockets select()?

Re: TCP "select"?

On Mon, 5 Nov 2012 23:06:20 -0500, Nick Sabalausky wrote:

Does vibe.d's TCP stuff have anything along the lines of the
BSD-style sockets select()?

Not in that exact form, but using rawYield() until InputStream.dataAvailableForRead() (on any of the connections) becomes true would be similar for waiting for the first data that comes available.

But usually it would be simpler/more robust to just have a separate task for each connection that performs normal, blocking operations. A vibe.core.signal.Signal can then be used to wake up a central coordinator task that handles each event appropriately.

Re: TCP "select"?

On Tue, 06 Nov 2012 08:07:42 GMT
"Sönke Ludwig" sludwig@rejectedsoftware.com wrote:

On Mon, 5 Nov 2012 23:06:20 -0500, Nick Sabalausky wrote:

Does vibe.d's TCP stuff have anything along the lines of the
BSD-style sockets select()?

Not in that exact form, but using rawYield() until
InputStream.dataAvailableForRead() (on any of the connections)
becomes true would be similar for waiting for the first data that
comes available.

But usually it would be simpler/more robust to just have a separate
task for each connection that performs normal, blocking operations. A
vibe.core.signal.Signal can then be used to wake up a central
coordinator task that handles each event appropriately.

Yea, that's what I ended up deciding to do anyway. I'm doing a
multiplayer game server, so I was thinking of having one task per "game
session", so the game session has easy access to each player's TCP
socket. But as I thought about it more, I realized: 1. That may
complicate the handling of connecting/disconnecting (esp. since each
game session is locked to the same players, similar to chess), and 2.
That design might not scale as easily to a load-balanced cluster of game
servers. (Then again, maybe I was wrong...Damn, I gotta
think about it some more...)

I did want to ask about the signal stuff though, to get a better feel
for it:

What sorts of expected use-cases is that for?

Does it make sense to have different signals to the same task
indicating different things?

If you signal twice in a row (either the same signal twice, or once with
one signal and then once with a different signal), does the target task
get woken up twice, or just once and then, if it needs to, it queries
the change in the count value to see how many times it was signaled?

What if the count value wraps around?

Is it like Posix OS "signals" (which I'm not super familiar with) or a
more general (more light-weight? or are those already light-weight?)
concept of signaling?

(I gather that the signaling is all done with libevent, but
unfortunately I'm not entirely familiar with that either.)

Re: TCP "select"?

Am 07.11.2012 00:20, schrieb Nick Sabalausky:

On Tue, 06 Nov 2012 08:07:42 GMT
"Sönke Ludwig" sludwig@rejectedsoftware.com wrote:

On Mon, 5 Nov 2012 23:06:20 -0500, Nick Sabalausky wrote:

Does vibe.d's TCP stuff have anything along the lines of the
BSD-style sockets select()?

Not in that exact form, but using rawYield() until
InputStream.dataAvailableForRead() (on any of the connections)
becomes true would be similar for waiting for the first data that
comes available.

But usually it would be simpler/more robust to just have a separate
task for each connection that performs normal, blocking operations. A
vibe.core.signal.Signal can then be used to wake up a central
coordinator task that handles each event appropriately.

Yea, that's what I ended up deciding to do anyway. I'm doing a
multiplayer game server, so I was thinking of having one task per "game
session", so the game session has easy access to each player's TCP
socket. But as I thought about it more, I realized: 1. That may
complicate the handling of connecting/disconnecting (esp. since each
game session is locked to the same players, similar to chess), and 2.
That design might not scale as easily to a load-balanced cluster of game
servers. (Then again, maybe I was wrong...Damn, I gotta
think about it some more...)

I did want to ask about the signal stuff though, to get a better feel
for it:

What sorts of expected use-cases is that for?

Does it make sense to have different signals to the same task
indicating different things?

Since signals only provide wait() with no additional information
attached, it usually makes more sense to use only one signal and use
some kind of additional state variable that indicates what happened. But
signals should be pretty lightweight (at least in the non-finished Win32
back end they are, I would have to test it for libevent) and as such
there would be no problem to do something like this:

Signal[] signals;
//...
int[] refs;
foreach( s; signals ){ s.acquire(); refs ~= s.emitCount; }
while(true){
	foreach( i, s; signals ){
		auto ec = s.emitCount;
		if( refs[i] != ec ){
			signal 1 was emitted refs[i]-ec times
		}
	}
	rawYield();
}

If you signal twice in a row (either the same signal twice, or once with
one signal and then once with a different signal), does the target task
get woken up twice, or just once and then, if it needs to, it queries
the change in the count value to see how many times it was signaled?

Currently it can be both - the destination tasks are woken up multiple
times but the emit count may already be incremented by more than one on
the first run and not incremented at all on the next wake events. So the
emitCount always has to be checked.

What if the count value wraps around?

A reasonably safe way should be to take the difference of the last
recorded emitCount and the current one, which should be very hard to get
up to int.max. There are not supposed to be any other effects apart
from the wrapping itself.

Is it like Posix OS "signals" (which I'm not super familiar with) or a
more general (more light-weight? or are those already light-weight?)
concept of signaling?

(I gather that the signaling is all done with libevent, but
unfortunately I'm not entirely familiar with that either.)

I need to check for libevent to be sure, but at least they are supposed
to be as lightweight as possible. On Windows they are implemented using
a call to PostThreadMessage, which could be better, but there is
always potential to optimize using an HEVENT or something.