Hacker News new | comments | ask | show | jobs | submit login

Perhaps because I am not really a low level programmer it strikes me odd that "receive packet" is a call. I would expect to pass a function pointer to the driver and be called with the packet address every time one has arrived.

For your own sanity, you want some control over which thread is processing a packet, and at what point it does so. The easiest way to do this is to explicitly notify the kernel when you are in fact interested in another packet, and whether you wish your thread of control to be suspended until such a packet arrives if there is no next packet.

The JavaScript model of "call some callback when the currently-executing function returns" doesn't work, because C is not event-based. The embedded model of "interrupt whatever's happening and invoke some handler on the current thread of control" is just an absolute nightmare to deal with.

"The JavaScript model of "call some callback when the currently-executing function returns" doesn't work,"

I can't prove it, but at this scale, I am guessing that the cost of constructing call frames to call into the callback will start to matter, too. Switching into an already-existing context is probably significantly cheaper. (Well, it's definitely significantly cheaper to switch into an existing C context than construct a Javascript call, but, that's sort of cheating. Or a low blow. Or something like that.)

Not even remotely... To setup for a call to a C function is a matter of a handfull of instructions. To setup a context switch is hundreds.

If you're talking about kernel context switches, the JS has them too, and then has more instructions to set up the JS call stack to boot. Setting up a million JS call stacks is not necessarily trivial. A million here, a million there, soon you're talking real wall-clock time.

> The JavaScript model of "call some callback when the currently-executing function returns" doesn't work, because C is not event-based.

This is misleading. Whether or not a C program is event-based is not defined by the language; the language itself has the necessary features. On the flip side, Javascript is not necessarily confined to event-based operation - this is dependent on the engine it's running in.

That's how I/O completion routines have worked on NT since its debut. (And, more recently, threadpool I/O callbacks since Vista, and RIO dequeue since Windows 8.)

It all comes back to how the kernel can get data back to the caller: https://speakerdeck.com/trent/pyparallel-how-we-removed-the-....

Windows has a distinct advantage thanks to design decisions made in VMS by Cutler et al; namely, I/O via I/O request packets, and much better memory management.

POSIX systems are at a disadvantage because of the readiness-oriented nature of I/O, leaving the caller responsible for "checking back" when something can be done, versus "here, do, this, tell me when it's done". (https://speakerdeck.com/trent/pyparallel-how-we-removed-the-...)

Check out lines 74 to 87: https://gist.github.com/geyslan/5174296

  ; Preparing to listen the incoming connection (passive socket)
  ; int listen(int sockfd, int backlog);
  ; listen(sockfd, 0);

  mov eax, 102		; syscall 102 - socketcall
  mov ebx, 4		; socketcall type (sys_listen 4)

  ; listen arguments
  push 0		; backlog (connections queue size)
  push edx		; socket fd

  mov ecx, esp		; ptr to argument array

  int 0x80		; kernel interruption (this is the "receive packet" call along with MOVs above)
We in userland are the ones responsible for calling that interruption in another thread and deciding what that thread should call when it's done. The low-level stuff is only concerned with system calls, not managing them for us.

Applications are open for YC Summer 2019

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact