[FASTCGI] libfcgi in multi threaded app
Dave Bender
codehero at gmail.com
Mon May 3 15:45:23 EDT 2010
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/0e7f9419/attachment.html>
More information about the FastCGI-developers
mailing list