Closed Bug 176919 Opened 22 years ago Closed 22 years ago

support for async input/output streams

Categories

(Core :: Networking, defect)

defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla1.3beta

People

(Reporter: darin.moz, Assigned: darin.moz)

References

(Blocks 3 open bugs)

Details

Attachments

(13 files, 1 obsolete file)

with the current mozilla architecture, data is pushed from the transport layer,
through the protocols, up to the consumers.  each layer must process all the
data pushed to it (via OnDataAvailable).  this requirement often complicates
stream listener implementations (e.g., additional buffering).

instead, consumers should be able to "ask" to be notified when an input stream
(or output stream) becomes "ready" ... by "ready" i mean either closed,
readable, or writable.  then consumers could be in complete control of the data
flow.

i think a lot of networking code could be simplified if the streams could tell a
consumer when they are ready.

i've put together a prototype implementation of nsPipe that provides these
interfaces:

  nsIAsyncInputStream : nsIInputStream
  {
    void asyncWait(in nsIInputStreamListener listener);
  }
  nsIAsyncOutputStream : nsIOutputStream
  {
    void asyncWait(in nsIOutputStreamListener listener);
  }

the listener interfaces are:

  nsIInputStreamListener : nsISupports
  {
    void onInputStreamReady(in nsIAsyncInputStream stream);
  }
  nsIOutputStreamListener : nsISupports
  {
    void onOutputStreamReady(in nsIAsyncOutputStream stream);
  }

there are a lot of details to work out, and the patch i'm about to submit is
only a prototype.
Attached patch prototype patch (obsolete) — — Splinter Review
Target Milestone: --- → mozilla1.4alpha
Target Milestone: mozilla1.4alpha → mozilla1.3beta
Blocks: 141624
Blocks: 133238
Blocks: 170594
Blocks: 184122
Blocks: 184358
Blocks: 98288
Blocks: 135182
Blocks: 92582
Blocks: 179391
Blocks: 181230
There are quite a few bugs, some nasty, which are waiting on this fix. Setting
blocking1.3b+ flag because drivers would like to see the dependencies fixed for
1.3beta.
Flags: blocking1.3b+
Attached patch patch: xpcom - v1 — — Splinter Review
this patch includes all changes under xpcom/.  the biggest changes include:

1- addition of nsIAsyncInputStream and nsIAsyncOutputStream
2- addition of nsIInputStreamNotify and nsIOutputStreamNotify
3- pipe rewrite; nsPipe2 is superceded by nsPipe3
4- nsStreamUtils, including NS_AsyncCopy for copying data between two
asynchronous streams (i.e. connects an async input stream to an async output
stream).
Attachment #104283 - Attachment is obsolete: true
Attachment #111455 - Flags: review?(dougt)
Attachment #111455 - Flags: superreview?(brendan)
Attached patch patch: necko transport - v1 — — Splinter Review
this patch includes only transport related changes under netwerk/base/.  this
patch should only depend on changes made under xpcom/.

the biggest changes include:

1- nsITransport no longer has asyncRead/asyncWrite methods.  returns
input/output streams optionally supporting nsIAsync{In,Out}putStream interfaces
depending on flags passed to open the streams.
2- rewrite of socket transport (nsSocketTransport2 supercedes
nsSocketTransport)
3- file transport replaced by more appropriately named stream transport
service.
Attachment #111457 - Flags: superreview?(bzbarsky)
Attachment #111457 - Flags: review?(dougt)
Attached patch patch: cache - v1 — — Splinter Review
this patch includes all changes under netwerk/cache/.  changes include:

1- cache descriptor returns blocking input/output streams instead of a
transport.
2- storage transport is eliminated in favor of storage stream (from xpcom/io/).
Attachment #111458 - Flags: superreview?(bzbarsky)
Attachment #111458 - Flags: review?(gordon)
this patch includes necko utility classes for common operations that leverage
async streams.	classes include:

1- nsInputStreamPump: drives a nsIStreamListener given a nsI{Async}InputStream
2- nsInputStreamChannel: wraps nsInputStreamPump in an implementation of
nsIChannel (this is an existing class that has just been modified).
3- nsAsyncStreamCopier: copies data asynchronously from a nsIInputStream to a
nsIOutputStream.  this basically wraps NS_AsyncCopy in a nsIRequest impl.
Attached patch patch: http - v1 — — Splinter Review
all changes in netwerk/protocol/http/.	biggest items:

1- moved HTTP connection management out into nsHttpConnectionMgr class.  this
was done to better factor the code, and keep multithreading issues well
isolated.  the HTTP connection mgr uses the new nsISocketTransportService::
postEvent method to move specific tasks onto the socket transport thread to
avoid locks.  this greatly eliminates the amount of MT code, which was an very
important goal of this work since the existing code is far too complex making
it difficult to fix bugs and add features.

2- a nsHttpConnection object now lives almost exclusively on the socket
transport thread.  this also greatly simplifies the HTTP MT logic.

3- the nsHttpPipeline now requests a new transaction from the connection mgr
when a transaction completes.  this helps keep the connection saturated, and
has proven to yield a significant improvement in pipelined Tp.

4- the HTTP channel uses a nsInputStreamPump to read from either a transaction
or the a cache input stream.

5- the buffer used to buffer a byte range response is now eliminated as the
nsInputStreamPump fully supports Suspend/Resume.
Attached patch patch: jar, file - v1 — — Splinter Review
includes changes in netwerk/protocol/jar/ and netwerk/protocol/file/.  its a
large patch because the file and jar protocol channels needed to be rewritten
in terms of the nsInputStreamPump.  the changes are fairly straightforward.
changes to other channel implementations.  gopher, finger, and datetime changes
are almost identical.  these channels actually share a lot of code (hmm.. maybe
they could be better factored into some kind of base class!)  about: changes
are just to deal with some minor API changes.
some comments about the FTP changes:

1- eliminated nsFtpStreamProvider.  the nsFtpControlConnection now just opens a
buffered output stream on the socket transport and writes commands directly to
it.    (this same thing was done to eliminate nsIStreamProvider implementations
in gopher, finger, and datetime.)

2- uses a nsInputStreamPump wrapping a buffered socket input stream to drive the
DataRequestForwarder.
this patch just includes some misc changes to necko.  mostly removing/moving
code and fixing up nsNetUtil.h to provide inline constructors for
nsInputStreamPump and friends.
Attached patch patch: chatzilla - v1 — — Splinter Review
backwards compatible patch for chatzilla.  attempts to detect old necko
interfaces and use them if available.  otherwise it uses the much simpler new
necko interfaces.  the new code path eliminates the StreamProvider class.
Attached patch patch: mailnews - v1 — — Splinter Review
changes under mailnews/.  these changes follow a simple theme.	nsMsgProtocol
opens input and output streams.  then it uses a nsInputStreamPump to AsyncRead
from the input stream.	nsMsgAsyncWriteProtocol uses nsIOutputStreamNotify to
asynchronously write to the output stream (used when sending messages). 
nsMsgAsyncWriteProtocol could probably be implemented in terms of
nsAsyncStreamCopier, but i haven't fully thought that through.	the
implementation in this patch conforms to the existing design as closely as
possible.

IMAP changes are more interesting.  it likewise utilizes nsInputStreamPump to
AsyncRead from the stream and depends heavily on Suspend/Resume working
correctly.  performance downloading large imap folders seems very good, though
i haven't run any benchmarks (are there any?).
Attached patch patch: other - v1 — — Splinter Review
other misc changes outside netwerk/.  big items include:

1- nsWyciwygChannel changes (cache API changes; now uses nsInputStreamPump).
2- nsJSProtocolHandler changes (nsIStreamIO no longer exists).
3- slight change to nsIDocShell::loadStream method.
full patch available if anyone wants it.
Attachment #111479 - Flags: review?(rginda)
Attachment #111480 - Flags: review?(sspitzer)
Attachment #111473 - Flags: superreview?(bzbarsky)
Attachment #111473 - Flags: review?(dougt)
Comment on attachment 111458 [details] [diff] [review]
patch: cache - v1

Looks good.  Ship it!
Attachment #111458 - Flags: review?(gordon) → review+
cathleen got Tz numbers for the latest patch.  here's a summary:

Overall Change in Size:
    Total:	   -25051 (+198700/-223751)
    Code:	  -22671 (+187098/-209769)
    Data:	   -2380 (+11602/-13982)


The biggest reduction was in necko.dll, a total of 33k

necko
    Total:	   -33792 (+90963/-124755)
    Code:	  -30777 (+81814/-112591)
    Data:	   -3015 (+9149/-12164)


Other areas of reductions include:
mime
    Total:	     -960 (+724/-1684)
    Code:	    -816 (+720/-1536)
    Data:	    -144 (+4/-148)


docshell
    Total:	     -726 (+2480/-3206)
    Code:	    -656 (+2448/-3104)
    Data:	     -70 (+32/-102)

emitter
    Total:	     -696 (+704/-1400)
    Code:	    -464 (+704/-1168)
    Data:	    -232 (+0/-232)


addrbook
    Total:	     -610 (+4228/-4838)
    Code:	    -544 (+3984/-4528)
    Data:	     -66 (+244/-310)

msgbase
    Total:	     -594 (+5200/-5794)
    Code:	    -528 (+5168/-5696)
    Data:	     -66 (+32/-98)

rdf
    Total:	     -594 (+2384/-2978)
    Code:	    -528 (+2336/-2864)
    Data:	     -66 (+48/-114)

msgcompo
    Total:	     -554 (+3370/-3924)
    Code:	    -576 (+3264/-3840)
    Data:	     +22 (+106/-84)

gkcontent
    Total:	     -352 (+37472/-37824)
    Code:	    -352 (+37472/-37824)
    Data:	      +0 (+0/+0)

urildr
    Total:	     -192 (+1408/-1600)
    Code:	    -208 (+1376/-1584)
    Data:	     +16 (+32/-16)

xpinstal
    Total:	      -48 (+1680/-1728)
    Code:	     -64 (+1632/-1696)
    Data:	     +16 (+48/-32)

appcomps
    Total:	      -32 (+2768/-2800)
    Code:	     -32 (+2768/-2800)
    Data:	      +0 (+0/+0)


NOTE: there are codesize increases in xpcom and parts of mailnews.
Blocks: 30892
cathleen sent me these mini-ibench results [win2k, 2.4 GHz, 1GB]:

default cache settings:

baseline
--------------
First loop (uncached?)  :           10.422
Avg. subsequent loop (cached?):      7.906
Total for all loops :               34.141
Number of loops :                        4

w/patch
--------------
First loop (uncached?)  :            8.938
Avg. subsequent loop (cached?) :     7.505
Total for all loops :               31.453
Number of loops:                         4


Disk cache = 0:

baseline
------------------
First loop (uncached?):              8.829
Avg. subsequent loop (cached?):      8.536
Total for all loops :               34.438
Number of loops :                        4

w/patch
------------------
First loop (uncached?):              8.485
Avg. subsequent loop (cached?):      8.365
Total for all loops :               33.579
Number of loops :                        4


Disk cache = 0  & memory cache = 0:

baseline
---------------
First loop (uncached?) :            13.688
Avg. subsequent loop (cached?):     16.917
Total for all loops:                64.438
Number of loops:                         4

w/patch
---------------
First loop (uncached?) :            12.297
Avg. subsequent loop (cached?):     12.318
Total for all loops :                49.25
Number of loops:                         4
cathleen also sent me these jrgm/cowtools results:

win98, 200mHz, 64MB
-----------------------------
baseline:  2500 ms
w/patch:   2475 ms

win2k, 2.4 GHz, 1GB
-----------------------------
baseline:   309 ms
w/patch:    302 ms


these are cummulative numbers (5 cycles)
Blocks: 186691
window open:
--------------------
1) 2.4 GHz, 1GB, win2k desktop
    baseline:  293ms   288ms  290ms
    w/patch:   297ms   291ms  294ms
2) 650 MHz, 512MB, win2k laptop
    baseline:  434ms   432ms  430ms
    w/patch:   432ms   428ms  427ms
3) 200MHz, 64MB, win98 desktop
    baseline: 2026ms  2013ms 2009ms
    w/patch:  2013ms  2026ms 2010ms

Seems like there is not much difference in window open.
Each score is an average of 10 window open test.

Startup
--------------
1) 2.4 GHz, 1GB, win2k desktop
     baseline: 1412, 1600, 1287, *1131*, 1350, 1881, 1850, 1225
     w/patch:  1396, 1662, 1053, *928*, 1475, 1037, 1037, 1615
2) 650 MHz, 512MB, win2k laptop
     baseline: 2077, 2168, 2080, 2312, 2424, 2215, 2630, *2074*
     w/patch:  2419, 2632, *1787*, 1880, 1952, 2633, 2531, 2576
3) 200MHz, 64MB, win98 desktop
     baseline: 7790, 7590, 7720, 7430, 7490, 7930, *7290*, 7700
     w/patch:  *7130*, 7760, 7280, 7470, 7230, 7330, 7430, 7170

There could be possible win in startup.  Test on tinderbox reports the lowest
score of 10 runs.  I marked out the lowest core of 8 runs here.
forgot to add that the Ts and Txul numbers are again courtesy of cathleen :-)
Ts up 20% on comet, ~ flat on beast/win32
Comment on attachment 111475 [details] [diff] [review]
patch: jar, file - v1

This commit have added a warning on brax TBox:

