[FASTCGI] libfcgi in multi threaded app

Dave Bender codehero at gmail.com
Mon May 3 15:51:24 EDT 2010


Please see function ProcessBeginRecord, line 1536:

       /*
         * The Web server is multiplexing the connection.  This
library
         * doesn't know how to handle multiplexing, so respond with
         * FCGI_END_REQUEST{protocolStatus = FCGI_CANT_MPX_CONN}
         */

Examining FCGX_Accept_r() indicates no more than one connection is open at a
time. Since connections cannot multiplex and only one connection is open at
a time, only one request may be active.

On Mon, May 3, 2010 at 3:45 PM, Dave Bender <codehero at gmail.com> wrote:

>
>
> On Mon, May 3, 2010 at 3:30 PM, Rob <rclemley at booksys.com> wrote:
>
>>  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.
>>
>>
> The only way the web server knows whether the fastcgi server can actually
> multiplex is through these variables. These variables are what inform the
> web server of the fastcgi server's capabilities. libfcgi reports it is
> incapable of multiplexing requests. Being hard coded responses, they are
> trivially not referenced by the rest of the code.
>
>
>> 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.
>>
>
>  Your conclusion is incorrect. There are only two input streams per
> request: params and stdin; these streams are not even concurrent; params
> must precede stdin. There are only two output streams per request: stdout
> and stderr. Keeping these streams separate is handled by parsing the headers
> of each packet, not by calling FCGX_Accept(_r)
>
> Looking through the source, the first thing that FCGX_Accept_r does is call
> FCGX_Finish_r.
>
>>
>> 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.
>>
>
>  Please read the spec and the source code more carefully.
>
>>
>> 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> 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>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 at mailman.fastcgi.com
>>>> [mailto:fastcgi-developers-bounces+chapmanm<fastcgi-developers-bounces%2Bchapmanm>
>>>> =pixia.com at mailman.fastcgi.com]
>>>> On Behalf Of Rob
>>>> Sent: Monday, May 03, 2010 11:06 AM
>>>> To: 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
>>>> http://mailman.pins.net/mailman/listinfo.cgi/fastcgi-developers
>>>>
>>>> _______________________________________________
>>>> FastCGI-developers mailing list
>>>> 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/92ccf795/attachment-0001.html>


More information about the FastCGI-developers mailing list