IoProcessor loop

Introduction

The IoProcessor instances are the place where we handle all the incoming and outgoing activity. It's an infinite loop, waiting for an event to occurs on the underlying transport.

The loop

Here is the description of this loop :

do forever
  int nbSelected = select( timeout )

  if nbSelected is null && we haven't been woke up && we haven't wait for the complete duration
    then something wrong has happened on the selector (probably the JDK bug
      create a new selector, and move all the keys to this new selector

  otherwise
    handle the newly created sessions (created by the IoAcceptor)
    set the Interest flags to read and write for the session
    process the selected sessions
    flush the waiting data to clients
    remove closed sessions
    notify the idle sessions
    quit if the number of sessions is null
done

As we can see, we have many different events to deal with, one of them being a corned case due to a bug in the recent JDKs.

Newly created sessions handling

When a new session is created in the IoAcceptor, its associated channel has to be registered on the selector. As the acceptor is running in a separated thread, it enqueue the newly created session, and wake up the IoProcessor, which will process this new session immediately before doing anything else.

The new session is initialized, which means its channel is registered on the selector, a copy of the service filter chain is stored within the session, and a SESSION_CREATED event is fired.

If something went wrong during this initialization, depending on whether the session has been registered on the selector or not, we destroy the session or add it the the queue of sessions to be deleted, after having fired an EXCEPTION_CAUGHT event.

Traffic Mask update

We now have to register the operations the newly opened sessions is likely to allow (OP_READ or OP_WRITE). This is done in this step.

As the session can be in different states, we act differently.

  • OPENING : We can't do anything right now, so we push back the session at the end of the queue for the next loop
  • CLOSING : Nothing to do
  • OPENED : now we can update the masks.

Processing the selected session

It's now time to handle reads and writes for each selected session. (One important thing is that while trying to read or write from the session's channel, the channel might have been closed in the meantime.)

Writes are easier to process than reads. If the session is scheduled for a flush, we just add it to the list of session to flush, and it will processed in the next step.

Reads is slightly more complex. It first depends on the type of transport we are using. For TCP transport (Socket or Datagram), we try to read a certain amount of data, depending on the default buffer size. Then we send the read buffer to the chain.

Here, we could have done better : no need to split the message in many fragments when there are more bytes available than the size of the buffer. We should read as much bytes as possible, and only then push them to the chain.

Added by Emmanuel Lécharny, last edited by Emmanuel Lécharny on Jul 30, 2009  (view change)