fixes bug 193917 "incorporate changes from bz's comments in bug 176919" r+sr=bzbarsky

This commit is contained in:
darin%meer.net 2003-10-09 01:54:07 +00:00
parent 2274da47a9
commit cbcb460359
17 changed files with 249 additions and 40 deletions

View File

@ -81,7 +81,7 @@ interface nsIAsyncStreamCopier : nsIRequest
* @param aObserver
* receives notifications.
* @param aObserverContext
* passed to listener methods.
* passed to observer methods.
*/
void asyncCopy(in nsIRequestObserver aObserver,
in nsISupports aObserverContext);

View File

@ -62,6 +62,9 @@ interface nsIInputStreamChannel : nsIChannel
* Otherwise, the stream will be read on a background thread.
*
* This attribute can only be changed before the channel is opened.
*
* @throws NS_ERROR_IN_PROGRESS if the setter is called after the channel
* has been opened.
*/
attribute nsIInputStream contentStream;
};

View File

@ -40,6 +40,20 @@
interface nsIInputStream;
interface nsIStreamListener;
/**
* nsIInputStreamPump
*
* This interface provides a means to configure and use a input stream pump
* instance. The input stream pump will asynchronously read from a input
* stream, and push data to a nsIStreamListener instance. It utilizes the
* current thread's nsIEventTarget in order to make reading from the stream
* asynchronous.
*
* If the given stream supports nsIAsyncInputStream, then the stream pump will
* call the stream's AsyncWait method to drive the stream listener. Otherwise,
* the stream will be read on a background thread utilizing the stream
* transport service. More details are provided below.
*/
[scriptable, uuid(f7dd8d87-efa7-48cc-9d94-df488df0b3f9)]
interface nsIInputStreamPump : nsIRequest
{

View File

@ -40,12 +40,13 @@
interface nsIInterfaceRequestor;
interface nsISocketEventSink;
[ptr] native PRNetAddrStar(union PRNetAddr);
native PRNetAddr(union PRNetAddr);
/**
* nsISocketTransport
*
* NOTE: This is a free-threaded interface.
* NOTE: This is a free-threaded interface, meaning that the methods on
* this interface may be called from any thread.
*/
[scriptable, uuid(1e372001-ca12-4507-8405-3267d4e0c1fd)]
interface nsISocketTransport : nsITransport
@ -64,18 +65,18 @@ interface nsISocketTransport : nsITransport
* Returns the IP address for the underlying socket connection. This
* attribute is only defined once a connection has been established.
*/
[noscript] void getAddress(in PRNetAddrStar netAddr);
[noscript] PRNetAddr getAddress();
/**
* Security info object returned from the PSM socket provider. This object
* supports nsISSLSocketControl, nsITransportSecurityInfo, and possibly
* other interfaces.
* Security info object returned from the secure socket provider. This
* object supports nsISSLSocketControl, nsITransportSecurityInfo, and
* possibly other interfaces.
*/
readonly attribute nsISupports securityInfo;
/**
* Security notification callbacks passed to PSM via nsISSLSocketControl at
* socket creation time.
* Security notification callbacks passed to the secure socket provider
* via nsISSLSocketControl at socket creation time.
*
* NOTE: this attribute cannot be changed once a stream has been opened.
*/
@ -94,13 +95,20 @@ interface nsISocketTransport : nsITransport
* with existing error codes in Necko, these status codes are confined
* within a very limited context where no error codes may appear, so there
* is no ambiguity.
*
* The values of these status codes must never change.
*
* The status codes appear in near-chronological order (not in numeric
* order). STATUS_RESOLVING may be skipped if the host does not need to be
* resolved. STATUS_WAITING_FOR is an optional status code, which the impl
* of this interface may choose not to generate.
*/
const unsigned long STATUS_RESOLVING = 0x804b0003;
const unsigned long STATUS_CONNECTING_TO = 0x804b0007;
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;
const unsigned long STATUS_RECEIVING_FROM = 0x804b0006;
};
%{C++

View File

@ -42,6 +42,21 @@ interface nsIOutputStream;
interface nsITransportEventSink;
interface nsIEventTarget;
/**
* nsITransport
*
* This interface provides a common way of accessing i/o streams connected
* to some resource. This interface does not in any way specify the resource.
* It provides methods to open blocking or non-blocking, buffered or unbuffered
* streams to the resource. The name "transport" is meant to connote the
* inherent data transfer implied by this interface (i.e., data is being
* transfered in some fashion via the streams exposed by this interface).
*
* A transport can have an event sink associated with it. The event sink
* receives transport-specific events as the transfer is occuring. For a
* socket transport, these events can include status about the connection.
* See nsISocketTransport for more info about socket transport specifics.
*/
[scriptable, uuid(cbb0baeb-5fcb-408b-a2be-9f8fc98d0af1)]
interface nsITransport : nsISupports
{
@ -54,6 +69,25 @@ interface nsITransport : nsISupports
/**
* Open an input stream on this transport.
*
* Flags have the following meaning:
*
* OPEN_BLOCKING
* If specified, then the resulting stream will have blocking stream
* semantics. This means that if the stream has no data and is not
* closed, then reading from it will block the calling thread until
* at least one byte is available or until the stream is closed.
* If this flag is NOT specified, then the stream has non-blocking
* stream semantics. This means that if the stream has no data and is
* not closed, then reading from it returns NS_BASE_STREAM_WOULD_BLOCK.
* In addition, in non-blocking mode, the stream is guaranteed to
* support nsIAsyncInputStream. This interface allows the consumer of
* the stream to be notified when the stream can again be read.
*
* OPEN_UNBUFFERED
* If specified, the resulting stream may not support ReadSegments.
* ReadSegments is only gauranteed to be implemented when this flag is
* NOT specified.
*
* @param aFlags
* optional transport specific flags.
* @param aSegmentSize
@ -70,6 +104,25 @@ interface nsITransport : nsISupports
/**
* Open an output stream on this transport.
*
* Flags have the following meaning:
*
* OPEN_BLOCKING
* If specified, then the resulting stream will have blocking stream
* semantics. This means that if the stream is full and is not closed,
* then writing to it will block the calling thread until ALL of the
* data can be written or until the stream is closed. If this flag is
* NOT specified, then the stream has non-blocking stream semantics.
* This means that if the stream is full and is not closed, then writing
* to it returns NS_BASE_STREAM_WOULD_BLOCK. In addition, in non-
* blocking mode, the stream is guaranteed to support
* nsIAsyncOutputStream. This interface allows the consumer of the
* stream to be notified when the stream can again accept more data.
*
* OPEN_UNBUFFERED
* If specified, the resulting stream may not support WriteSegments and
* WriteFrom. WriteSegments and WriteFrom are only gauranteed to be
* implemented when this flag is NOT specified.
*
* @param aFlags
* optional transport specific flags.
* @param aSegmentSize

View File

@ -283,6 +283,8 @@ nsInputStreamChannel::Open(nsIInputStream **result)
NS_ENSURE_TRUE(mContentStream, NS_ERROR_NOT_INITIALIZED);
NS_ENSURE_TRUE(!mPump, NS_ERROR_IN_PROGRESS);
// XXX this won't work if mContentStream is non-blocking.
NS_ADDREF(*result = mContentStream);
return NS_OK;
}
@ -293,6 +295,11 @@ nsInputStreamChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
NS_ENSURE_TRUE(mContentStream, NS_ERROR_NOT_INITIALIZED);
NS_ENSURE_TRUE(!mPump, NS_ERROR_IN_PROGRESS);
// if content length is unknown, then we must guess... in this case, we
// assume the stream can tell us. if the stream is a pipe, then this will
// not work. in that case, we hope that the user of this interface would
// have set our content length to PR_UINT32_MAX to cause us to read until
// end of stream.
if (mContentLength == -1)
mContentStream->Available((PRUint32 *) &mContentLength);

View File

@ -64,7 +64,7 @@ static PRLogModuleInfo *gStreamPumpLog = nsnull;
nsInputStreamPump::nsInputStreamPump()
: mState(STATE_IDLE)
, mStreamOffset(0)
, mStreamLength(~0U)
, mStreamLength(PR_UINT32_MAX)
, mStatus(NS_OK)
, mSuspendCount(0)
, mLoadFlags(LOAD_NORMAL)
@ -84,6 +84,9 @@ nsInputStreamPump::~nsInputStreamPump()
nsresult
nsInputStreamPump::EnsureWaiting()
{
// no need to worry about multiple threads... an input stream pump lives
// on only one thread.
if (!mWaiting) {
nsresult rv = mAsyncStream->AsyncWait(this, 0, 0, mEventQ);
if (NS_FAILED(rv)) {
@ -244,8 +247,20 @@ nsInputStreamPump::AsyncRead(nsIStreamListener *listener, nsISupports *ctxt)
rv = mStream->IsNonBlocking(&nonBlocking);
if (NS_FAILED(rv)) return rv;
if (nonBlocking)
if (nonBlocking) {
mAsyncStream = do_QueryInterface(mStream);
//
// if the stream supports nsIAsyncInputStream, and if we need to seek
// to a starting offset, then we must do so here. in the non-async
// stream case, the stream transport service will take care of seeking
// for us.
//
if (mAsyncStream && (mStreamOffset != PR_UINT32_MAX)) {
nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mStream);
if (seekable)
seekable->Seek(nsISeekableStream::NS_SEEK_SET, mStreamOffset);
}
}
if (!mAsyncStream) {
// ok, let's use the stream transport service to read this stream.

View File

@ -119,7 +119,7 @@ static PRErrorCode RandomizeConnectError(PRErrorCode code)
{
//
// To test out these errors, load http://www.yahoo.com/. It should load
// correctly despite the random occurance of there errors.
// correctly despite the random occurance of these errors.
//
int n = rand();
if (n > RAND_MAX/2) {
@ -209,6 +209,8 @@ nsSocketInputStream::OnSocketReady(nsresult condition)
LOG(("nsSocketInputStream::OnSocketReady [this=%x cond=%x]\n",
this, condition));
NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
nsCOMPtr<nsIInputStreamCallback> callback;
{
nsAutoLock lock(mTransport->mLock);
@ -450,6 +452,8 @@ nsSocketOutputStream::OnSocketReady(nsresult condition)
LOG(("nsSocketOutputStream::OnSocketReady [this=%x cond=%x]\n",
this, condition));
NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
nsCOMPtr<nsIOutputStreamCallback> callback;
{
nsAutoLock lock(mTransport->mLock);
@ -683,7 +687,7 @@ nsSocketTransport::~nsSocketTransport()
PRUint32 i;
for (i=0; i<mTypeCount; ++i)
PL_strfree(mTypes[i]);
PR_Free(mTypes);
free(mTypes);
}
if (mLock)
@ -720,7 +724,7 @@ nsSocketTransport::Init(const char **types, PRUint32 typeCount,
// include proxy type as a socket type if proxy type is not "http"
mTypeCount = typeCount + (proxyType != nsnull);
if (mTypeCount) {
mTypes = (char **) PR_Malloc(mTypeCount * sizeof(char *));
mTypes = (char **) malloc(mTypeCount * sizeof(char *));
if (!mTypes)
return NS_ERROR_OUT_OF_MEMORY;
@ -794,7 +798,7 @@ nsSocketTransport::SendStatus(nsresult status)
}
}
if (sink)
sink->OnTransportStatus(this, status, progress, ~0U);
sink->OnTransportStatus(this, status, progress, PR_UINT32_MAX);
}
nsresult
@ -1133,8 +1137,10 @@ nsSocketTransport::OnMsgInputClosed(nsresult reason)
LOG(("nsSocketTransport::OnMsgInputClosed [this=%x reason=%x]\n",
this, reason));
NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
mInputClosed = PR_TRUE;
// check if event should effect entire transport
// check if event should affect entire transport
if (NS_FAILED(reason) && (reason != NS_BASE_STREAM_CLOSED))
mCondition = reason; // XXX except if NS_FAILED(mCondition), right??
else if (mOutputClosed)
@ -1153,8 +1159,10 @@ nsSocketTransport::OnMsgOutputClosed(nsresult reason)
LOG(("nsSocketTransport::OnMsgOutputClosed [this=%x reason=%x]\n",
this, reason));
NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
mOutputClosed = PR_TRUE;
// check if event should effect entire transport
// check if event should affect entire transport
if (NS_FAILED(reason) && (reason != NS_BASE_STREAM_CLOSED))
mCondition = reason; // XXX except if NS_FAILED(mCondition), right??
else if (mInputClosed)
@ -1372,6 +1380,8 @@ nsSocketTransport::OnSocketDetached(PRFileDesc *fd)
LOG(("nsSocketTransport::OnSocketDetached [this=%x cond=%x]\n",
this, mCondition));
NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
// if we didn't initiate this detach, then be sure to pass an error
// condition up to our consumers. (e.g., STS is shutting down.)
if (NS_SUCCEEDED(mCondition))

View File

@ -92,6 +92,7 @@ nsSocketTransportService::nsSocketTransportService()
PR_INIT_CLIST(&mEventQ);
PR_INIT_CLIST(&mPendingSocketQ);
NS_ASSERTION(!gSocketTransportService, "must not instantiate twice");
gSocketTransportService = this;
}
@ -145,6 +146,8 @@ nsSocketTransportService::NotifyWhenCanAttachSocket(PLEvent *event)
{
LOG(("nsSocketTransportService::NotifyWhenCanAttachSocket\n"));
NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
if (CanAttachSocket()) {
NS_WARNING("should have called CanAttachSocket");
return PostEvent(event);
@ -159,6 +162,8 @@ nsSocketTransportService::AttachSocket(PRFileDesc *fd, nsASocketHandler *handler
{
LOG(("nsSocketTransportService::AttachSocket [handler=%x]\n", handler));
NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
SocketContext sock;
sock.mFD = fd;
sock.mHandler = handler;

View File

@ -57,7 +57,8 @@ interface nsICacheEntryDescriptor : nsICacheEntryInfo
* stream MAY implement nsISeekableStream.
*
* @param offset
* read starting from this offset into the cached data.
* read starting from this offset into the cached data. an offset
* beyond the end of the stream has undefined consequences.
*
* @return blocking, unbuffered input stream.
*/
@ -73,7 +74,8 @@ interface nsICacheEntryDescriptor : nsICacheEntryInfo
* truncated to the specified offset.
*
* @param offset
* write starting from this offset into the cached data.
* write starting from this offset into the cached data. an offset
* beyond the end of the stream has undefined consequences.
*
* @return blocking, unbuffered output stream.
*/

View File

@ -589,7 +589,7 @@ nsOutputStreamWrapper::LazyInit()
nsresult nsCacheEntryDescriptor::
nsOutputStreamWrapper::OnWrite(PRUint32 count)
{
if (count > 0x7FFFFFFF) return NS_ERROR_UNEXPECTED;
if (count > PR_INT32_MAX) return NS_ERROR_UNEXPECTED;
return mDescriptor->RequestDataSizeChange((PRInt32)count);
}

View File

@ -746,7 +746,6 @@ nsresult
nsDiskCacheStreamIO::Seek(PRInt32 whence, PRInt32 offset)
{
PRInt32 newPos;
//nsAutoLock lock(nsCacheService::ServiceLock()); // grab service lock
if (!mBinding) return NS_ERROR_NOT_AVAILABLE;
if (PRUint32(offset) > mStreamEnd) return NS_ERROR_FAILURE;

View File

@ -40,6 +40,34 @@
interface nsIMemory;
/**
* nsIPipe represents an in-process buffer that can be read using nsIInputStream
* and written using nsIOutputStream. The reader and writer of a pipe do not
* have to be on the same thread. As a result, the pipe is an ideal mechanism
* to bridge data exchange between two threads. For example, a worker thread
* might write data to a pipe from which the main thread will read.
*
* Each end of the pipe can be either blocking or non-blocking. Recall that a
* non-blocking stream will return NS_BASE_STREAM_WOULD_BLOCK if it cannot be
* read or written to without blocking the calling thread. For example, if you
* try to read from an empty pipe that has not yet been closed, then if that
* pipe's input end is non-blocking, then the read call will fail immediately
* with NS_BASE_STREAM_WOULD_BLOCK as the error condition. However, if that
* pipe's input end is blocking, then the read call will not return until the
* pipe has data or until the pipe is closed. This example presumes that the
* pipe is being filled asynchronously on some background thread.
*
* The pipe supports nsIAsyncInputStream and nsIAsyncOutputStream, which give
* the user of a non-blocking pipe the ability to wait for the pipe to become
* ready again. For example, in the case of an empty non-blocking pipe, the
* user can call AsyncWait on the input end of the pipe to be notified when
* the pipe has data to read (or when the pipe becomes closed).
*
* NS_NewPipe2 and NS_NewPipe provide convenient pipe constructors. In most
* cases nsIPipe is not actually used. It is usually enough to just get
* references to the pipe's input and output end. In which case, the pipe is
* automatically closed when the respective pipe ends are released.
*/
[scriptable, uuid(f4211abc-61b3-11d4-9877-00c04fa0cf4a)]
interface nsIPipe : nsISupports
{
@ -52,10 +80,21 @@ interface nsIPipe : nsISupports
in unsigned long segmentCount,
in nsIMemory segmentAllocator);
/**
* The pipe's input end, which also implements nsISearchableInputStream.
*/
readonly attribute nsIAsyncInputStream inputStream;
/**
* The pipe's output end.
*/
readonly attribute nsIAsyncOutputStream outputStream;
};
/**
* XXX this interface doesn't really belong in here. It is here because
* currently nsPipeInputStream is the only implementation of this interface.
*/
[scriptable, uuid(8C39EF62-F7C9-11d4-98F5-001083010E9B)]
interface nsISearchableInputStream : nsISupports
{
@ -77,6 +116,35 @@ interface nsISearchableInputStream : nsISupports
%{C++
/**
* NS_NewPipe2
*
* This function supercedes NS_NewPipe. It differs from NS_NewPipe in two
* major ways:
* (1) returns nsIAsyncInputStream and nsIAsyncOutputStream, so it is
* not necessary to QI in order to access these interfaces.
* (2) the size of the pipe is determined by the number of segments
* times the size of each segment.
*
* @param pipeIn
* resulting input end of the pipe
* @param pipeOut
* resulting output end of the pipe
* @param nonBlockingInput
* true specifies non-blocking input stream behavior
* @param nonBlockingOutput
* true specifies non-blocking output stream behavior
* @param segmentSize
* specifies the segment size in bytes (pass 0 to use default value)
* @param segmentCount
* specifies the max number of segments (pass 0 to use default value)
* passing PR_UINT32_MAX here causes the pipe to have "infinite" space.
* this mode can be useful in some cases, but should always be used with
* caution. the default value for this parameter is a finite value.
* @param segmentAlloc
* pass reference to nsIMemory to have all pipe allocations use this
* allocator (pass null to use the default allocator)
*/
extern NS_COM nsresult
NS_NewPipe2(nsIAsyncInputStream **pipeIn,
nsIAsyncOutputStream **pipeOut,
@ -86,6 +154,34 @@ NS_NewPipe2(nsIAsyncInputStream **pipeIn,
PRUint32 segmentCount = 0,
nsIMemory *segmentAlloc = nsnull);
/**
* NS_NewPipe
*
* Preserved for backwards compatibility. Plus, this interface is more
* amiable in certain contexts (e.g., when you don't need the pipe's async
* capabilities).
*
* @param pipeIn
* resulting input end of the pipe
* @param pipeOut
* resulting output end of the pipe
* @param segmentSize
* specifies the segment size in bytes (pass 0 to use default value)
* @param maxSize
* specifies the max size of the pipe (pass 0 to use default value)
* number of segments is maxSize / segmentSize, and maxSize must be a
* multiple of segmentSize. passing PR_UINT32_MAX here causes the
* pipe to have "infinite" space. this mode can be useful in some
* cases, but should always be used with caution. the default value
* for this parameter is a finite value.
* @param nonBlockingInput
* true specifies non-blocking input stream behavior
* @param nonBlockingOutput
* true specifies non-blocking output stream behavior
* @param segmentAlloc
* pass reference to nsIMemory to have all pipe allocations use this
* allocator (pass null to use the default allocator)
*/
inline nsresult
NS_NewPipe(nsIInputStream **pipeIn,
nsIOutputStream **pipeOut,

View File

@ -183,6 +183,14 @@ nsInputStreamTee::GetSource(nsIInputStream **source)
NS_IMETHODIMP
nsInputStreamTee::SetSink(nsIOutputStream *sink)
{
#ifdef DEBUG
if (sink) {
PRBool nonBlocking;
nsresult rv = sink->IsNonBlocking(&nonBlocking);
if (NS_FAILED(rv) || nonBlocking)
NS_ERROR("sink should be a blocking stream");
}
#endif
mSink = sink;
return NS_OK;
}

View File

@ -319,7 +319,6 @@ nsPipe::nsPipe()
, mWriteLimit(nsnull)
, mStatus(NS_OK)
{
NS_INIT_ISUPPORTS();
}
nsPipe::~nsPipe()
@ -760,7 +759,7 @@ nsPipeInputStream::ReadSegments(nsWriteSegmentFun writer,
rv = writer(this, closure, segment, *readCount, segmentLen, &writeCount);
if (NS_FAILED(rv) || (writeCount == 0)) {
if (NS_FAILED(rv) || writeCount == 0) {
count = 0;
// any errors returned from the writer end here: do not
// propogate to the caller of ReadSegments.
@ -768,6 +767,7 @@ nsPipeInputStream::ReadSegments(nsWriteSegmentFun writer,
break;
}
NS_ASSERTION(writeCount <= segmentLen, "wrote more than expected");
segment += writeCount;
segmentLen -= writeCount;
count -= writeCount;
@ -1095,7 +1095,7 @@ nsPipeOutputStream::WriteSegments(nsReadSegmentFun reader,
rv = reader(this, closure, segment, *writeCount, segmentLen, &readCount);
if (NS_FAILED(rv) || (readCount == 0)) {
if (NS_FAILED(rv) || readCount == 0) {
count = 0;
// any errors returned from the reader end here: do not
// propogate to the caller of WriteSegments.
@ -1103,6 +1103,7 @@ nsPipeOutputStream::WriteSegments(nsReadSegmentFun reader,
break;
}
NS_ASSERTION(readCount <= segmentLen, "read more than expected");
segment += readCount;
segmentLen -= readCount;
count -= readCount;

View File

@ -401,9 +401,7 @@ TestPipeObserver()
////////////////////////////////////////////////////////////////////////////////
class nsPump : /*public nsIInputStreamObserver,
public nsIOutputStreamObserver,*/
public nsIRunnable
class nsPump : public nsIRunnable
{
public:
NS_DECL_ISUPPORTS
@ -489,14 +487,12 @@ TestChainedPipes()
len = len * rand() / RAND_MAX;
len = PR_MAX(1, len);
rv = WriteAll(out1, buf, len, &writeCount);
//rv = out1->Write(buf, len, &writeCount);
if (NS_FAILED(rv)) return rv;
NS_ASSERTION(writeCount == len, "didn't write enough");
total += writeCount;
if (gTrace)
printf("wrote %d bytes: %s\n", writeCount, buf);
//out1->Flush(); // wakes up the pump
PR_smprintf_free(buf);
}
@ -638,8 +634,6 @@ main(int argc, char* argv[])
TestSearch("baz", 2);
#endif
//rv = TestPipeObserver();
//NS_ASSERTION(NS_SUCCEEDED(rv), "TestPipeObserver failed");
rv = TestChainedPipes();
NS_ASSERTION(NS_SUCCEEDED(rv), "TestChainedPipes failed");
RunTests(16, 1);

View File

@ -45,14 +45,8 @@
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;
return CallGetService(kEventQueueServiceCID, result);
}
inline nsresult