Squeak Socket Primitives

Craig Latta Craig.Latta at NetJam.ORG
Thu Nov 11 08:35:38 UTC 1999


Hi--

	I will attempt to limit myself to one novel-- er, message per day on this topic... I'll try not to repeat what's already been said (unless it seems worthwhile :).

	Lex writes:

> If a VM implementor wants to, they can have a thread listening
> on each socket so that semaphores will be signalled immediately
> when they become ready. I think the Mac port does so already.

	The Mac does use interrupt-driven callbacks in the VM, provided via MacTCP. But MacTCP is going bye-bye.

> Thus, you don't need a new primitive suite to support what you
> are describing, right?

	Right; it only matters if you want optimal performance and maximal simplicity in implementation and debugging.

> Maybe there are other reasons to have new primitives, though?

	Hey, I read my mind! :)

> Also, an important question that everyone is ducking so far is,
> what is the *practical* difference with polling versus using OS
> wake-up events?

	It's the *latency* associated with responding to a socket event.

> ...it seems like you can't avoid some socket state checks no matter 
> what you do--for instance, it's critical to keep verifying that the
> socket is still connected before you try anything else.

	The host socket library, in concert with the primitive failure mechanism (in the VM), can do that for you. 

	Yoshiki writes (please forgive my editing):

> ...I would be happy if I could write the network support
> code without using non-blocking sockets or polling.
> But if the answer is OS-level threads, I can't agree with
> it. The threads of the Zaurus OS are so limited that, for
> example, one cannot even kill them.

	If the host doesn't support threads adequately, then naturally we can't use them. But I think we should use them if it does.

> Apart from the Zaurus OS and network support, I think the last
> thing on which Squeak should depend is OS-native threading,
> whose API and behavior vary from platform to platform.

	I think the benefits of performance and simplicity outweigh that platform-dependence. I'll maintain that position until someone rewrites the IP stack in Slang.

	John writes:

> The cost of an extra test in the Smalltalk code once per
> incoming packet is utterly insignificant relative to the overhead
> of transferring the data.

	Hmm. At this point I need to come back with benchmarks. I plan to do this... The servers I'm writing (streaming interactive multi-way audio with many active clients) will send any framework through the ringer.

> What *would* be inefficient would be a busy loop polling the
> socket status. However, such polling isn't needed because the
> client waits on the semaphore until something actually happens.

	That's in Smalltalk-process land. In VM-land, we have things like sqPoll() on win32, which is pretty inefficient.

> ...there are several ways to allow one Squeak thread to
> wait for reading independently of another thread that is waiting
> for writing...

	Good points, but the techniques you describe are inefficient. I suppose I'm too quick to associate correctness with efficiency.

	Andreas writes:

> I spent half the night looking into Craig's set of primitives for the
> correspondents framework...

	Half as long as I spent writing the comparison. :)

> ...there has been too much talking about the primitive support
> without anybody giving it a really close look...

	...except for me. ;)   (self horn toot)

> I felt the need of getting at least some ground into this discussion.

	What does that mean?

> Other than [the Correspondents primitives providing immediate 
> notification for socket events, instead of monitoring all socket 
> transitions in one line of control], the functional differences between 
> the correspondant prims and current squeak prims are practically
> non-existent.

	Er, okay... isn't that point pretty important? Leaving aside the rest of my points, I also think the benefit of implementational simplicity is important. I daresay the Squeak team has waxed nearly poetic about that in the past...

> That correspondents uses blocking calls is irrelevant since it
> makes sure that the socket can be read/written by guarding these
> calls with the appropriate checks of the status.

	I assume you meant "it makes sure that the socket can be read/written by guarding these calls with the appropriate checks of the *opcode*" (connecting, accepting, reading, or writing). This does render the use of blocking calls irrelevant in the slightest! It just minimizes the number of host threads. The real point is that waiting is performed by the host's kernel [in select()], instead of by a polling mechanism that the VM implementor wrote.

> ...bypassing these checks can get you in a tight spot since the
> blocking VM call will stop Squeak completely and because of this
> I'd rather go for non-blocking sockets here...

	Huh? If you're doing the work in a host thread, the main VM process is unaffected. That's why I use threads. Make the host kernel earn its existence! :)

> ...but that is a matter of taste.

	I think it is instead a matter of performance and simplicity (sorry, I know I'm repeating myself now).

> Using blocking sockets just helps to lower the CPU cycles on an
> inactive task and give more to the other processes having some
> actual work to do.

	Sounds good to me!

> [Craig says] "In my implementation, there are two separate
> host threads per socket. One is for connecting and reading, the
> other is for writing. Sockets are used in blocking mode."  I...
> interpreted [this] as 'there are two threads, one performing
> blocking connections and reads, the other one blocking writes',
> [which] was a misinterpretation.

	'Sorry for not being clear. I think a short summary for the rest of the audience is in order here. Each host thread waits for two things. First, it waits for an indication from Smalltalk that Smalltalk would like to perform a particular operation. Then, it waits for the socket event associated with that operation. See, e.g., openAndHandleReadingRequests() in my implementation.

> From all of the above it is clearly the case that there is no actual
> need to get away from the current set of primitives for any
> functional reasons.

	I don't think that follows at all. I suppose we're discarding the simplicity-of-implementation point by default (deep sigh), but, further, you're implicitly accepting the suboptimal performance of the current design.

> ...my recommendation is to stay with the current primitive set and 
> consider an inclusion of the optional primitive 'Socket>>signal: 
> aSemaphoreIndex forOperation: opCode timeout: timeOutMSecs
> socket: socketHandle' from the correspondents framework...

	Well, this would certainly be a lot better than the status quo.


	For those of you still reading... Hi! Have you ever considered the benefits of a truly nice set of encyclopaedias?

	Okay, I'm finished. :)


-C


--
Craig Latta
composer and computer scientist
craig.latta at netjam.org
www.netjam.org
latta at interval.com
Smalltalkers do: [:it | All with: Class, (And love: it)]





More information about the Squeak-dev mailing list