diff --git a/mozilla/xpcom/build/dlldeps.cpp b/mozilla/xpcom/build/dlldeps.cpp index 5ef2ef777db..c92791f6031 100644 --- a/mozilla/xpcom/build/dlldeps.cpp +++ b/mozilla/xpcom/build/dlldeps.cpp @@ -49,8 +49,7 @@ void XXXNeverCalled() nsVoidArray(); NS_GetNumberOfAtoms(); nsFileURL(NULL); -// NS_NewPipe(NULL, NULL); - NS_NewPipe2(NULL, NULL, 0, 0); + NS_NewPipe(NULL, NULL, 0, 0, 0, NULL); nsFileSpec s; NS_NewIOFileStream(NULL, s, 0, 0); nsInputFileStream(s, 0, 0); diff --git a/mozilla/xpcom/ds/nsBuffer.cpp b/mozilla/xpcom/ds/nsBuffer.cpp index 70eefac1a96..27b5fbfd18c 100644 --- a/mozilla/xpcom/ds/nsBuffer.cpp +++ b/mozilla/xpcom/ds/nsBuffer.cpp @@ -42,13 +42,15 @@ nsBuffer::nsBuffer() NS_IMETHODIMP nsBuffer::Init(PRUint32 growBySize, PRUint32 maxSize, - nsIAllocator* allocator) + nsIBufferObserver* observer, nsIAllocator* allocator) { NS_ASSERTION(sizeof(PRCList) <= SEGMENT_OVERHEAD, "need to change SEGMENT_OVERHEAD size"); NS_ASSERTION(growBySize > SEGMENT_OVERHEAD, "bad growBySize"); mGrowBySize = growBySize; mMaxSize = maxSize; + mObserver = observer; + NS_IF_ADDREF(mObserver); mAllocator = allocator; NS_ADDREF(mAllocator); return NS_OK; @@ -56,6 +58,7 @@ nsBuffer::Init(PRUint32 growBySize, PRUint32 maxSize, nsBuffer::~nsBuffer() { + NS_IF_RELEASE(mObserver); NS_IF_RELEASE(mAllocator); } @@ -85,6 +88,10 @@ nsBuffer::PushWriteSegment() nsAutoMonitor mon(this); // protect mSegments if (mBufferSize >= mMaxSize) { + if (mObserver) { + nsresult rv = mObserver->OnFull(); + if (NS_FAILED(rv)) return rv; + } return NS_ERROR_FAILURE; } @@ -135,6 +142,10 @@ nsBuffer::PopReadSegment() mReadSegment = nsnull; mReadSegmentEnd = nsnull; mReadCursor = nsnull; + if (mObserver) { + rv = mObserver->OnEmpty(); + if (NS_FAILED(rv)) return rv; + } } else { mReadSegment = mSegments.next; @@ -159,11 +170,11 @@ nsBuffer::ReadSegments(nsWriteSegmentFun writer, void* closure, PRUint32 count, while (count > 0) { rv = GetReadSegment(0, &readBuffer, &readBufferLen); if (rv == NS_BASE_STREAM_EOF) // all we're going to get - return *readCount > 0 ? NS_OK : NS_BASE_STREAM_EOF; + return *readCount == 0 ? rv : NS_OK; if (NS_FAILED(rv)) return rv; if (readBufferLen == 0) - return mEOF && *readCount == 0 ? NS_BASE_STREAM_EOF : NS_OK; + return mEOF && (*readCount == 0) ? NS_BASE_STREAM_EOF : NS_OK; readBufferLen = PR_MIN(readBufferLen, count); while (readBufferLen > 0) { @@ -172,7 +183,7 @@ nsBuffer::ReadSegments(nsWriteSegmentFun writer, void* closure, PRUint32 count, if (NS_FAILED(rv)) { // if we failed to write just report what we were // able to read so far - return NS_OK; + return (*readCount == 0) ? rv : NS_OK; } NS_ASSERTION(writeCount <= readBufferLen, "writer returned bad writeCount"); readBuffer += writeCount; @@ -192,7 +203,7 @@ nsBuffer::ReadSegments(nsWriteSegmentFun writer, void* closure, PRUint32 count, return NS_OK; } -NS_METHOD +static NS_METHOD nsWriteToRawBuffer(void* closure, const char* fromRawSegment, PRUint32 offset, @@ -208,39 +219,7 @@ nsWriteToRawBuffer(void* closure, NS_IMETHODIMP nsBuffer::Read(char* toBuf, PRUint32 bufLen, PRUint32 *readCount) { -#if 1 return ReadSegments(nsWriteToRawBuffer, toBuf, bufLen, readCount); -#else - nsresult rv; - PRUint32 readBufferLen; - char* readBuffer; - - *readCount = 0; - while (bufLen > 0) { - rv = GetReadSegment(0, &readBuffer, &readBufferLen); - if (rv == NS_BASE_STREAM_EOF) // all we're going to get - return *readCount > 0 ? NS_OK : NS_BASE_STREAM_EOF; - if (NS_FAILED(rv)) return rv; - - if (readBufferLen == 0) - return mEOF && *readCount == 0 ? NS_BASE_STREAM_EOF : NS_OK; - - PRUint32 count = PR_MIN(bufLen, readBufferLen); - nsCRT::memcpy(toBuf, readBuffer, count); - *readCount += count; - toBuf += count; - bufLen -= count; - - if (mReadCursor + count == mReadSegmentEnd) { - rv = PopReadSegment(); - if (NS_FAILED(rv)) return rv; - } - else { - mReadCursor += count; - } - } - return NS_OK; -#endif } NS_IMETHODIMP @@ -319,6 +298,59 @@ nsBuffer::GetReadSegment(PRUint32 segmentLogicalOffset, return NS_ERROR_FAILURE; } +NS_IMETHODIMP +nsBuffer::GetReadableAmount(PRUint32 *result) +{ + // first set the read segment and cursor if not already set + if (mReadSegment == nsnull) { + if (PR_CLIST_IS_EMPTY(&mSegments)) { + *result = 0; + return NS_OK; + } + else { + mReadSegment = mSegments.next; + mReadSegmentEnd = (char*)mReadSegment + mGrowBySize; + mReadCursor = (char*)mReadSegment + sizeof(PRCList); + *result = mGrowBySize; + } + } + + // now search for the segment starting from segmentLogicalOffset and return it + PRCList* curSeg = mReadSegment; + char* curSegStart = mReadCursor; + char* curSegEnd = mReadSegmentEnd; + PRInt32 amt; + while (PR_TRUE) { + // snapshot the write cursor into a local variable -- this allows + // a writer to freely change it while we're reading while avoiding + // using a lock + char* snapshotWriteCursor = mWriteCursor; // atomic + + // next check if the write cursor is in our segment + if (curSegStart <= snapshotWriteCursor && + snapshotWriteCursor < curSegEnd) { + // same segment -- read up to the snapshotWriteCursor + curSegEnd = snapshotWriteCursor; + + amt = curSegEnd - curSegStart; + *result += amt; + return NS_OK; + } + else { + amt = curSegEnd - curSegStart; + *result += amt; + curSeg = PR_NEXT_LINK(curSeg); + if (curSeg == mReadSegment) { + // been all the way around + return NS_OK; + } + curSegEnd = (char*)curSeg + mGrowBySize; + curSegStart = (char*)curSeg + sizeof(PRCList); + } + } + return NS_ERROR_FAILURE; +} + //////////////////////////////////////////////////////////////////////////////// NS_IMETHODIMP @@ -339,7 +371,7 @@ nsBuffer::WriteSegments(nsReadSegmentFun reader, void* closure, PRUint32 count, // if we failed to allocate a new segment, we're probably out // of memory, but we don't care -- just report what we were // able to write so far - return (*writeCount == 0) ? NS_BASE_STREAM_FULL : NS_OK; + return (*writeCount == 0) ? NS_BASE_STREAM_FULL : NS_OK; } writeBufLen = PR_MIN(writeBufLen, count); @@ -350,11 +382,11 @@ nsBuffer::WriteSegments(nsReadSegmentFun reader, void* closure, PRUint32 count, // If the input stream ends, set EOF on the buffer so that // nsBuffer::Read later notices it. SetEOF(); - return NS_OK; + return (*writeCount == 0) ? rv : NS_OK; } else if (rv == NS_BASE_STREAM_WOULD_BLOCK) { - // If no more data is available then return... - return rv; + // If no more data is available then return... + return rv; } else if (NS_FAILED(rv)) { // if we failed to read just report what we were @@ -380,7 +412,7 @@ nsBuffer::WriteSegments(nsReadSegmentFun reader, void* closure, PRUint32 count, return NS_OK; } -NS_METHOD +static NS_METHOD nsReadFromRawBuffer(void* closure, char* toRawSegment, PRUint32 offset, @@ -396,45 +428,10 @@ nsReadFromRawBuffer(void* closure, NS_IMETHODIMP nsBuffer::Write(const char* fromBuf, PRUint32 bufLen, PRUint32 *writeCount) { -#if 1 return WriteSegments(nsReadFromRawBuffer, (void*)fromBuf, bufLen, writeCount); -#else - nsresult rv; - - if (mEOF) - return NS_BASE_STREAM_EOF; - - *writeCount = 0; - while (bufLen > 0) { - PRUint32 writeBufLen; - char* writeBuf; - rv = GetWriteSegment(&writeBuf, &writeBufLen); - if (NS_FAILED(rv)) { - // if we failed to allocate a new segment, we're probably out - // of memory, but we don't care -- just report what we were - // able to write so far - return NS_OK; - } - - PRUint32 count = PR_MIN(writeBufLen, bufLen); - nsCRT::memcpy(writeBuf, fromBuf, count); - fromBuf += count; - bufLen -= count; - *writeCount += count; - // set the write cursor after the data is valid - if (mWriteCursor + count == mWriteSegmentEnd) { - mWriteSegment = nsnull; // allocate a new segment next time around - mWriteSegmentEnd = nsnull; - mWriteCursor = nsnull; - } - else - mWriteCursor += count; - } - return NS_OK; -#endif } -NS_METHOD +static NS_METHOD nsReadFromInputStream(void* closure, char* toRawSegment, PRUint32 offset, @@ -448,52 +445,7 @@ nsReadFromInputStream(void* closure, NS_IMETHODIMP nsBuffer::WriteFrom(nsIInputStream* fromStream, PRUint32 count, PRUint32 *writeCount) { -#if 1 return WriteSegments(nsReadFromInputStream, fromStream, count, writeCount); -#else - nsresult rv; - - if (mEOF) - return NS_BASE_STREAM_EOF; - - *writeCount = 0; - while (count > 0) { - PRUint32 writeBufLen; - char* writeBuf; - rv = GetWriteSegment(&writeBuf, &writeBufLen); - if (NS_FAILED(rv)) { - // if we failed to allocate a new segment, we're probably out - // of memory, but we don't care -- just report what we were - // able to write so far - return NS_OK; - } - - PRUint32 readCount; - rv = fromStream->Read(writeBuf, PR_MIN(writeBufLen, count), &readCount); - if (rv == NS_BASE_STREAM_EOF) { - // If the input stream ends, set EOF on the buffer so that - // nsBuffer::Read later notices it. - SetEOF(); - return NS_OK; - } - else if (NS_FAILED(rv)) { - // if we failed to read just report what we were - // able to write so far - return NS_OK; - } - *writeCount += readCount; - count -= readCount; - // set the write cursor after the data is valid - if (mWriteCursor + readCount == mWriteSegmentEnd) { - mWriteSegment = nsnull; // allocate a new segment next time around - mWriteSegmentEnd = nsnull; - mWriteCursor = nsnull; - } - else - mWriteCursor += readCount; - } - return NS_OK; -#endif } NS_IMETHODIMP @@ -507,9 +459,6 @@ nsBuffer::GetWriteSegment(char* *resultSegment, nsresult rv; if (mWriteSegment == nsnull) { - if (mBufferSize >= mMaxSize) - return NS_ERROR_FAILURE; - rv = PushWriteSegment(); if (NS_FAILED(rv)) return rv; @@ -521,6 +470,17 @@ nsBuffer::GetWriteSegment(char* *resultSegment, return NS_OK; } +NS_IMETHODIMP +nsBuffer::GetWritableAmount(PRUint32 *amount) +{ + nsresult rv; + PRUint32 readableAmount; + rv = GetReadableAmount(&readableAmount); + if (NS_FAILED(rv)) return rv; + *amount = mMaxSize - readableAmount; + return NS_OK; +} + NS_IMETHODIMP nsBuffer::SetEOF() { @@ -616,7 +576,8 @@ static NS_DEFINE_CID(kAllocatorCID, NS_ALLOCATOR_CID); NS_COM nsresult NS_NewBuffer(nsIBuffer* *result, - PRUint32 growBySize, PRUint32 maxSize) + PRUint32 growBySize, PRUint32 maxSize, + nsIBufferObserver* observer) { nsresult rv; NS_WITH_SERVICE(nsIAllocator, alloc, kAllocatorCID, &rv); @@ -626,7 +587,7 @@ NS_NewBuffer(nsIBuffer* *result, rv = nsBuffer::Create(NULL, nsIBuffer::GetIID(), (void**)&buf); if (NS_FAILED(rv)) return rv; - rv = buf->Init(growBySize, maxSize, alloc); + rv = buf->Init(growBySize, maxSize, observer, alloc); if (NS_FAILED(rv)) { NS_RELEASE(buf); return rv; @@ -640,7 +601,8 @@ static NS_DEFINE_CID(kPageManagerCID, NS_PAGEMANAGER_CID); NS_COM nsresult NS_NewPageBuffer(nsIBuffer* *result, - PRUint32 growBySize, PRUint32 maxSize) + PRUint32 growBySize, PRUint32 maxSize, + nsIBufferObserver* observer) { nsresult rv; NS_WITH_SERVICE(nsIAllocator, alloc, kPageManagerCID, &rv); @@ -650,7 +612,7 @@ NS_NewPageBuffer(nsIBuffer* *result, rv = nsBuffer::Create(NULL, nsIBuffer::GetIID(), (void**)&buf); if (NS_FAILED(rv)) return rv; - rv = buf->Init(growBySize, maxSize, alloc); + rv = buf->Init(growBySize, maxSize, observer, alloc); if (NS_FAILED(rv)) { NS_RELEASE(buf); return rv; diff --git a/mozilla/xpcom/ds/nsBuffer.h b/mozilla/xpcom/ds/nsBuffer.h index 2eef5ef0ef6..77f9d057106 100644 --- a/mozilla/xpcom/ds/nsBuffer.h +++ b/mozilla/xpcom/ds/nsBuffer.h @@ -33,19 +33,21 @@ public: // nsIBuffer methods: NS_IMETHOD Init(PRUint32 growBySize, PRUint32 maxSize, - nsIAllocator* allocator); + nsIBufferObserver* observer, nsIAllocator* allocator); NS_IMETHOD Read(char* toBuf, PRUint32 bufLen, PRUint32 *readCount); NS_IMETHOD ReadSegments(nsWriteSegmentFun writer, void* closure, PRUint32 count, PRUint32 *readCount); NS_IMETHOD GetReadSegment(PRUint32 segmentLogicalOffset, const char* *resultSegment, PRUint32 *resultSegmentLen); + NS_IMETHOD GetReadableAmount(PRUint32 *amount); NS_IMETHOD Write(const char* fromBuf, PRUint32 bufLen, PRUint32 *writeCount); NS_IMETHOD WriteFrom(nsIInputStream* fromStream, PRUint32 count, PRUint32 *writeCount); NS_IMETHOD WriteSegments(nsReadSegmentFun reader, void* closure, PRUint32 count, PRUint32 *writeCount); NS_IMETHOD GetWriteSegment(char* *resultSegment, PRUint32 *resultSegmentLen); + NS_IMETHOD GetWritableAmount(PRUint32 *amount); NS_IMETHOD SetEOF(); NS_IMETHOD AtEOF(PRBool *result); NS_IMETHOD Search(const char* forString, PRBool ignoreCase, @@ -62,6 +64,7 @@ protected: PRUint32 mGrowBySize; PRUint32 mMaxSize; nsIAllocator* mAllocator; + nsIBufferObserver* mObserver; PRCList mSegments; PRUint32 mBufferSize; diff --git a/mozilla/xpcom/ds/nsIBuffer.h b/mozilla/xpcom/ds/nsIBuffer.h index 67591552c6e..ed876250311 100644 --- a/mozilla/xpcom/ds/nsIBuffer.h +++ b/mozilla/xpcom/ds/nsIBuffer.h @@ -26,6 +26,7 @@ class nsIInputStream; class nsIAllocator; class nsIBufferInputStream; class nsIBufferOutputStream; +class nsIBufferObserver; #define NS_IBUFFER_IID \ { /* 1eebb300-fb8b-11d2-9324-00104ba0fd40 */ \ @@ -76,7 +77,7 @@ public: * minus SEGMENT_OVERHEAD bytes. */ NS_IMETHOD Init(PRUint32 growBySize, PRUint32 maxSize, - nsIAllocator* allocator) = 0; + nsIBufferObserver* observer, nsIAllocator* allocator) = 0; /** * Reads from the read cursor into a char buffer up to a specified length. @@ -103,6 +104,11 @@ public: const char* *resultSegment, PRUint32 *resultSegmentLen) = 0; + /** + * Returns the amount of data currently in the buffer available for reading. + */ + NS_IMETHOD GetReadableAmount(PRUint32 *amount) = 0; + /** * Writes from a char buffer up to a specified length. * @param writeCount - The amount that could be written. If the buffer becomes full, @@ -133,6 +139,11 @@ public: NS_IMETHOD GetWriteSegment(char* *resultSegment, PRUint32 *resultSegmentLen) = 0; + /** + * Returns the amount of space currently in the buffer available for writing. + */ + NS_IMETHOD GetWritableAmount(PRUint32 *amount) = 0; + /** * Sets an EOF marker (typcially done by the writer) so that a reader can be informed * when all the data in the buffer is consumed. After the EOF marker has been @@ -160,13 +171,47 @@ public: PRBool *found, PRUint32 *offsetSearchedTo) = 0; }; +//////////////////////////////////////////////////////////////////////////////// + +#define NS_IBUFFEROBSERVER_IID \ +{ /* 0c18bef0-22a8-11d3-9349-00104ba0fd40 */ \ + 0x0c18bef0, \ + 0x22a8, \ + 0x11d3, \ + {0x93, 0x49, 0x00, 0x10, 0x4b, 0xa0, 0xfd, 0x40} \ +} + +/** + * A buffer observer is used to detect when the buffer becomes completely full + * or completely empty. + */ +class nsIBufferObserver : public nsISupports { +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IBUFFEROBSERVER_IID); + + NS_IMETHOD OnFull() = 0; + + NS_IMETHOD OnEmpty() = 0; +}; + +//////////////////////////////////////////////////////////////////////////////// + +/** + * Creates a new buffer. + * @param observer - may be null + */ extern NS_COM nsresult NS_NewBuffer(nsIBuffer* *result, - PRUint32 growBySize, PRUint32 maxSize); + PRUint32 growBySize, PRUint32 maxSize, + nsIBufferObserver* observer); +/** + * Creates a new buffer, allocating segments from virtual memory pages. + */ extern NS_COM nsresult NS_NewPageBuffer(nsIBuffer* *result, - PRUint32 growBySize, PRUint32 maxSize); + PRUint32 growBySize, PRUint32 maxSize, + nsIBufferObserver* observer); extern NS_COM nsresult NS_NewBufferInputStream(nsIBufferInputStream* *result, @@ -177,8 +222,11 @@ NS_NewBufferOutputStream(nsIBufferOutputStream* *result, nsIBuffer* buffer, PRBool blocking = PR_FALSE); extern NS_COM nsresult -NS_NewPipe2(nsIBufferInputStream* *inStrResult, +NS_NewPipe(nsIBufferInputStream* *inStrResult, nsIBufferOutputStream* *outStrResult, - PRUint32 growBySize, PRUint32 maxSize); + PRUint32 growBySize, PRUint32 maxSize, + PRBool blocking, nsIBufferObserver* observer); + +//////////////////////////////////////////////////////////////////////////////// #endif // nsIBuffer_h___ diff --git a/mozilla/xpcom/io/nsPipe.cpp b/mozilla/xpcom/io/nsPipe.cpp index 0972735fea1..d71311fd29d 100644 --- a/mozilla/xpcom/io/nsPipe.cpp +++ b/mozilla/xpcom/io/nsPipe.cpp @@ -168,16 +168,18 @@ nsBufferInputStream::Read(char* aBuf, PRUint32 aCount, PRUint32 *aReadCount) while (aCount > 0) { PRUint32 amt; rv = mBuffer->Read(aBuf, aCount, &amt); - if (rv == NS_BASE_STREAM_EOF) - return *aReadCount > 0 ? NS_OK : rv; - if (NS_FAILED(rv)) return rv; + if (rv == NS_BASE_STREAM_EOF) { + rv = (*aReadCount == 0) ? rv : NS_OK; + break; + } + if (NS_FAILED(rv)) break; if (amt == 0) { rv = Fill(); - if (NS_FAILED(rv)) return rv; - if (!mBlocking) { - // Only return WOULD_BLOCK if no data was read... - return *aReadCount > 0 ? NS_OK : rv; + if (rv == NS_BASE_STREAM_WOULD_BLOCK) { + rv = (*aReadCount == 0) ? rv : NS_OK; + break; } + if (NS_FAILED(rv)) break; } else { *aReadCount += amt; @@ -185,6 +187,11 @@ nsBufferInputStream::Read(char* aBuf, PRUint32 aCount, PRUint32 *aReadCount) aCount -= amt; } } + if (rv == NS_BASE_STREAM_EOF) { + // all we're ever going to get -- so wake up anyone in Flush + nsAutoMonitor mon(mBuffer); + mon.Notify(); // wake up writer + } return rv; } @@ -200,21 +207,62 @@ nsBufferInputStream::GetBuffer(nsIBuffer* *result) } NS_IMETHODIMP -nsBufferInputStream::Fill(const char* buf, PRUint32 count, PRUint32 *result) +nsBufferInputStream::Fill(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount) { if (mBuffer == nsnull) return NS_BASE_STREAM_CLOSED; - return mBuffer->Write(buf, count, result); + nsresult rv = NS_OK; + *aWriteCount = 0; + + while (aCount > 0) { + PRUint32 amt; + rv = mBuffer->Write(aBuf, aCount, &amt); + if (rv == NS_BASE_STREAM_EOF) + return *aWriteCount > 0 ? NS_OK : rv; + if (NS_FAILED(rv)) return rv; + if (amt == 0) { + rv = Fill(); + if (rv == NS_BASE_STREAM_WOULD_BLOCK) + return *aWriteCount > 0 ? NS_OK : rv; + if (NS_FAILED(rv)) return rv; + } + else { + aBuf += amt; + aCount -= amt; + *aWriteCount += amt; + } + } + return rv; } NS_IMETHODIMP -nsBufferInputStream::FillFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *result) +nsBufferInputStream::FillFrom(nsIInputStream *fromStream, PRUint32 aCount, PRUint32 *aWriteCount) { if (mBuffer == nsnull) return NS_BASE_STREAM_CLOSED; - return mBuffer->WriteFrom(inStr, count, result); + nsresult rv = NS_OK; + *aWriteCount = 0; + + while (aCount > 0) { + PRUint32 amt; + rv = mBuffer->WriteFrom(fromStream, aCount, &amt); + if (rv == NS_BASE_STREAM_EOF) + return *aWriteCount > 0 ? NS_OK : rv; + if (NS_FAILED(rv)) return rv; + if (amt == 0) { + rv = Fill(); + if (rv == NS_BASE_STREAM_WOULD_BLOCK) + return *aWriteCount > 0 ? NS_OK : rv; + if (NS_FAILED(rv)) return rv; + } + else { + aCount -= amt; + *aWriteCount += amt; + } + } + return rv; } nsresult @@ -348,12 +396,18 @@ nsBufferOutputStream::Write(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteC while (aCount > 0) { PRUint32 amt; rv = mBuffer->Write(aBuf, aCount, &amt); - if (rv == NS_BASE_STREAM_EOF) - return *aWriteCount > 0 ? NS_OK : rv; - if (NS_FAILED(rv)) return rv; + if (rv == NS_BASE_STREAM_EOF) { + rv = (*aWriteCount == 0) ? rv : NS_OK; + break; + } + if (NS_FAILED(rv)) break; if (amt == 0) { rv = Flush(); - if (NS_FAILED(rv)) return rv; + if (rv == NS_BASE_STREAM_WOULD_BLOCK) { + rv = (*aWriteCount == 0) ? rv : NS_OK; + break; + } + if (NS_FAILED(rv)) break; } else { aBuf += amt; @@ -361,6 +415,11 @@ nsBufferOutputStream::Write(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteC *aWriteCount += amt; } } + if (rv == NS_BASE_STREAM_EOF) { + // all we're ever going to get -- so wake up anyone in Flush + nsAutoMonitor mon(mBuffer); + mon.Notify(); // wake up writer + } return rv; } @@ -377,18 +436,29 @@ nsBufferOutputStream::WriteFrom(nsIInputStream* fromStream, PRUint32 aCount, while (aCount > 0) { PRUint32 amt; rv = mBuffer->WriteFrom(fromStream, aCount, &amt); - if (rv == NS_BASE_STREAM_EOF) - return *aWriteCount > 0 ? NS_OK : rv; - if (NS_FAILED(rv)) return rv; + if (rv == NS_BASE_STREAM_EOF) { + rv = (*aWriteCount == 0) ? rv : NS_OK; + break; + } + if (NS_FAILED(rv)) break; if (amt == 0) { rv = Flush(); - if (NS_FAILED(rv)) return rv; + if (rv == NS_BASE_STREAM_WOULD_BLOCK) { + rv = (*aWriteCount == 0) ? rv : NS_OK; + break; + } + if (NS_FAILED(rv)) break; } else { aCount -= amt; *aWriteCount += amt; } } + if (rv == NS_BASE_STREAM_EOF) { + // all we're ever going to get -- so wake up anyone in Flush + nsAutoMonitor mon(mBuffer); + mon.Notify(); // wake up writer + } return rv; } @@ -406,10 +476,10 @@ nsBufferOutputStream::Flush(void) PRUint32 amt; char* buf; rv = mBuffer->GetWriteSegment(&buf, &amt); - if (rv == NS_BASE_STREAM_EOF) return rv; + // don't exit on EOF here -- we need to block until the data is consumed if (NS_SUCCEEDED(rv) && amt > 0) return NS_OK; - // else notify the reader and wait + // else notify the reader and wait rv = mon.Notify(); if (NS_FAILED(rv)) return rv; // interrupted rv = mon.Wait(); @@ -446,22 +516,23 @@ NS_NewBufferOutputStream(nsIBufferOutputStream* *result, //////////////////////////////////////////////////////////////////////////////// NS_COM nsresult -NS_NewPipe2(nsIBufferInputStream* *inStrResult, +NS_NewPipe(nsIBufferInputStream* *inStrResult, nsIBufferOutputStream* *outStrResult, - PRUint32 growBySize, PRUint32 maxSize) + PRUint32 growBySize, PRUint32 maxSize, + PRBool blocking, nsIBufferObserver* observer) { nsresult rv; nsIBufferInputStream* inStr = nsnull; nsIBufferOutputStream* outStr = nsnull; nsIBuffer* buf = nsnull; - rv = NS_NewPageBuffer(&buf, growBySize, maxSize); + rv = NS_NewPageBuffer(&buf, growBySize, maxSize, observer); if (NS_FAILED(rv)) goto error; - rv = NS_NewBufferInputStream(&inStr, buf, PR_TRUE); + rv = NS_NewBufferInputStream(&inStr, buf, blocking); if (NS_FAILED(rv)) goto error; - rv = NS_NewBufferOutputStream(&outStr, buf, PR_TRUE); + rv = NS_NewBufferOutputStream(&outStr, buf, blocking); if (NS_FAILED(rv)) goto error; NS_RELEASE(buf); diff --git a/mozilla/xpcom/threads/nsThread.cpp b/mozilla/xpcom/threads/nsThread.cpp index 999c6a99693..b306b74ad16 100644 --- a/mozilla/xpcom/threads/nsThread.cpp +++ b/mozilla/xpcom/threads/nsThread.cpp @@ -18,17 +18,45 @@ #include "nsThread.h" #include "prmem.h" -//#include +#include "prlog.h" PRUintn nsThread::kIThreadSelfIndex = 0; static nsIThread *gMainThread = 0; +#if defined(PR_LOGGING) +// +// Log module for nsIThread logging... +// +// To enable logging (see prlog.h for full details): +// +// set NSPR_LOG_MODULES=nsIThread:5 +// set NSPR_LOG_FILE=nspr.log +// +// this enables PR_LOG_DEBUG level information and places all output in +// the file nspr.log +// +// gSocketLog is defined in nsSocketTransport.cpp +// +PRLogModuleInfo* nsIThreadLog = nsnull; + +#endif /* PR_LOGGING */ + //////////////////////////////////////////////////////////////////////////////// nsThread::nsThread() : mThread(nsnull), mRunnable(nsnull), mDead(PR_FALSE) { NS_INIT_REFCNT(); + +#if defined(PR_LOGGING) + // + // Initialize the global PRLogModule for nsIThread logging + // if necessary... + // + if (nsIThreadLog == nsnull) { + nsIThreadLog = PR_NewLogModule("nsIThread"); + } +#endif /* PR_LOGGING */ } nsresult @@ -46,7 +74,8 @@ nsThread::Init(nsIRunnable* runnable, NS_ADDREF_THIS(); // released in nsThread::Join mThread = PR_CreateThread(PR_USER_THREAD, Main, this, priority, scope, state, stackSize); -// printf("%x %x (%d) create\n", this, mThread, mRefCnt); + PR_LOG(nsIThreadLog, PR_LOG_DEBUG, + ("nsIThread %p created\n", this)); if (mThread == nsnull) return NS_ERROR_OUT_OF_MEMORY; return NS_OK; @@ -54,7 +83,8 @@ nsThread::Init(nsIRunnable* runnable, nsThread::~nsThread() { -// printf("%x %x (%d) destroy\n", this, mThread, mRefCnt); + PR_LOG(nsIThreadLog, PR_LOG_DEBUG, + ("nsIThread %p destroyed\n", this)); NS_IF_RELEASE(mRunnable); } @@ -67,13 +97,15 @@ nsThread::Main(void* arg) rv = self->RegisterThreadSelf(); NS_ASSERTION(rv == NS_OK, "failed to set thread self"); -// printf("%x %x (%d) start run\n", self, self->mThread, self->mRefCnt); + PR_LOG(nsIThreadLog, PR_LOG_DEBUG, + ("nsIThread %p start run %p\n", self, self->mRunnable)); rv = self->mRunnable->Run(); NS_ASSERTION(NS_SUCCEEDED(rv), "runnable failed"); PRThreadState state; rv = self->GetState(&state); -// printf("%x %x (%d) end run\n", self, self->mThread, self->mRefCnt); + PR_LOG(nsIThreadLog, PR_LOG_DEBUG, + ("nsIThread %p end run %p\n", self, self->mRunnable)); } void @@ -82,7 +114,8 @@ nsThread::Exit(void* arg) nsThread* self = (nsThread*)arg; nsresult rv = NS_OK; self->mDead = PR_TRUE; -// printf("%x %x (%d) exit\n", self, self->mThread, self->mRefCnt - 1); + PR_LOG(nsIThreadLog, PR_LOG_DEBUG, + ("nsIThread %p exited\n", self)); NS_RELEASE(self); } @@ -94,11 +127,13 @@ nsThread::Join() // don't check for mDead here because nspr calls Exit (cleaning up // thread-local storage) before they let us join with the thread -// printf("%x %x (%d) start join\n", this, mThread, mRefCnt); + PR_LOG(nsIThreadLog, PR_LOG_DEBUG, + ("nsIThread %p start join\n", this)); PRStatus status = PR_JoinThread(mThread); // XXX can't use NS_RELEASE here because the macro wants to set // this to null (bad c++) -// printf("%x %x (%d) end join\n", this, mThread, mRefCnt); + PR_LOG(nsIThreadLog, PR_LOG_DEBUG, + ("nsIThread %p end join\n", this)); if (status == PR_SUCCESS) { this->Release(); // most likely the final release of this thread return NS_OK; @@ -368,7 +403,12 @@ nsThreadPool::GetRequest() rv = NS_ERROR_FAILURE; break; } -// printf("thread %x waiting\n", PR_CurrentThread()); +#if defined(PR_LOGGING) + nsIThread* th; + nsIThread::GetCurrent(&th); +#endif + PR_LOG(nsIThreadLog, PR_LOG_DEBUG, + ("nsIThreadPool thread %p waiting\n", th)); PRStatus status = PR_Wait(mRequestMonitor, PR_INTERVAL_NO_TIMEOUT); if (status != PR_SUCCESS || mShuttingDown) { rv = NS_ERROR_FAILURE; @@ -495,17 +535,23 @@ nsThreadPoolRunnable::Run() PR_CNotify(mPool); PR_CExitMonitor(mPool); +#if defined(PR_LOGGING) + nsIThread* th; + nsIThread::GetCurrent(&th); +#endif while ((request = mPool->GetRequest()) != nsnull) { -// printf("running %x, thread %x\n", this, PR_CurrentThread()); + PR_LOG(nsIThreadLog, PR_LOG_DEBUG, + ("nsIThreadPool thread %p running %p\n", th, this)); rv = request->Run(); NS_ASSERTION(NS_SUCCEEDED(rv), "runnable failed"); - // let the thread pool know we're finished a run + // let the thread pool know we've finished a run PR_CEnterMonitor(mPool); PR_CNotify(mPool); PR_CExitMonitor(mPool); } -// printf("quitting %x, thread %x\n", this, PR_CurrentThread()); + PR_LOG(nsIThreadLog, PR_LOG_DEBUG, + ("nsIThreadPool thread %p quitting %x\n", th, this)); return rv; }