+netwerk/protocol/jar/src/nsJARChannel.cpp:443
+ `nsresult rv' might be used uninitialized in this function

Indeed, the warning appears to be pointing out a real issue - if ext is
non-NULL, but mimeServ is NULL, then the code will check NS_FAILED on an
uninitialized nsresult - see
http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/netwerk/protocol/jar/src/ns
JARChannel.cpp&rev=1.96&mark=446,469,470,471,481#443
Comment on attachment 111473 [details] [diff] [review]
patch: necko utility classes - v1

This checkin have added a warning on brad TBox:

+netwerk/base/src/nsInputStreamPump.cpp:310
+ `PRUint32 nextState' might be used uninitialized in this function

Indeed, if mState is neither of the 3 values handled in the switch, the
nextState will stay uninitialized - see
http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/netwerk/base/src/nsInputStr
eamPump.cpp&rev=1.1&mark=310,311,323#304

P.S. See bug 59652 and	bug 179819 for more discussion of "uninitialized"
warnings.
so... which of these patches are now checked in? all of them?
if so, is this bug fixed?
comment #24 is legitimate if the mime service fails to be initialized.
comment #25 is invalid.  the warning occurs because of the switch statement
appearing to allow nextState to be unset.  it cannot be unset because mState can
only be within the set of handled cases.
Depends on: 189843
I think that this checkin broke reading and writing files for applications that
use jslib.  I've fixed reading files for the calendar, and will send the fix
back to them, hopefully someone there will fix writing files.
People should be on the look out for add on applications that no longer work
after this checkin.
http://mozdev.org/bugs/showattachment.cgi?attach_id=674 has the patch that was
applied to the calendar code to allow it to read files using the jslib code.

