[FASTCGI] libfcgi in multi threaded app

Rob rclemley at booksys.com
Mon May 3 15:30:43 EDT 2010


  The variables mentioned (FCGI_MPXS_CONNS, FCGI_MAX_REQS, and 
FCGI_MAX_CONNS) are not referenced anywhere in either the libfcgi or the 
apache2 mod_fastcgi libraries.  They are set only in the code fragment 
you included, but never referenced.

However in the introduction to the spec, we find this (emphasis mine):

    After a FastCGI process accepts a connection on its listening
    socket, the process executes a simple protocol to receive and send
    data. The protocol serves two purposes. /*First, the protocol
    multiplexes a single transport connection between several
    independent FastCGI requests. This supports applications that are
    able to **process concurrent requests using event-driven or
    multi-threaded programming techniques. Second, within each request
    the protocol provides several independent data streams in each
    direction.*/ This way, for instance, both stdout and stderr data
    pass over a single transport connection from the application to the
    Web server, rather than requiring separate pipes as with CGI/1.1.

By using FCGX_Accept*_r*(), which keeps these streams separate, we're 
able to simultaneously handle multiple FastCGI connections within one App.

Also, in Appendix B, example #4, we see:

    4. Two instances of example 1, multiplexed onto a single connection.
    The first request is more difficult than the second, so the
    application finishes the requests out of order: [...]


I think the variables that we're discussing probably don't mean what you 
think they mean.

Rob


On 05/03/2010 01:32 PM, Dave Bender wrote:
> Section 4.1 ( http://www.fastcgi.com/devkit/doc/fcgi-spec.html#SA ) 
> states:
>
> FCGI_MPXS_CONNS: "0" if this application does not multiplex 
> connections (i.e. handle concurrent requests over each connection), 
> "1" otherwise.
>
> Seeing as how the library is limited to 1 connection and 1 request,
>
> On Mon, May 3, 2010 at 2:27 PM, Rob <rclemley at booksys.com 
> <mailto:rclemley at booksys.com>> wrote:
>
>     I cannot really address your question because you're touching
>     deeper into the internals of libfcgi and attempting to reconcile
>     it with "the spec", without explicit references to which part of
>     the spec.  I just don't have time to do that much research right now.
>
> Section 4.1 ( http://www.fastcgi.com/devkit/doc/fcgi-spec.html#SA ) 
> states:
>
> FCGI_MPXS_CONNS: "0" if this application does not multiplex 
> connections (i.e. handle concurrent requests over each connection), 
> "1" otherwise.
>
> This would imply connections are handled one at a time.
>
>     I would guess that you're missing some understanding of the
>     complete flow of processing web requests, and how the requests are
>     handled in the various nooks and crannies of FastCGI.
>
>     Rob
>
>
>
>     On 05/03/2010 12:22 PM, Dave Bender wrote:
>>     I'm also curious, how does the library even accept multiple
>>     requests simultaneously when the librar returns the following
>>     values for its management records:
>>
>>                 if(strcmp(name, FCGI_MAX_CONNS) == 0) {
>>                     value = '1';
>>                 } else if(strcmp(name, FCGI_MAX_REQS) == 0) {
>>                     value = '1';
>>                 } else if(strcmp(name, FCGI_MPXS_CONNS) == 0) {
>>                     value = '0';
>>                 } else {
>>                     name = NULL;
>>                 }
>>     (taken from fcgiapp.c, version 2.4.0)
>>
>>     According to the spec, the web server should only be sending 1 at
>>     a time.
>>
>>     -Dave
>>
>>     On Mon, May 3, 2010 at 1:14 PM, Martin Chapman
>>     <chapmanm at pixia.com <mailto:chapmanm at pixia.com>> wrote:
>>
>>         Rob,
>>
>>         So how does this solution account for the fact that
>>         FCGX_Accept_r () resets
>>         the stdio global structure each time it's called?  If you are
>>         synchronizing
>>         the code between each request, regardless of it's processed
>>         on a separate
>>         worker thread then only one request at a time is really being
>>         executed.
>>
>>         Martin
>>
>>
>>         -----Original Message-----
>>         From: fastcgi-developers-bounces+chapmanm=pixia.com
>>         <http://pixia.com>@mailman.fastcgi.com
>>         <http://mailman.fastcgi.com>
>>         [mailto:fastcgi-developers-bounces+chapmanm
>>         <mailto:fastcgi-developers-bounces%2Bchapmanm>=pixia.com
>>         <http://pixia.com>@mailman.fastcgi.com
>>         <http://mailman.fastcgi.com>]
>>         On Behalf Of Rob
>>         Sent: Monday, May 03, 2010 11:06 AM
>>         To: fastcgi-developers at mailman.pins.net
>>         <mailto:fastcgi-developers at mailman.pins.net>
>>         Subject: Re: [FASTCGI] libfcgi in multi threaded app
>>
>>          On 05/03/2010 10:27 AM, AlannY wrote:
>>         > I've created a socket via FCGX_OpenSocket. Everything all
>>         right.
>>         >
>>         > Then, I'm creating threads (5, for example). In each
>>         thread, I'm
>>         > creating a request with FCGX_InitRequest (with socket,
>>         created early and
>>         > FCGI_FAIL_ACCEPT_ON_INTR).
>>         >
>>         > Then the main loop starts. In this loop I'm calling
>>         FCGX_Accept_r on
>>         > this request. Here is trouble. Some of threads can
>>         successfully accept,
>>         > but some of then can't. Return code from FCGX_Accept is -9.
>>
>>         The main thread loop should repeatedly call FCGX_Accept_r().
>>           Requests
>>         successfully accepted by FCGX_Accept_r() must then be passed
>>         off to your
>>         worker threads for processing.  Therefore, you might choose to
>>         dynamically allocate an fcgi request structure before calling
>>         FCGX_Accept_r() and then pass the dynamically allocated request
>>         structure to an available worker thread.  The worker thread
>>         would then
>>         process the request and then deallocate the request.
>>
>>         The multi-threaded problem is: "how to pass the requests to
>>         the worker
>>         threads?"  Your program  will be simple and graceful if you
>>         choose the
>>         means of a synchronized queue data structure.  In a
>>         synchronized queue
>>         object, all of the thread synchronization is performed upon
>>         access to
>>         get or put items on the queue.   The mutex guards access to
>>         the internal
>>         data.  The conditions NotFull and NotEmpty signal the threads
>>         to wake up
>>         appropriately via the condition primitives: notify_one or
>>         notify_all.
>>         We use C++ and boost::threads to do something like this:
>>
>>         pseudo code for main thread:
>>
>>             synchronized_queue_class synchronized_queue  #this is the
>>         only
>>         object that must be visible from all threads
>>
>>             function get_fcgi_request( request )
>>                 request = allocate(sizeof request)
>>                 FCGX_init_request(request ...)
>>                 if FCGX_Accept_r(request) is successful
>>                 then return TRUE
>>                 else return FALSE
>>                 endif
>>             endfunction
>>
>>             while get_fcgi_request( request )
>>                 synchronized_queue.Put(request)
>>             endwhile
>>
>>         pseudo code for worker threads:
>>
>>             while synchronized_queue.Get(request)
>>                 process(request)
>>                 deallocate(request)
>>             endwhile
>>
>>         pseudo code for synchronized_queue_class:
>>
>>             class synchronized_queue_class:
>>                 queue internal_queue
>>                 condition notFull_condition
>>                 condition notEmpty_condition
>>                 mutex    monitor
>>
>>         procedure Put(item):
>>                     scoped_lock(monitor)
>>                     while internal_queue.full()
>>         notFull_condition.wait(monitor)
>>                     internal_queue.put(item)
>>                     notEmpty_condition.notify_one()
>>                 endprocedure
>>
>>         procedure Get(item):
>>                     scoped_lock(monitor)
>>                     while internal_queue.empty:
>>         notEmpty_condition.wait(monitor)
>>                     internal_queue.push(item)
>>                     notFull_condtion.notify_one()
>>                 endprocedure
>>
>>             endclass
>>
>>         (There are other details in the synchronized queue which
>>         should be
>>         addressed, such as how to shut down the  queue at the end of
>>         the program
>>         and tell the worker threads to exit.)
>>
>>
>>
>>
>>
>>         _______________________________________________
>>         FastCGI-developers mailing list
>>         FastCGI-developers at mailman.fastcgi.com
>>         <mailto:FastCGI-developers at mailman.fastcgi.com>
>>         http://mailman.pins.net/mailman/listinfo.cgi/fastcgi-developers
>>
>>         _______________________________________________
>>         FastCGI-developers mailing list
>>         FastCGI-developers at mailman.fastcgi.com
>>         <mailto:FastCGI-developers at mailman.fastcgi.com>
>>         http://mailman.pins.net/mailman/listinfo.cgi/fastcgi-developers
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.pins.net/mailman/private.cgi/fastcgi-developers/attachments/20100503/3ecbab82/attachment-0001.html>


More information about the FastCGI-developers mailing list