I/O event queue
The I/O event queue is what handles most of our I/O tasks. Now we'll go through
how we register events to that queue later on, but once an event is ready we
it sends the event_id
through our channel.
fn process_epoll_events(&mut self, event_id: usize) {
self.callbacks_to_run.push((event_id, Js::Undefined));
self.epoll_pending_events -= 1;
}
As we'll see later on, the way we designed this, we actually made our event_id
and callback_id
the same value since both represents an unique value for this
event. It simplifies things slightly for us.
We add the callback_id
to the collection of callbacks to run. We pass
in Js::Undefined
since we'll not actually pass any data along here. You'll see
why when we reach the `Http module chapter, but the main
point is that the I/O queue doesn't return any data itself, it just tells us that
data is ready to be read.
Lastly it's only for our own bookkeeping we decrement the count of outstanding
epoll_pending_events
so we keep track of how many events we have pending.
Why even keep track of how many
epoll_events
are pending? We don't use this value here, but I added it to make it easier to create someOne area we're taking shortcuts on all the way here is security. If someone were to build a public facing server out of this, we need to account for slow networks and malicious users.
Since we use
IOCP
, which is a completion based model, we allocate memory for a buffer for eachRead
orWrite
event. When we lend this memory to the OS, we're in a weird situation. We own it, but we can't touch it. There are several ways in which we could register interest in more events than occur, and thereby allocating memory that is just held in the buffers. Now if someone wanted to crash our server, they could cause this intentionally.A good practice is therefore to create a "high watermark" by keeping track of the number of pending events, and when we reach that watermark, we queue events instead of registering them with the OS.
By extension, this is also why you should always have a timeout on these events so that you at some point can reclaim the memory and return an timeout error if necessary.