Closed Bug 497799 Opened 15 years ago Closed 15 years ago

httpd.js hangs on large writes

Categories

(Testing :: General, defect)

defect
Not set
normal

Tracking

(Not tracked)

RESOLVED WORKSFORME

People

(Reporter: johnjbarton, Unassigned)

References

Details

(Whiteboard: )

On 1.9.2 the FBTest console/1693/Issue1693.js hangs the browser (not responding).

Our files for this test case:
http://code.google.com/p/fbug/source/browse/#svn/tests/content/console/1693
They are not useful directly, but the case is also simple. (We are working towards a single - XPI install to run our tests, but it will probably a few weeks.)

 With Boris' help I narrowed it down as below, starting from the threads when it hangs.

--------
Boris Zbarsky wrote:
> John J Barton wrote:
>> mozilla::Monitor::Wait seems interesting:
>
> Indeed!
>
>>  >    xpcom_core.dll!mozilla::Monitor::Wait(unsigned int)  Line 123    C++
>>      xpcom_core.dll!nsPipeOutputStream::Wait()  Line 1012    C++
>>      xpcom_core.dll!nsPipeOutputStream::WriteSegments(unsigned int (nsIOutputStream *, void *, char *, unsigned int, unsigned int, unsigned int *)*, void *, unsigned int, unsigned int *)  Line 1121    C++
>
> OK, looks like a blocking pipe and someone tried to write more data to 

Well that test case title is:
  Viewing requests with large message bodies in Console tab temporarily
  freezes browser
so you seem to be on to something...

> it than it can hold... so it blocked.  Who's supposed to be reading the data?  And are they trying to do it on the same thread or something?

Looks like the problem is related to httpd.js from the 1.9.2 tree:

  this._output = new BinaryOutputStream(output);
...
  this._output.writeByteArray(data, data.length);
For data.length = 468890, this call never completes.

The test case locks the browser if I use httpd.js from 1.9.2 on FF 3.0.10.

The test case succeeds of I use httpd.js from 1.9.1 on FF 3.0.10.

-----------------

I added dumpn calls around the statement above to verify the point of the last call.


Advice on a workaround would be welcome.
Flags: wanted1.9.2?
jwalden+code@mit.edu failed to add.
Whiteboard: [firebug-p2]
So what confuses me is that httpd.js doesn't seem to use any finite-length pipes (which are the ones that could actually block).  John, I'd really appreciate a js stack here, or explicit steps to reproduce starting with a vanilla Firefox install.
The 192 httpd.js has no dependencies on 192-specific functionality at this point -- the only bit was removed in bug 396226 -- and if you modify that test to use asynchronous response generation and yield appropriately (dispatch events to the thread manager to iterate through writing out all the data) you're still in good shape.

The problem you're encountering here is one peculiar to a single-threaded server residing in the same thread as the client reading from it.  The server tries to write output to the socket output stream -- which internally is a pipe, as I recall (so the pipe that's blocking isn't one in httpd.js at all) -- and the buffer gets filled up.  Since the same thread is the only code that tries to empty that buffer, you hang.  The reason 191 didn't have this is that it used an async stream copier that wrote out incrementally; I might be able to hack that into the current code, but it's a little tricky due to the functionality added in bug 396226.

In any case if you're updating httpd.js I recommend modifying the request handler as I first mentioned and going with that for now.  This hazard has always been mentioned in the server's IDL, and it's easy enough to work around the problem anyway.
Component: Networking → httpd.js
Flags: wanted1.9.2?
OS: Windows XP → All
Product: Core → Testing
QA Contact: networking → httpd.js
Hardware: x86 → All
Unfortunately I don't quite understand what you mean. Maybe Honza understands ir better. I could probably fix the 191 version, I narrowed it down to a new API call.
By async response generation I mean the processAsync() method, writes from a sequence of events dispatched at the current thread (the main thread), ending with a finish().  See the document below for an example of how this would work:

https://developer.mozilla.org/En/HTTP_server_for_unit_tests
Thanks, but I am not successful. I changed are code to add the processAsync():
FBTest.registerPathHandler("/console/1693/issue1693.php", function (metadata, response)
    {
        response.processAsync(); // see https://bugzilla.mozilla.org/show_bug.cgi?id=497799

        response.setHeader("Content-Type", "text/html", false);
        var text = "";
        for (var i=0; i<80000; i++)
            text += i + " ";
        window.dump("begin response.write with processAsync\n");
        response.write(text);
        window.dump("done response.write\n");
    });
But in 20090605 Shiretoko/3.5pre it hangs on the writeByteArray call:

begin response.write with processAsync
*** _startAsyncProcessor()
*** _sendHeaders()
*** header post-processing completed, sending response head...
*** starting async copier of body data...
*** onStartRequest
*** _waitForData
done response.write
*** complete()
*** onInputStreamReady
avail; 468890
onInputStreamReady to writeByteArray data length:468890
(hang)
You missed the part where I said you need to do the writes from a sequence of events dispatched at the main thread -- you need to yield for data to be read from the socket, using the XPCOM thread manager and dispatchEvent({run: function() { ... }}).
Resolving this as it is working as designed.
Status: NEW → RESOLVED
Closed: 15 years ago
Resolution: --- → WORKSFORME
Whiteboard: [firebug-p2] →
Component: httpd.js → General
You need to log in before you can comment on or make changes to this bug.