Re: Using select() with FASTCGI

Mark Brown (mbrown@OpenMarket.com)
Tue, 04 Jun 1996 17:18:16 -0400

Message-Id: <199606042118.RAA12432@breckenridge.openmarket.com>
To: fastcgi-developers@OpenMarket.com
Subject: Re: Using select() with FASTCGI
Date: Tue, 04 Jun 1996 17:18:16 -0400
From: Mark Brown <mbrown@OpenMarket.com>


Oops, this mail bounced and then got lost in my inbox.

I've attached a reply to some of Paul's points at the bottom.

   --mark

------- Forwarded Message
Date: Fri, 24 May 1996 18:43:30 +100 (BST)
From: Paul Mahoney <ptm@xact.demon.co.uk>
X-Sender: ptm@xact4.xact.com
To: Fastcgi Developers <fastcgi-developers@openmarket.com>
Subject: Re: Using select() with FASTCGI 
In-Reply-To: <199605231540.LAA09145@breckenridge.openmarket.com>
Message-Id: <Pine.SCO.3.90.960524181553.2308A-100000@xact4.xact.com>
MIME-Version: 1.0
Content-Type: TEXT/PLAIN; charset=US-ASCII
Sender: ptm@xact.demon.co.uk

On Thu, 23 May 1996, Mark Brown wrote:
> The fcgiapp library that exists today is not designed to support your
> requirement.  (fcgi_stdio is layered on fcgiapp, so it doesn't
> help you, either.)

Yes... I realised this once I started to study the code :-(

> Programming in the event-driven style using select() isn't a very
> comfortable fit with the stream-oriented style that fcgiapp
> implements.  An event-driven application has to be aware of how many
> bytes are available in the input buffer and must never attempt to read
> more than are available; it would be an application programming
> error to do so.  (I'm curious about your application; most
> Web applications don't do a lot of reading from stdin, so
> it works OK to read stdin to EOF before doing anything else.)

This application would only be reading "content" information from
FCGI_stdin, so the amount of data is given by CONTENT_LEN from the
environment. Also, reading past the end of the input buffer is not
a problem if you setup non-blocking i/o...

> If you accept this constraint then you could (a) expose the connection
> socket so that you could use it with select() and (b) expose a
> function to be called when select() indicates that data is available
> for reading from the socket.  If this work was done correctly it could
> be folded back into the shared code base.  If you are interested in
> pursuing this approach I could give you more advice offline.
> 
> My own idea for supporting concurrency within FastCGI applications is
> to exploit POSIX (and NT) threads.  This approach fits very well with
> streams and requires only minor surgery to the fcgiapp library.  It
> will allow us to support multiple connections and multiplexed
> connections as well as handling your type of requirement.  If you or
> others are interested in this topic, I would be glad to share some
> design sketches and get some feedback on them.

I'm not sure threads are very portable. My preference would be to select()
on whatever streams you need (including FCGI_LISTEN_FILENO) and when there
is something to read on fcgi, call some form of FCGI_Accept(). This call
would read the input from the web server and buila/maintain a structure
(object) that records the current state of each "connection" and any
associated environment. The fcgi application could then scan the current
list of these "connections" to see which have become "complete" with
respect to input from the web server. 

Any "complete" "connection" would then be processed by the fcgi
application. This may require, as in my case, the application to send
messages to another system and await a reply.... so it goes back to the
select() loop. Once it gets the reply it locates the "connection" to which
it relates, sends the results back to the web server and "closes" the
connection. 

Of course, while it is waiting for a reply, additional input may appear on
the FGCI socket and, consequently, other "connections" may be "opened" or
existing ones become "complete". Thus multiple "connections" can be
maintained, and any "connection" that will a long time to process will not
block any other, or new, connections. 

All of this is academic if the web server fastcgi implementations do not
support connection multiplexing... I'm trying to use Apache for this work. 

I hope this makes some sense... it's a bit off the top of my head.
Anyway, I'm just off on holiday for two weeks. Please mail me if you want
to discuss this further. I'll get back to you when I return.

- ---
Paul Mahoney, X-Act Solutions Limited
smail: Owlsmead, Meads Road, Little Common, Bexhill-on-Sea, East Sussex TN39 
4SY
email: ptm@xact.demon.co.uk ... pmahoney@cix.compulink.co.uk
phone: +44 424 846368

------- End of Forwarded Message

Paul, you say:

    This application would only be reading "content" information from
    FCGI_stdin, so the amount of data is given by CONTENT_LEN from the
    environment. Also, reading past the end of the input buffer is not
    a problem if you setup non-blocking i/o...

The problem I anticipate is this.  Your application
calls getc on stdin.  Down inside the implementation
of stdin (fcgiapp in this case) you discover that the input
buffer is empty.  Now what?  What does getc return to tell
your application "Sorry, the input buffer is empty, please go
away and come back when you've gotten me more data"?

This is what I mean by saying that streams and event-driven
programming are not a comfortable fit.

    ... The fcgi application could then scan the current
    list of these "connections" to see which have become "complete"
    with respect to input from the web server. 
   
What this amounts to, I think, is to maintain for each stream
a count of how many bytes can be read/written without blocking.
And define any attempt to read from an empty buffer or write to a full
buffer as giving an error return.

In practice I suspect that you get 80% of the benefit with 5% of the
work by doing an outer select that includes FCGI_LISTENSOCK_FILENO and
whatever other FDs might be interesting.  If FCGI_LISTENSOCK_FILENO
turns up readable then call FCGI_Accept, which won't block waiting for
a connection, and then run the request to completion.  You
might want the ability to configure and output buffer bigger than
the current wired-in 8K bytes.

    All of this is academic if the web server fastcgi implementations do not
    support connection multiplexing... I'm trying to use Apache for this work. 

A single application process could accept multiple (non-multiplexed)
connections -- with a little more work in fcgiapp.c.  So the
application can benefit even if the server doesn't multiplex
connections.

    --mark