http://mozdev.org/bugs/show_bug.cgi?id=2954 is the bug.
mike: sorry for the jslib bustage.  i had no idea of its existance, and these
are not frozen APIs :-(

marking FIXED (all patches landed).
Status: NEW → RESOLVED
Closed: 22 years ago
Resolution: --- → FIXED
Comment on attachment 111455 [details] [diff] [review]
patch: xpcom - v1

OK... here goes.

>Index: xpcom/build/dlldeps.cpp

>-    NS_NewPipe(NULL, NULL, 0, 0, PR_FALSE, PR_FALSE, NULL);
>+    NS_NewPipe2(NULL, NULL, PR_FALSE, PR_FALSE, 0, 0, NULL);

I guess we're just revving this function name because the signature changed and
it has nothing to do with the nsPipe3.cpp name of the file... a little
confusing, but I can see why we'd want to keep it that way.  Though, we're
keeping NS_NewPipe around too, no (if I read nsIPipe.idl correctly)?  Why?

>Index: xpcom/io/nsIAsyncInputStream.idl

>+interface nsIInputStreamNotify;

This seems like a very awkward name for that beastie.... nsIInputStreamListener
perhaps?

This interface could use a comment explaining why you'd want to use one in
general (eg 'Use an nsIAsyncInputStream when you want to have an input stream
that will notify you when data is available and wait for you to read it').

>+    void closeEx(in nsresult reason);

Maybe "closeWithReason()"?  "closeEx" is somewhat random...

>+     * @param aRequestedCount
>+     *        Wait until at least this many bytes may be read.  This is only
>+     *        a suggestion to the underlying stream; it may be ignored.

Maybe callers should be able to pass "0" if they don't care?

>+     * @param aEventQ

aEventQueue, maybe?  The more I think about it, the less I care... ;)

>+interface nsIInputStreamNotify : nsISupports

Should this live in a separate IDL file?  If we'll have to do that anyway at
some point (before freezing this) we may as well do it now...


>Index: xpcom/io/nsIAsyncOutputStream.idl

Basically the same exact comments apply here as for nsIAsyncInputStream.idl

>Index: xpcom/io/nsIPipe.idl

Again, a short blurb explaining why, where, and how this would be used would be
great.

>-     * supports nsIObservableInputStream and nsISearchableInputStream

Perhaps leave the part about nsISearchableInputStream in there?

>+inline nsresult
>+NS_NewPipe(nsIInputStream **pipeIn,

Could we move all this C++ out of the IDL file?  ;)


>Index: xpcom/io/nsInputStreamTee.cpp

Could we leave a debug-only version of that code in, possibly?	Doesn't need to
return an error, jsut to assert that NS_FAILED(rv) || !nonBlocking... That
would catch misuse more reliably than the assert when we try to actually write
to it, imo...

>Index: xpcom/io/nsPipe3.cpp

>+class nsPipeEvents

This could use a short comment explaining what it's used for....

>+class nsPipeInputStream : public nsIAsyncInputStream

Same here

>+    NS_DECL_ISUPPORTS_INHERITED

This is a very fishy use of NS_DECL_ISUPPORTS_INHERITED... at least comment why
you're using it even though you are not in fact inheriting from anyone who's
implementing a refcount?

Maybe use an nsAutoRefCnt instead of an nsrefcount?  Not really sure it
matters.

Please document what OnInputReadable actually does?  In particular, document
the return value...


>+class nsPipeOutputStream : public nsIAsyncOutputStream

Same comments here as for the input stream.  (And document OnOutputWritable).

>+    nsPipeInputStream* InputStream() { return &mInput; }
>+    nsPipeOutputStream* OutputStream() { return &mOutput; }

Do these two methods need to exist?  Why not access those members directly?

>+nsPipe::nsPipe()
>+{
>+    NS_INIT_ISUPPORTS();
>+}

You don't need to call NS_INIT_ISUPPORTS() anymore... dbaron has removed almost
all uses in the tree at this point.  Take that out, please?

>+    InputStream()->SetNonBlocking(nonBlockingIn);
>+    OutputStream()->SetNonBlocking(nonBlockingOut);

mInput.SetNonBlocking(nonBlockingIn);
mOutput.SetNonBlocking(nonBlockingOut);

>+nsPipe::PeekSegment(PRUint32 index, char *&cursor, char *&limit)

This has gotten a face-lift since this patch landed anyway... so has the
AdvanceReadCursor() code... (just in case anyone else decides to review this,
don't bother with the patch in these parts; read the actual file).

>+        InputStream()->ReduceAvailable(bytesRead);

mInput.ReduceAvailable(bytesRead);

>+            // notify output stream that pipe is writable
>+            if (OutputStream()->OnOutputWritable(events))

mOutput.OnOutputWritable(events);

>+        if (mReadCursor == mWriteCursor)
>+            NS_ERROR("read cursor is bad");

NS_ASSERTION here?

>+                OutputStream()->SetWritable(PR_FALSE);

mOutput.SetWritable(PR_FALSE);

>+        if (InputStream()->OnInputReadable(bytesWritten, events))

mInput.OnInputReadable(bytesWritted, events);

>+        if (outputOnly && !InputStream()->Available())

mInput.Available();

>+            if (InputStream()->OnInputException(reason, events))

mInput.OnInputException(reason, events);

>+        if (OutputStream()->OnOutputException(reason, events))

mOutput.OnOutputException(reason, events);

>+    // return error if pipe closed with error.
>+    if (!mAvailable && NS_FAILED(mPipe->mStatus))
>+        if (mPipe->mStatus != NS_BASE_STREAM_CLOSED)

Shouldn't that be one |if| statement with just a && tossed in there?

>+nsPipeInputStream::ReadSegments(nsWriteSegmentFun writer, 
>+            mPipe->OnPipeException(rv);

Hmm.. so this would notify the reader that the stream is ready and _then_
return an error from ReadSegments?  That seems a little odd....

>+            if (NS_FAILED(rv) || (writeCount == 0)) {

That second condition is overparenthesized....

>+nsPipeInputStream::Search(const char *forString, 
>+            // exception, then we should just inform that caller that all

"the caller"

I guess we're hoping no one ever calls Search with a string that has parts in 3
separate segments, huh?  I guess that's a decent-ish assumption....


>+nsPipeOutputStream::WriteSegments(nsReadSegmentFun reader,
>+            mPipe->OnPipeException(rv);

Same as the similar code in nsPipeInputStream::ReadSegments...	Is this really
what we want to do?

>+            rv = reader(this, closure, segment, *writeCount, segmentLen, &readCount);

Could we have an assert in the success case that readCount <= segmentLen? 
Similarly for ReadSegments in nsPipeInputStream.

>+            if (NS_FAILED(rv) || (readCount == 0)) {

This is overparenthesized.

>+nsPipeOutputStream::WriteFrom(nsIInputStream* fromStream,
>+                                      PRUint32 count,
>+                                      PRUint32 *writeCount)

Wacky indentation.

>+        // replace a pending notify
>+        mNotify = 0;

So... is there a good reason you can think of why this code would ever get
called when mNotify is non-null with a |mNotify != notify|?  I can't think of
any offhand....  Wouldn't doing that force the first mNotify to never get the
notification it's waiting for?	(All this applies to the nsPipeInputStream
too.)

>Index: xpcom/io/nsStreamUtils.cpp

>+    nsInputStreamReadyEvent(nsIInputStreamNotify *notify,
>+    {
>+        NS_INIT_ISUPPORTS();
>+    }

No need for that.

>+    static void *PR_CALLBACK EventHandler(PLEvent *plevent)

PR_STATIC_CALLBACK(void*) EventHandler(PLEvent *plevent)

>+        nsInputStreamReadyEvent *ev = (nsInputStreamReadyEvent *) plevent;

NS_STATIC_CAST, please

>+    static void PR_CALLBACK EventCleanup(PLEvent *plevent)

PR_STATIC_CALLBACK(void) EventCleanup(PLEvent *plevent)

>+        nsInputStreamReadyEvent *ev = (nsInputStreamReadyEvent *) plevent;

NS_STATIC_CAST


Same comments for the nsOutputStreamReadyEvent

>+    nsStreamCopierIB(nsIAsyncInputStream *in,
>+        { NS_INIT_ISUPPORTS(); }

No need for that.

>+    NS_IMETHOD OnOutputStreamReady(nsIAsyncOutputStream *out)
>+            if (NS_FAILED(rv) || (n == 0)) {

Overparenthesized

>+    nsStreamCopierOB(nsIAsyncInputStream *in,
>+        { NS_INIT_ISUPPORTS(); }

The usual.  ;)

>+    NS_IMETHOD OnInputStreamReady(nsIAsyncInputStream *in)
>+            if (NS_FAILED(rv) || (n == 0)) {

Overparenthesized

>+NS_AsyncCopy(nsIAsyncInputStream *source,
>+        //
>+        // fire off two async copies :-)
>+        //
>+        rv = NS_AsyncCopy(source, pipeOut, segmentSize, PR_FALSE, PR_TRUE);
>+        rv = NS_AsyncCopy(pipeIn, sink, segmentSize, PR_TRUE, PR_FALSE);

Surely the segmentSize should come _after_ the booleans.

>+        // maybe calling NS_AsyncCopy twice is a bad idea!
>+        NS_ASSERTION(NS_SUCCEEDED(rv), "uh-oh");

Let's make this assert a _little_ more informative, ok?  ;)  Something like
"Async copying into pipe that will never empty"?

>Index: xpcom/tests/TestPipes.cpp
>+class nsPump : /*public nsIInputStreamObserver, 
>+               public nsIOutputStreamObserver,*/

Why leave the commented out code there?

>+        rv = WriteAll(out1, buf, len, &writeCount);
>+        //rv = out1->Write(buf, len, &writeCount);

Same here.

>+    //rv = TestPipeObserver();
>+    //NS_ASSERTION(NS_SUCCEEDED(rv), "TestPipeObserver failed");

And here.

>Index: xpcom/threads/nsEventQueueUtils.h
>+inline nsresult
>+NS_GetEventQueueService(nsIEventQueueService **result)
>+{
>+  nsresult rv;
>+
>+  static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
>+  nsCOMPtr<nsIEventQueueService> eqs = do_GetService(kEventQueueServiceCID, &rv);
>+  if (NS_FAILED(rv)) return rv;
>+
>+  NS_ADDREF(*result = eqs);
>+  return NS_OK;
>+}

replace the body with:

static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
return CallGetService(kEventQueueServiceCID, result);

??

Comments on other diffs coming up later (tomorrow or Friday)
lot's of good suggestions.  thx bz!
Comment on attachment 111455 [details] [diff] [review]
patch: xpcom - v1

One more comment on the XPCOM stuff.. I'm a little worried about the ownership
issues of the notify stuff.  Should we make it clearer that the stream we are
AsyncWait()ing on does _not_ hold a useful ref to the notify object passed in
(it does hold a ref, but it drops this ref, so this ref should not be counted
on to keep the object alive....)
Comment on attachment 111455 [details] [diff] [review]
patch: xpcom - v1

Speaking of the memory issues...  I just remembered why it's a problem. 
NS_AsyncCopy creates a StreamCopier, sets it to wait, and then drops the ref to
it.  So the copier is held alive only by the stream it's waiting on.  So the
code that possibly kills the "notify" object should be fixed, I think...
discussed this with bz.. not a prob.  just needs to be thoroughly documented ;-)
Comment on attachment 111455 [details] [diff] [review]
patch: xpcom - v1

OK, never mind me.  The ref nsPipeEvents holds saves the day for spidy.  Could
we get that documented so no one mucks with it?
Comment on attachment 111457 [details] [diff] [review]
patch: necko transport - v1

>Index: netwerk/base/public/nsITransport.idl

At risk of starting to sound repetitive, add a few lines explaining how this
interface would typically be used?  If I understand correctly, this lets you
set up a pipe and gives you back the input and output streams for that pipe;
then you can give the output stream to someone to pump data into and pass the
input stream to someone to read data from?  And the difference from nsIPipe is
that one of the streams may Just Exist already and we just want the other one? 
It would be good to document this.

>Index: netwerk/base/public/nsISocketTransport.idl

>+/**
>+ * nsISocketTransport
>+ *
>+ * NOTE: This is a free-threaded interface.
>+ */

Could we just say "this interface may be called (used?) on any thread"?  That
would help people who may not know that term...

>+    [noscript] void getAddress(in PRNetAddrStar addr);

Hmm... This would be better as:

native PRNetAddr(PRNetAddr);
[noscript] PRNetAddr getAddress();

That compiles to the same C++ and is a lot clearer, imo.

>+     * Security info object returned from the PSM socket provider.

Maybe "SSL socket provider"?

>+     * Security notification callbacks passed to PSM

Same here?

It's a nit; feel free to ignore it.  ;)

>+    const unsigned long STATUS_RESOLVING      = 0x804b0003;
>+    const unsigned long STATUS_CONNECTED_TO   = 0x804b0004;
>+    const unsigned long STATUS_SENDING_TO     = 0x804b0005;
>+    const unsigned long STATUS_RECEIVING_FROM = 0x804b0006;
>+    const unsigned long STATUS_CONNECTING_TO  = 0x804b0007;
>+    const unsigned long STATUS_WAITING_FOR    = 0x804b000a;

I'm torn between listing these in numeric order and chronological order (with
CONNECTING_TO moved up to the second spot, and WAITING_FOR possibly moved too).
 Again, no real preference on this one.

>Index: netwerk/base/public/nsISocketTransportService.idl


>+    nsISocketTransport createTransport([array, size_is(aTypeCount)]
>+                                       in string aSocketTypes,

Put those on one line?	That looks very confusing (as an extra arg instead of a
qualifier).

>Index: netwerk/base/src/nsStreamTransportService.cpp

>+    static NS_METHOD FillPipeSegment(nsIOutputStream *, void *, char *,
>+                                     PRUint32, PRUint32, PRUint32 *);

Give those params names please?

>+nsInputStreamTransport::Run()
>+        if (mOffset != ~0U) {

Shouldn't that be PRUint32(-1)?  The IDL specifies to pass "-1".. (yes, I know
we have problems if 
PRUint32(-1) != ~0U, but...).

>+    static NS_METHOD ConsumePipeSegment(nsIInputStream *, void *, const char *,
>+                                        PRUint32, PRUint32, PRUint32 *);

Param names.

>+        if (mOffset != ~0U) {

As above.

>+nsOutputStreamTransport::OpenOutputStream(PRUint32 flags,
>+    NS_ASSERTION(flags == 0, "unexpected flags");

Does this assert need to be added to nsInputStreamTransport::OpenInputStream? 
Or removed from here?

>+nsStreamTransportService::nsStreamTransportService()
>+    : mLock(PR_NewLock())
>+{
>+    gSTS = this;

Please assert that gSTS is null here.  We don't want someone calling
do_CreateInstance on us and thus creating _two_ transport services that will
start scribbling on the gSTS pointer, etc....

>+nsStreamTransportService::Init()
>+{
>+    nsAutoLock lock(mLock);

Assert that mPool is null here?  Or do we not care if someone calls Init()
twice?	If so, why are we locking?

>Index: netwerk/base/src/nsStreamTransportService.h
>+    /** used internally **/
>+    nsresult Dispatch(nsIRunnable *);

make this protected and declare some friend classes (and remove that comment)? 
;)

>+private:
>+    nsresult Dispatch_Locked(nsIRunnable *);

This seems to no longer be implemented.  Remove the decl?

>Index: netwerk/base/src/nsSocketTransport2.cpp


>+static PRErrorCode RandomizeConnectError(PRErrorCode code)
>+    // correctly despite the random occurance of there errors.

"these", not "there".

>+NS_IMPL_QUERY_INTERFACE2(nsSocketInputStream,
>+                         nsIInputStream,
>+                         nsIAsyncInputStream)

This would really belong before the OnSocketReady method imo....  Not a big
deal either way.

Same for the nsSocketOutputStream impl.

>+nsSocketTransport::Init(const char **types, PRUint32 typeCount,
>+        mTypes = (char **) PR_Malloc(mTypeCount + sizeof(char *));

mTypeCount * sizeof(char*)

>+nsSocketTransport::SendStatus(nsresult status)
>+        sink->OnTransportStatus(this, status, progress, ~0U);

Again, perhaps PRUint32(-1)

>+nsSocketTransport::OnMsgInputClosed(nsresult reason)
>+    // check if event should effect entire transport

affect

>+nsSocketTransport::OnMsgOutputClosed(nsresult reason)
>+    // check if event should effect entire transport

affect

>+nsSocketTransport::OpenInputStream(PRUint32 flags,
>+        rv = NS_AsyncCopy(&mInput, pipeOut, PR_FALSE, PR_TRUE,
>+                          segsize, 1, segalloc);

Why "1" for the segment count?	Isn't that going to be unused in this case
anyway?  Wouldn't it be more consistent to pass segcount or 0?

>+nsSocketTransport::OpenOutputStream(PRUint32 flags,
>+        rv = NS_NewPipe2(getter_AddRefs(pipeIn), getter_AddRefs(pipeOut),
>+                         PR_TRUE, !openBlocking, segsize, segcount, segalloc);

Same.

>+    // flag output stream as open
>+    mInputClosed = PR_FALSE;

mOutputClosed = PR_FALSE;

+// called on the socket thread only

Could the methods for which this is true assert so?
  NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "Called on wrong
thread");
or something along those lines?  Or is gSocketThread not guaranteed to be set
to the right thing?


>Index: netwerk/base/src/nsSocketTransport2.h

+class nsSocketInputStream : public nsIAsyncInputStream
>+    nsIOutputStreamNotify *mNotify;

Could we make that a strong ref?  It means we pay an extra addref/release in
OnSocketReady, but it'd be a good deal safer...

I'd do that as a separate checkin from anything else and I'd be ok with backing
it out if the cost of that extra addref/release is really noticeable....

>+class nsSocketOutputStream : public nsIAsyncOutputStream
>+    nsIOutputStreamNotify *mNotify;

Same.

>+    // we have to be careful with these.  they are modified on the DNS thread,
>+    // while we are in the resolving state.  once we've received the event
>+    // MSG_DNS_LOOKUP_COMPLETE, these can only be accessed on the socket thread.

Could accesses to these in the code assert that either the event has not been
received or the thread is the socket thread?

Also, if we have code here that must be called off the main thread (not sure if
there is such), could we assert that too?


>Index: netwerk/base/src/nsSocketTransportService2.cpp

>+nsSocketTransportService::nsSocketTransportService()
>+    gSocketTransportService = this;

Assert that this is null in case someone does a do_CreateInstance on us....

>+nsSocketTransportService::~nsSocketTransportService()
>+    PR_DestroyLock(mEventQLock);

Shouldn't that null-check the lock?

>+//-----------------------------------------------------------------------------
>+// socket api (socket thread only)

Could these assert being called on the socket thread?

The hashtable access should probably check that the hashtable is inited (by
looking at its .ops member) and bail if it's not....

>+    static PRBool PR_CALLBACK MatchEntry(PLDHashTable *, const PLDHashEntryHdr *, const void *);
>+    static void   PR_CALLBACK ClearEntry(PLDHashTable *, PLDHashEntryHdr *);

PR_STATIC_CALLBACK(PRBool)/PR_STATIC_CALLBACK(void)
Comment on attachment 111458 [details] [diff] [review]
patch: cache - v1

>Index: netwerk/cache/public/nsICacheEntryDescriptor.idl

>+     * @param offset
>+     *        read starting from this offset into the cached data.

>+     * @param offset
>+     *        write starting from this offset into the cached data.

What happens if the offset is past the end of the existing data?  For writing,
it looks to me like we'll just expand the entry and leave a chunk of garbage
data in the middle?  For reading, I'm not sure what happens.  It would be good
to document this, in any case.

>Index: netwerk/cache/src/nsCacheEntryDescriptor.cpp

>+nsresult nsCacheEntryDescriptor::
>+nsOutputStreamWrapper::OnWrite(PRUint32 count)
>+    if (count > 0x7FFFFFFF)  return NS_ERROR_UNEXPECTED;

PR_INT32_MAX, please.

>Index: netwerk/cache/src/nsDiskCacheStreams.cpp

>+// NOTE: called with service lock held
> nsresult
> nsDiskCacheStreamIO::Seek(PRInt32 whence, PRInt32 offset)
> {
>-    nsAutoLock lock(nsCacheService::ServiceLock()); // grab service lock
>+    //nsAutoLock lock(nsCacheService::ServiceLock()); // grab service lock

Just remove the line, don't comment it....

Looks good other than that!  ;)
Attachment #111458 - Flags: superreview?(bzbarsky) → superreview+
Comment on attachment 111473 [details] [diff] [review]
patch: necko utility classes - v1

>Index: netwerk/base/public/nsIInputStreamPump.idl

Some brief documentation explaining why one would use this would be good.  The
comments for the two methods cover that information in sum, but it would be
good to just have an overall description of the interface...

>Index: netwerk/base/public/nsIInputStreamChannel.idl

>+     * This attribute can only be changed before the channel is opened.
>+     */
>+    attribute nsIInputStream contentStream;

What exception is thrown if you try to change it afterward?

>Index: netwerk/base/public/nsIAsyncStreamCopier.idl

Description of overall purpose in life?

>+    /**
>+     * asyncRead causes the input stream to be read in chunks and delivered
>+     * asynchronously to the listener via OnDataAvailable.
>+     *
>+     * @param aListener
>+     *        receives notifications.
>+     * @param aListenerContext
>+     *        passed to listener methods.
>+     */
>+    void asyncCopy(in nsIRequestObserver   aObserver,
>+                   in nsISupports          aObserverContext);

This comment looks like it came from nsIInputStreamPump and just got lost here.
 Please fix?

>Index: netwerk/base/src/nsInputStreamPump.cpp
>+    , mStreamLength(~0U)

If you mean -1, use -1.  If you mean PR_UINT32_MAX, use that....

>+nsInputStreamPump::EnsureWaiting()
>+{
>+    if (!mWaiting) {
>+        nsresult rv = mAsyncStream->AsyncWait(this, 0, mEventQ);
>+        if (NS_FAILED(rv)) {
>+            NS_ERROR("AsyncWait failed");
>+            return rv;
>+        }
>+        mWaiting = PR_TRUE;

I asumme that we will never have two threads calling that?

>+nsInputStreamPump::AsyncRead(nsIStreamListener *listener, nsISupports *ctxt)

>+    if (nonBlocking)
>+        mAsyncStream = do_QueryInterface(mStream);
...
>+    // mStreamOffset now holds the number of bytes currently read.  we use this
>+    // to enforce the mStreamLength restriction.
>+    mStreamOffset = 0;

Um.  What if mStream implements both nsISeekableStream and nsIAsyncInputStream?
 Shouldn't we seek it?

>+nsInputStreamPump::OnInputStreamReady(nsIAsyncInputStream *stream)
>+        if (mSuspendCount || mState == STATE_IDLE) {
>+            mWaiting = PR_FALSE;
>+            break;
>+        }

Hmm... So if I have an input stream pump.  I call AsyncRead on it, suspend it
and then forget about it, ok?  At this point the only ref to it is the one that
the async input stream holds (since the pump is waiting on it).  This
OnInputStreamReady gets called and we just bounce out of it without doing
anything, at which point the ref to us is dropped (by the event that called
us), and we go away, taking the stream and such with us.

I suppose that makes sense, since suspending a pump and then dropping the ref
to it means that you will never unsuspend it and thus do not care whether it
dies.... but shouldn't the pump's destructor close the streams involved or
something?  Or is it just relying on the stream destructors to clean up?  The
StreamTransport is held by the transport service and only goes away if it does
not re-dispatch itself... what cleans it up?

>+nsInputStreamPump::OnStateTransfer()
>+        if (avail + mStreamOffset > mStreamLength) {
>+            avail = mStreamLength - mStreamOffset;
>+            if (avail > mSegSize)
>+                avail = mSegSize;
>+        }

Shouldn't that inner if statement be done no matter whether avail +
mStreamOffset > mStreamLength?

>+nsInputStreamPump::OnStateStop()
>+    mAsyncStream = 0;

Same question here.  We don't need to explicitly close mAsyncStream?

>Index: netwerk/base/src/nsInputStreamChannel.cpp

>+nsInputStreamChannel::GetName(nsACString &result)
>+    return mURI->GetSpec(result);

What if mURI is null?

>+nsInputStreamChannel::Open(nsIInputStream **result)

What if this gets called multiple times?  We'll just keep passing back this
same stream, I guess...  Do we know for sure that this stream is blocking so
when the consumer calls Read() it will block?

>+nsInputStreamChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
>+    if (mContentLength == -1)
>+        mContentStream->Available((PRUint32 *) &mContentLength);
>+    nsresult rv = NS_NewInputStreamPump(getter_AddRefs(mPump), mContentStream,
>+                                        -1, mContentLength, 0, 0, PR_TRUE);
>+    if (NS_FAILED(rv)) return rv;

What if mContentStream is being filled from the other end (eg a pipe)?	Then
its Available will _not_ return the complete amount of data it may have
available; just what's there right now.  And we will only pump out that much
data, leaving the rest in the stream....  Seems wrong to me.

>Index: netwerk/base/src/nsAsyncStreamCopier.cpp

>+nsInputWrapper::Available(PRUint32 *avail)
>+{
>+    nsresult status;
>+    if (mCopier->IsComplete(&status))
>+        return status;

Hmm... can't it be complete with a NS_OK status?  Don't we want to set *avail
to 0 in this case?

>+nsInputWrapper::Read(char *buf, PRUint32 count, PRUint32 *countRead)
>+    nsresult rv = mSource->Read(buf, count, countRead);
>+    /*
>+    if (NS_FAILED(rv)) {
>+        if (rv != NS_BASE_STREAM_WOULD_BLOCK)
>+            CloseEx(rv);
>+        // else, not a real error
>+    }
>+    else if (*countRead == 0)
>+        CloseEx(NS_BASE_STREAM_CLOSED);
>+    */
>+    return rv;

What's up with this code? Is it in or out?

>+nsInputWrapper::ReadSegments(nsWriteSegmentFun writer, void *closure,
>+                             PRUint32 count, PRUint32 *countRead)

Same question about a similar block of code.

>+nsInputWrapper::IsNonBlocking(PRBool *result)

Again, can we be complete with an NS_OK status?

>+nsInputWrapper::AsyncWait(nsIInputStreamNotify *notify, PRUint32 amount, nsIEventQueue *eventQ)
>+{
>+    // we'll cheat a little bit here since we know that NS_AsyncCopy does pass
>+    // an event queue.
>+    NS_ASSERTION(eventQ == nsnull, "unexpected");

Shouldn't that be NS_ASSERTION(eventQ, "unexpected") ?

>+nsOutputWrapper::Write(const char *buf, PRUint32 count, PRUint32 *countWritten)
>+    /*
>+    if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK)
>+        CloseEx(rv);
>+    */

In or out?  ;)

>+nsOutputWrapper::WriteSegments(nsReadSegmentFun reader, void *closure,
>+    /*
>+    if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK)
>+        CloseEx(rv);
>+    */

Again.

>+nsOutputWrapper::IsNonBlocking(PRBool *result)

The usual question about being complete with NS_OK status.  ;)

>+nsOutputWrapper::AsyncWait(nsIOutputStreamNotify *notify, PRUint32 amount, nsIEventQueue *eventQ)
>+    // we'll cheat a little bit here since we know that NS_AsyncCopy does pass
>+    // an event queue.
>+    NS_ASSERTION(eventQ == nsnull, "unexpected");

Again, the assert seems to be reversed....

>Index: netwerk/base/src/nsAsyncStreamCopier.h

>+    class nsInputWrapper : public nsIAsyncInputStream
>+        NS_DECL_ISUPPORTS_INHERITED

Please comment explaining why you're doing that even though it's obviously not
inheriting an nsISupportsImpl....

>+    //-------------------------------------------------------------------------
>+    // nsInputWrapper
>+    //-------------------------------------------------------------------------
>+
>+    class nsOutputWrapper : public nsIAsyncOutputStream

Fix the comment?

Same question about NS_DECL_ISUPPORTS_INHERITED.

I didn't give the new tests a very thorough review, but they look more or less
ok.
Comment on attachment 111455 [details] [diff] [review]
patch: xpcom - v1

>+interface nsIAsyncInputStream : nsIInputStream
>+{
>+     * Any pending asyncWait will be notified.
>+    void closeEx(in nsresult reason);
>+     * @param aNotify
>+     *        This object is notified when the stream becomes ready.
does being closed count as ready? I'm fairly certain from reading closeEx()
that aNotify will be called when the stream is closed
>+    void asyncWait(in nsIInputStreamNotify aNotify,

>+interface nsIAsyncOutputStream : nsIOutputStream
>+{
>+     * @param aNotify
>+     *        This object is notified when the stream becomes ready.
same comment.
>+    void asyncWait(in nsIOutputStreamNotify aNotify,

>+NS_IMETHODIMP
>+nsPipe::GetInputStream(nsIAsyncInputStream **aInputStream)
>+{
>+    NS_ADDREF(*aInputStream = &mInput);
>+    return NS_OK;
>+}
>+
>+NS_IMETHODIMP
>+nsPipe::GetOutputStream(nsIAsyncOutputStream **aOutputStream)
>+{
>+    NS_ADDREF(*aOutputStream = &mOutput);
>+    return NS_OK;
>+}
It appears that the refcount for mInput and mOutput starts at 0 and goes up to
1 when Get<>Stream is called, which measn that they could be destroyed when a
caller drops its reference to the object.  Did I miss something?
> Did I miss something?

Yes.  mInput and mOutput implement custom AddRef/Release methods (see comment
31) which refcount the pipe itself.
Comment on attachment 111457 [details] [diff] [review]
patch: necko transport - v1

>+    void close(in nsresult aReason);
bz suggested closeWithReason, could you possibly use the same name for the same
signature?

> interface nsISocketTransport : nsITransport 
>+     * Security info object returned from the PSM socket provider.  This object
bz nit'd about the explicit reference to PSM. I too don't want to see PSM
explicitly referenced in this stuff.

>+    if (mTypeCount) {
>+        mTypes = (char **) PR_Malloc(mTypeCount + sizeof(char *));
>+            mTypes[type++] = PL_strdup(proxyType);
>+            mTypes[type++] = PL_strdup(types[i]);
hrm, i didn't see the pairs to this

>+nsSocketTransport::OpenInputStream(PRUint32 flags,
>+    if (!(flags & OPEN_UNBUFFERED) || (flags & OPEN_BLOCKING)) {
>+    else
>+        *result = &mInput;
>+    NS_ADDREF(*result);
Again, it looks like the default refcount will be 1 which would lead to a
caller killing it.

>+nsSocketTransport::OpenOutputStream(PRUint32 flags,
>+    if (!(flags & OPEN_UNBUFFERED) || (flags & OPEN_BLOCKING)) {
>+    else
>+        *result = &mOutput;
>+    NS_ADDREF(*result);
again...

>+    // these members are "set" at initialization time and are never modified
>+    // afterwards.  this allows them to be safely accessed from any thread.
>+    char      **mTypes;

>+nsSocketTransportService::ClearEntry(PLDHashTable *table,
>+    PL_strfree((char *) he->key);

>+    // this condition variable will be checked to determine if the socket
>+    // handler should be detached.  it must only be accessed on the socket
>+    // thread.
>+    nsresult mCondition;
why is it an nsresult and what results is it likely to have?

>+    // LookupHost checks to see if we've previously resolved the hostname
>+    // during this session.  We remember all successful connections to prevent
>+    // ip-address spoofing.  See bug 149943.
Does going offline flush this?

>+    nsresult LookupHost(const nsACString &host, PRUint16 port, PRIPv6Addr *addr);
>+        // give background threads a chance to finish whatever work they may
>+        // be doing.
this is broken :-).  I know you don't care, but if you could file a bug against
me, i'll address it the next time i run through test apps.
>+        LOG(("waiting 1 second before exiting...\n"));
>+        PR_Sleep(PR_SecondsToInterval(1));
>+    } // this scopes the nsCOMPtrs
Comment on attachment 111480 [details] [diff] [review]
patch: mailnews - v1

this landed, so clearing the review request
Attachment #111480 - Flags: review?(sspitzer)
Seems like the original checkin on January is the root cause for bug 192808. 

I can't pinpoint the exact location and don't have conclusive evidence, I did
confirm however that the problem started occurring after January 17. This change
is the most likely candidate for the XPI hangers we have been seeing with 1.3b.
Blocks: 192808
>>> People should be on the look out for add on applications that no longer work
after this checkin.

Greetings.  I am the lead developer of a Mozilla add-on application which uses
networking code through XPCOM.  I am most furious about this bug.

One of the fundamental concepts of COM is that interfaces never change.  I see
absolutely no reason why it was necessary to change function definitions and
outright remove entire functions from public interfaces which are being widely
used by Mozilla add-on applications.  Interfaces /never/ change.  Interfaces can
be added to, and new interfaces can be created, but existing interfaces should
/never/ change.  Certainly changes which involve outright removing of functions
should scream "CREATE A NEW INTERFACE" to the developer.

Mozilla's interfaces are frozen by the act of publishing the software. 
Developers cannot limit themselves to working mearly on your officially frozen APIs.

Because of this change, numerous developers like myself are forced to branch
their projects and maintain a release which will work with pre-1.3b Mozilla, and
another that will work with post-1.3b Mozilla.  I'm unable to simply update my
project to work with 1.3b and ignore users with older software.

Please, consider all APIs frozen by act of software publication.  This is not
going to harm your development, it will simply make Mozilla a friendly
development environment.
> Please, consider all APIs frozen by act of software publication.

That would mean never checking in any work-in-progress, making development
_very_ difficult.  Right now the @FROZEN tag exists to mark interfaces public;
any interface not marked such is a work in progress and should _NOT_ be treated
as a public interface -- it is not one....

If you're finding that you have to use a non-frozen interface, please let us
know!  (n.p.m.embedding, or mailing the module owner involved).  We want to know
about such things so that we can freeze interfaces that are in a finalized state
and are genuinely useful to people (the latter is sometimes more important than
the former).
More importantly, which particular interfaces are the problem in this case?  The
socket transport and the inability to use it to stream data to/from files?
>>> That would mean never checking in any work-in-progress, making development
_very_ difficult.

I don't suggest that work in progress is not checked in.  I suggest that
interfaces which are present in released software (cut, versioned releases)
should not change.

>>> If you're finding that you have to use a non-frozen interface, please let us
know!  (n.p.m.embedding, or mailing the module owner involved).  We want to know
about such things so that we can freeze interfaces that are in a finalized state
and are genuinely useful to people (the latter is sometimes more important than
the former).

I find it unlikely that anybody thought nsITransport and derived interfaces were
only being used internally.  Third party developers have to use these interfaces
to do any low-level networking, right?  If these interfaces aren't to be
considered public, then I can't make useful software with Mozilla.

>>> More importantly, which particular interfaces are the problem in this case?
 The socket transport and the inability to use it to stream data to/from files?

The actual concept behind these changes is what causes me problems.  I need to
re-write my socket code, which was previously done through asyncRead/asyncWrite,
to use an entirely different interface.  The redeclaration of
nsISocketTransportService::createTransport, nsITransport::openInputStream, and
nsITransport::openOutputStream also breaks existing code.
> cut, versioned releases

Then drivers need to get sane and not cut releases every 4 weeks.... :(
Mathieu: i'm sorry for the headache this has caused you, and i am more than
willing to help you make the transition to the new interfaces.  but, most
importantly as boris stated we are learning through this that these interfaces
need to be frozen.  we all know these are important interfaces that would be
required if anyone wanted to write an external component that makes use of the
socket transport for instance, but we were not aware of any such external
components.  moreover, the policy of mozilla.org with regard to frozen
interfaces and such is exactly as boris stated it.  only interfaces marked
"@status FROZEN" should be considered static from release to release.

can you please tell us more about your application?  thx!
> Mathieu: i'm sorry for the headache this has caused you, and i am more than
willing to help you make the transition to the new interfaces.  

Thank you for the offer Darin, but I should be able to figure it out based off
the Chatzilla diff attached to this bug.  My networking code was originally
borrowed from there a year and a half ago, anyways. :)

> moreover, the policy of mozilla.org with regard to frozen
interfaces and such is exactly as boris stated it.  only interfaces marked
"@status FROZEN" should be considered static from release to release.

I understand.  I still believe that this is a flawed policy that makes external
development more difficult.

Without static interfaces, XPCOM doesn't seem to serve any purpose, except that
it provides a common point for multiple programming languages to access each
other.  MSCOM strongly discourages changing interfaces (making it very
difficult), as well as clearly documenting that interfaces should never change.
 As a result, ActiveX controls and other COM-based applications are very cleanly
plug-in-able.  (well, you know, besides the flaws in MS's implementation).

Anyways, this isn't the proper forum to suggest change, and I doubt such a
suggestion would be welcome anyways.  After banging my head on the desk this
morning when reading this bug, I couldn't stop myself from saying /something/.

> can you please tell us more about your application?  thx!

The application is a Mozilla based HTML-rendering MOO/MUD client, similar to
Cacho's old Pueblo application.  It's webpage is http://www.moo.ca/moozilla.

Thanks for listening to my complaints, fellows.  Have a good day.
>Without static interfaces, XPCOM doesn't seem to serve any purpose, except that
>it provides a common point for multiple programming languages to access each
>other.  MSCOM strongly discourages changing interfaces (making it very
>difficult), as well as clearly documenting that interfaces should never change.
> As a result, ActiveX controls and other COM-based applications are very
>cleanly plug-in-able.  (well, you know, besides the flaws in MS's >implementation).

mozilla.org stongly discourages changes to frozen interfaces (verboten!).  the
fact that XPCOM is used to link components _internal_ to the mozilla
implementation is in fact just an implementation detail.  the fact that mozilla
has frozen so few interfaces is the unfortunate bit IMO.  we are working to
freeze more interfaces.
Darin Fisher wrote:
> we are working to freeze more interfaces.

Please be carefull not to freeze too much. There are already a couple of
(badly-designed) interfaces which are frozen and now we have to work around that
(yes, I know, the alternative would be to create a new interface with a new name
- but some of this stuff like nsIPrefsBranch covers most of Mozilla's code...
;-(( ) - which costs _much_ time... ;-((
Attachment #111455 - Flags: superreview?(brendan)
Attachment #111455 - Flags: review?(dougt)
Attachment #111457 - Flags: superreview?(bzbarsky)
Attachment #111457 - Flags: review?(dougt)
Attachment #111473 - Flags: superreview?(bzbarsky)
Attachment #111473 - Flags: review?(dougt)
Attachment #111479 - Flags: review?(rginda)
Comment on attachment 111474 [details] [diff] [review]
patch: http - v1

I would like to keep this on my radar, since I would still like to review the
rest of this code....

What's the bug number for landing the changes that correspond to my comments up
to now, Darin?
Attachment #111474 - Flags: superreview?(bzbarsky)
bz: bug 193917
Depends on: 193917
Attachment #111474 - Flags: superreview?(bzbarsky)
Depends on: 387049
Regressions: 1735152
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: