From ec8aed1d7779a9deb136f59b86bf8a07972be18c Mon Sep 17 00:00:00 2001 From: "warren%netscape.com" Date: Tue, 13 Apr 1999 18:17:29 +0000 Subject: [PATCH] Added NS_NewPipe and cleaned up ByteBufferInputStreams. git-svn-id: svn://10.0.0.236/trunk@27339 18797224-902f-48f8-a5cc-f745e15eee43 --- .../base/public/nsIByteBufferInputStream.h | 42 +- mozilla/base/src/nsByteBufferInputStream.cpp | 455 +++++++++++++++--- mozilla/base/src/nsIBaseStream.h | 2 + mozilla/base/tests/TestPipes.cpp | 100 ++++ mozilla/base/tests/makefile.win | 10 +- mozilla/xpcom/io/nsByteBufferInputStream.cpp | 455 +++++++++++++++--- mozilla/xpcom/io/nsIBaseStream.h | 2 + mozilla/xpcom/io/nsIByteBufferInputStream.h | 42 +- mozilla/xpcom/tests/TestPipes.cpp | 100 ++++ 9 files changed, 1048 insertions(+), 160 deletions(-) create mode 100644 mozilla/base/tests/TestPipes.cpp create mode 100644 mozilla/xpcom/tests/TestPipes.cpp diff --git a/mozilla/base/public/nsIByteBufferInputStream.h b/mozilla/base/public/nsIByteBufferInputStream.h index f0408528cfb..15d0c4df79f 100644 --- a/mozilla/base/public/nsIByteBufferInputStream.h +++ b/mozilla/base/public/nsIByteBufferInputStream.h @@ -15,10 +15,12 @@ * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ + #ifndef nsIByteBufferInputStream_h___ #define nsIByteBufferInputStream_h___ #include "nsIInputStream.h" +#include "nsIOutputStream.h" #define NS_IBYTEBUFFERINPUTSTREAM_IID \ { /* 40767100-eb9c-11d2-931c-00104ba0fd40 */ \ @@ -30,14 +32,46 @@ class nsIByteBufferInputStream : public nsIInputStream { public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IBYTEBUFFERINPUTSTREAM_IID); - static const nsIID& GetIID() { static nsIID iid = NS_IBYTEBUFFERINPUTSTREAM_IID; return iid; } + NS_IMETHOD Fill(nsIInputStream* stream, PRUint32 *aWriteCount) = 0; + + NS_IMETHOD Fill(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount) = 0; - NS_IMETHOD Fill(nsIInputStream* stream, PRUint32 *filledAmount) = 0; }; -// Makes an byte buffer input stream: +//////////////////////////////////////////////////////////////////////////////// + +// XXX regenerate: +#define NS_IBYTEBUFFEROUTPUTSTREAM_IID \ +{ /* 924df6d0-f192-11d2-9322-000000000000 */ \ + 0x924df6d0, \ + 0xf192, \ + 0x11d2, \ + {0x93, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} \ +} + +class nsIByteBufferOutputStream : public nsIOutputStream { +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IBYTEBUFFEROUTPUTSTREAM_IID); + + NS_IMETHOD Write(nsIInputStream* fromStream, PRUint32 *aWriteCount) = 0; + +}; + +//////////////////////////////////////////////////////////////////////////////// + extern NS_BASE nsresult -NS_NewByteBufferInputStream(PRUint32 size, nsIByteBufferInputStream* *result); +NS_NewByteBufferInputStream(nsIByteBufferInputStream* *result, + PRBool blocking = PR_FALSE, + PRUint32 size = 4096); + +extern NS_BASE nsresult +NS_NewPipe(nsIInputStream* *inStrResult, + nsIOutputStream* *outStrResult, + PRBool blocking = PR_TRUE, + PRUint32 bufferSize = 4096); + +//////////////////////////////////////////////////////////////////////////////// #endif /* nsByteBufferInputStream_h___ */ diff --git a/mozilla/base/src/nsByteBufferInputStream.cpp b/mozilla/base/src/nsByteBufferInputStream.cpp index d699a9735eb..ff8f45b9fb2 100644 --- a/mozilla/base/src/nsByteBufferInputStream.cpp +++ b/mozilla/base/src/nsByteBufferInputStream.cpp @@ -18,6 +18,35 @@ #include "nsIByteBufferInputStream.h" #include "nsCRT.h" +#include "prcmon.h" + +class nsByteBufferInputStream; + +//////////////////////////////////////////////////////////////////////////////// + +class nsByteBufferOutputStream : public nsIByteBufferOutputStream +{ +public: + NS_DECL_ISUPPORTS + + // nsIBaseStream methods: + NS_IMETHOD Close(void); + + // nsIOutputStream methods: + NS_IMETHOD Write(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount); + + // nsIByteBufferOutputStream methods: + NS_IMETHOD Write(nsIInputStream* fromStream, PRUint32 *aWriteCount); + + // nsByteBufferOutputStream methods: + nsByteBufferOutputStream(nsByteBufferInputStream* in); + virtual ~nsByteBufferOutputStream(); + +protected: + nsByteBufferInputStream* mInputStream; +}; + +//////////////////////////////////////////////////////////////////////////////// class nsByteBufferInputStream : public nsIByteBufferInputStream { @@ -32,13 +61,37 @@ public: NS_IMETHOD Read(char* aBuf, PRUint32 aCount, PRUint32 *aReadCount); // nsIByteBufferInputStream methods: - NS_IMETHOD Fill(nsIInputStream* stream, PRUint32 *filledAmount); - + NS_IMETHOD Fill(nsIInputStream* stream, PRUint32 *aWriteCount); + NS_IMETHOD Fill(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount); + // nsByteBufferInputStream methods: - nsByteBufferInputStream(); + nsByteBufferInputStream(PRBool blocking, PRUint32 size); virtual ~nsByteBufferInputStream(); - nsresult Init(PRUint32 size); + friend class nsByteBufferOutputStream; + + nsresult Init(void); + void SetEOF(void); + + PRBool AtEOF() { return mEOF && (mReadCursor == mWriteCursor) && !mFull; } + + PRUint32 ReadableAmount() { + if (mReadCursor < mWriteCursor) + return mWriteCursor - mReadCursor; + else if (mReadCursor == mWriteCursor && !mFull) + return 0; + else + return (mLength - mReadCursor) + mWriteCursor; + } + + PRUint32 WritableAmount() { + if (mWriteCursor < mReadCursor) + return mWriteCursor - mReadCursor; + else if (mReadCursor == mWriteCursor && mFull) + return 0; + else + return (mLength - mWriteCursor) + mReadCursor; + } void ReadChunk(char* toBuf, PRUint32 max, PRUint32 end, PRUint32 *totalRef) @@ -48,15 +101,19 @@ public: PRInt32 amt = PR_MIN(max, diff); if (amt > 0) { nsCRT::memcpy(toBuf, &mBuffer[mReadCursor], amt); +#ifdef NS_DEBUG + nsCRT::memset(&mBuffer[mReadCursor], 0xDD, amt); +#endif mReadCursor += amt; *totalRef += amt; } } - nsresult WriteChunk(nsIInputStream* in, PRUint32 end, PRUint32 *totalRef) + nsresult WriteChunk(nsIInputStream* in, + PRUint32 end, PRUint32 *totalRef) { NS_ASSERTION(mWriteCursor <= end, "bad range"); - PRInt32 amt = end - mWriteCursor; + PRUint32 amt = end - mWriteCursor; if (amt > 0) { PRUint32 readAmt; nsresult rv = in->Read(&mBuffer[mWriteCursor], amt, &readAmt); @@ -68,34 +125,100 @@ public: } protected: - char* mBuffer; - PRUint32 mLength; - PRUint32 mReadCursor; - PRUint32 mWriteCursor; - PRBool mFull; + char* mBuffer; + PRUint32 mLength; + PRUint32 mReadCursor; + PRUint32 mWriteCursor; + PRBool mFull; + PRBool mClosed; + PRBool mEOF; + PRBool mBlocking; }; //////////////////////////////////////////////////////////////////////////////// -nsByteBufferInputStream::nsByteBufferInputStream() - : mBuffer(nsnull), mLength(0), mReadCursor(0), mWriteCursor(0), mFull(PR_FALSE) +class nsDummyBufferStream : public nsIInputStream +{ +public: + NS_DECL_ISUPPORTS + + // nsIBaseStream methods: + NS_IMETHOD Close(void) { + NS_NOTREACHED("nsDummyBufferStream::Close"); + return NS_ERROR_FAILURE; + } + + // nsIInputStream methods: + NS_IMETHOD GetLength(PRUint32 *aLength) { + *aLength = mLength; + return NS_OK; + } + NS_IMETHOD Read(char* aBuf, PRUint32 aCount, PRUint32 *aReadCount) { + PRUint32 amt = PR_MIN(aCount, mLength); + if (amt > 0) { + nsCRT::memcpy(aBuf, mBuffer, amt); + mBuffer += amt; + mLength -= amt; + } + *aReadCount = amt; + return NS_OK; + } + + // nsDummyBufferStream methods: + nsDummyBufferStream(const char* buffer, PRUint32 length) + : mBuffer(buffer), mLength(length) {} + ~nsDummyBufferStream() {} + +protected: + const char* mBuffer; + PRUint32 mLength; +}; + +NS_IMETHODIMP +nsDummyBufferStream::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + NS_NOTREACHED("nsDummyBufferStream::QueryInterface"); + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP_(nsrefcnt) +nsDummyBufferStream::AddRef(void) +{ + NS_NOTREACHED("nsDummyBufferStream::AddRef"); + return 1; +} + +NS_IMETHODIMP_(nsrefcnt) +nsDummyBufferStream::Release(void) +{ + NS_NOTREACHED("nsDummyBufferStream::Release"); + return 1; +} + +//////////////////////////////////////////////////////////////////////////////// +// nsByteBufferInputStream methods: +//////////////////////////////////////////////////////////////////////////////// + +nsByteBufferInputStream::nsByteBufferInputStream(PRBool blocking, PRUint32 size) + : mBuffer(nsnull), mLength(size), mReadCursor(0), mWriteCursor(0), + mFull(PR_FALSE), mClosed(PR_FALSE), mEOF(PR_FALSE), mBlocking(blocking) { NS_INIT_REFCNT(); } nsresult -nsByteBufferInputStream::Init(PRUint32 size) +nsByteBufferInputStream::Init(void) { - mBuffer = new char[size]; + mBuffer = new char[mLength]; if (mBuffer == nsnull) return NS_ERROR_OUT_OF_MEMORY; - mLength = size; return NS_OK; } nsByteBufferInputStream::~nsByteBufferInputStream() { - Close(); + (void)Close(); + if (mBuffer) delete mBuffer; } NS_IMPL_ADDREF(nsByteBufferInputStream); @@ -108,7 +231,8 @@ nsByteBufferInputStream::QueryInterface(REFNSIID aIID, void** aInstancePtr) return NS_ERROR_NULL_POINTER; if (aIID.Equals(nsIByteBufferInputStream::GetIID()) || aIID.Equals(nsIInputStream::GetIID()) || - aIID.Equals(nsIBaseStream::GetIID())) { + aIID.Equals(nsIBaseStream::GetIID()) || + aIID.Equals(nsISupports::GetIID())) { *aInstancePtr = this; NS_ADDREF_THIS(); return NS_OK; @@ -119,105 +243,288 @@ nsByteBufferInputStream::QueryInterface(REFNSIID aIID, void** aInstancePtr) NS_IMETHODIMP nsByteBufferInputStream::Close(void) { - if (mBuffer == nsnull) - return NS_BASE_STREAM_CLOSED; - - delete mBuffer; - mBuffer = nsnull; - mLength = 0; - mReadCursor = 0; - mWriteCursor = 0; + if (mBlocking) + PR_CEnterMonitor(this); + mClosed = PR_TRUE; + if (mBlocking) { + PR_CNotify(this); // wake up the writer + PR_CExitMonitor(this); + } return NS_OK; } NS_IMETHODIMP nsByteBufferInputStream::GetLength(PRUint32 *aLength) { - if (mBuffer == nsnull) + if (mClosed) return NS_BASE_STREAM_CLOSED; - if (mReadCursor < mWriteCursor) - *aLength = mWriteCursor - mReadCursor; - else - *aLength = (mLength - mReadCursor) + mWriteCursor; + if (mBlocking) + PR_CEnterMonitor(this); + *aLength = ReadableAmount(); + if (mBlocking) + PR_CExitMonitor(this); return NS_OK; } NS_IMETHODIMP nsByteBufferInputStream::Read(char* aBuf, PRUint32 aCount, PRUint32 *aReadCount) { - if (mBuffer == nsnull) + nsresult rv = NS_OK; + if (mClosed) return NS_BASE_STREAM_CLOSED; - // wrap-around buffer: - if (mReadCursor == mWriteCursor && !mFull) { + if (AtEOF()) return NS_BASE_STREAM_EOF; - } + if (mBlocking) + PR_CEnterMonitor(this); *aReadCount = 0; - if (mReadCursor >= mWriteCursor || mFull) { + + /*while (aCount > 0)*/ { // XXX should this block trying to fill the buffer, or return ASAP? + if (ReadableAmount() == 0) { + if (mBlocking) { + PRStatus status = PR_CWait(this, PR_INTERVAL_NO_TIMEOUT); + if (status != PR_SUCCESS) { + rv = NS_ERROR_FAILURE; + goto done; + } + } + if (mEOF) { + rv = NS_BASE_STREAM_EOF; + goto done; + } + else if (!mBlocking) { + rv = NS_BASE_STREAM_WOULD_BLOCK; + goto done; + } + } + + // wrap-around buffer: PRUint32 amt = 0; - ReadChunk(aBuf, aCount, mLength, &amt); - *aReadCount += amt; - if (mReadCursor == mLength) { - mReadCursor = 0; + if (mReadCursor >= mWriteCursor || mFull) { + ReadChunk(aBuf, aCount, mLength, &amt); + *aReadCount += amt; aBuf += amt; aCount -= amt; - ReadChunk(aBuf, aCount, mWriteCursor, aReadCount); - if (mReadCursor == mWriteCursor) - mFull = PR_FALSE; + if (mReadCursor == mLength) { + mReadCursor = 0; + amt = 0; + ReadChunk(aBuf, aCount, mWriteCursor, &amt); + *aReadCount += amt; + aBuf += amt; + aCount -= amt; + } } + else { + ReadChunk(aBuf, aCount, mWriteCursor, &amt); + *aReadCount += amt; + aBuf += amt; + aCount -= amt; + } + if (*aReadCount) + mFull = PR_FALSE; + + if (mBlocking) + PR_CNotify(this); // tell the writer there's space } - else { - ReadChunk(aBuf, aCount, mWriteCursor, aReadCount); + done: + if (mBlocking) + PR_CExitMonitor(this); + return rv; +} + +NS_IMETHODIMP +nsByteBufferInputStream::Fill(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount) +{ + nsDummyBufferStream in(aBuf, aCount); + return Fill(&in, aWriteCount); +} + +NS_IMETHODIMP +nsByteBufferInputStream::Fill(nsIInputStream* stream, PRUint32 *aWriteCount) +{ + nsresult rv = NS_OK; + + if (mClosed || mEOF) + return NS_BASE_STREAM_CLOSED; + + *aWriteCount = 0; + PRUint32 aCount; + rv = stream->GetLength(&aCount); + if (NS_FAILED(rv)) return rv; + + if (mBlocking) + PR_CEnterMonitor(this); + + while (aCount > 0) { + if (WritableAmount() == 0) { + if (mBlocking) { + PRStatus status = PR_CWait(this, PR_INTERVAL_NO_TIMEOUT); + if (status != PR_SUCCESS) { + rv = NS_ERROR_FAILURE; + goto done; + } + } + if (mClosed) { + rv = NS_BASE_STREAM_CLOSED; + goto done; + } + else if (!mBlocking) { + rv = NS_BASE_STREAM_WOULD_BLOCK; + goto done; + } + } + + // wrap-around buffer: + PRUint32 amt = 0; + if (mReadCursor <= mWriteCursor && !mFull) { + rv = WriteChunk(stream, mLength, &amt); + if (NS_FAILED(rv)) goto done; + *aWriteCount += amt; + aCount -= amt; + if (mWriteCursor == mLength) { + mWriteCursor = 0; + amt = 0; + rv = WriteChunk(stream, mReadCursor, &amt); + if (NS_FAILED(rv)) goto done; + *aWriteCount += amt; + aCount -= amt; + } + } + else { + rv = WriteChunk(stream, mReadCursor, &amt); + if (NS_FAILED(rv)) goto done; + *aWriteCount += amt; + aCount -= amt; + } + if (mWriteCursor == mReadCursor) + mFull = PR_TRUE; + + if (mBlocking) + PR_CNotify(this); // tell the reader there's more } + done: + if (mBlocking) + PR_CExitMonitor(this); + return rv; +} + +void +nsByteBufferInputStream::SetEOF() +{ + if (mBlocking) + PR_CEnterMonitor(this); + mEOF = PR_TRUE; + if (mBlocking) { + PR_CNotify(this); // wake up the reader + PR_CExitMonitor(this); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// nsByteBufferOutputStream methods: +//////////////////////////////////////////////////////////////////////////////// + +nsByteBufferOutputStream::nsByteBufferOutputStream(nsByteBufferInputStream* in) + : mInputStream(in) +{ + NS_INIT_REFCNT(); + NS_ADDREF(mInputStream); +} + +nsByteBufferOutputStream::~nsByteBufferOutputStream() +{ + (void)Close(); + NS_IF_RELEASE(mInputStream); +} + +NS_IMPL_ADDREF(nsByteBufferOutputStream); +NS_IMPL_RELEASE(nsByteBufferOutputStream); + +NS_IMETHODIMP +nsByteBufferOutputStream::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if (aInstancePtr == nsnull) + return NS_ERROR_NULL_POINTER; + if (aIID.Equals(nsIByteBufferOutputStream::GetIID()) || + aIID.Equals(nsIOutputStream::GetIID()) || + aIID.Equals(nsIBaseStream::GetIID()) || + aIID.Equals(nsISupports::GetIID())) { + *aInstancePtr = this; + NS_ADDREF_THIS(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +NS_IMETHODIMP +nsByteBufferOutputStream::Close(void) +{ + mInputStream->SetEOF(); return NS_OK; } NS_IMETHODIMP -nsByteBufferInputStream::Fill(nsIInputStream* stream, PRUint32 *filledAmount) +nsByteBufferOutputStream::Write(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount) { - if (mBuffer == nsnull) - return NS_BASE_STREAM_CLOSED; + return mInputStream->Fill(aBuf, aCount, aWriteCount); +} +NS_IMETHODIMP +nsByteBufferOutputStream::Write(nsIInputStream* fromStream, PRUint32 *aWriteCount) +{ + return mInputStream->Fill(fromStream, aWriteCount); +} + +//////////////////////////////////////////////////////////////////////////////// + +NS_BASE nsresult +NS_NewByteBufferInputStream(nsIByteBufferInputStream* *result, + PRBool blocking, PRUint32 size) +{ nsresult rv; + nsByteBufferInputStream* inStr = nsnull; - // wrap-around buffer: - *filledAmount = 0; - if (mReadCursor <= mWriteCursor && !mFull) { - rv = WriteChunk(stream, mLength, filledAmount); - if (NS_FAILED(rv)) return rv; - if (mWriteCursor == mLength) { - mWriteCursor = 0; - rv = WriteChunk(stream, mReadCursor, filledAmount); - if (NS_FAILED(rv)) return rv; - if (mWriteCursor == mReadCursor) - mFull = PR_TRUE; - } - } - else { - rv = WriteChunk(stream, mReadCursor, filledAmount); - if (NS_FAILED(rv)) return rv; + inStr = new nsByteBufferInputStream(blocking, size); + if (inStr == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + rv = inStr->Init(); + if (NS_FAILED(rv)) { + delete inStr; + return rv; } + NS_ADDREF(inStr); + *result = inStr; return NS_OK; } //////////////////////////////////////////////////////////////////////////////// NS_BASE nsresult -NS_NewByteBufferInputStream(PRUint32 size, nsIByteBufferInputStream* *result) +NS_NewPipe(nsIInputStream* *inStrResult, + nsIOutputStream* *outStrResult, + PRBool blocking, PRUint32 size) { - nsByteBufferInputStream* str = - new nsByteBufferInputStream(); - if (str == nsnull) + nsresult rv; + nsIByteBufferInputStream* in; + nsByteBufferInputStream* inStr; + nsByteBufferOutputStream* outStr; + + rv = NS_NewByteBufferInputStream(&in, blocking, size); + if (NS_FAILED(rv)) return rv; + // this cast is safe, because we know how NS_NewByteBufferInputStream works: + inStr = NS_STATIC_CAST(nsByteBufferInputStream*, in); + + outStr = new nsByteBufferOutputStream(inStr); + if (outStr == nsnull) { + NS_RELEASE(inStr); return NS_ERROR_OUT_OF_MEMORY; - nsresult rv = str->Init(size); - if (NS_FAILED(rv)) { - delete str; - return rv; } - NS_ADDREF(str); - *result = str; + NS_ADDREF(outStr); + + *inStrResult = inStr; + *outStrResult = outStr; return NS_OK; } diff --git a/mozilla/base/src/nsIBaseStream.h b/mozilla/base/src/nsIBaseStream.h index ffef4d25c15..bf2f734f0ec 100644 --- a/mozilla/base/src/nsIBaseStream.h +++ b/mozilla/base/src/nsIBaseStream.h @@ -52,6 +52,8 @@ public: #define NS_BASE_STREAM_NO_CONVERTER NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 5) /// For unichar streams #define NS_BASE_STREAM_BAD_CONVERSION NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 6) + +#define NS_BASE_STREAM_WOULD_BLOCK NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_BASE, 7) //@} diff --git a/mozilla/base/tests/TestPipes.cpp b/mozilla/base/tests/TestPipes.cpp new file mode 100644 index 00000000000..064297c7097 --- /dev/null +++ b/mozilla/base/tests/TestPipes.cpp @@ -0,0 +1,100 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "nsIThread.h" +#include "nsIByteBufferInputStream.h" +#include "prprf.h" +#include "plstr.h" +#include + +#define KEY 0xa7 +#define ITERATIONS 333 +char kTestPattern[] = "My hovercraft is full of eels.\n"; + +class nsReceiver : public nsIRunnable { +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD Run() { + nsresult rv; + char buf[101]; + PRUint32 count; + while (PR_TRUE) { + rv = mIn->Read(buf, 100, &count); + if (rv == NS_BASE_STREAM_EOF) { + printf("EOF count = %d\n", mCount); + return NS_OK; + } + if (NS_FAILED(rv)) { + printf("read failed\n"); + return rv; + } + + buf[count] = '\0'; + printf(buf); + + mCount += count; + } + return rv; + } + + nsReceiver(nsIInputStream* in) : mIn(in), mCount(0) { + NS_INIT_REFCNT(); + NS_ADDREF(in); + } + + virtual ~nsReceiver() { + NS_RELEASE(mIn); + } + +protected: + nsIInputStream* mIn; + PRUint32 mCount; +}; + +NS_IMPL_ISUPPORTS(nsReceiver, nsIRunnable::GetIID()); + +int +main() +{ + nsresult rv; + nsIInputStream* in; + nsIOutputStream* out; + + rv = NS_NewPipe(&in, &out, PR_TRUE, 40); + if (NS_FAILED(rv)) return -1; + + nsIThread* receiver; + rv = NS_NewThread(&receiver, new nsReceiver(in)); + NS_RELEASE(in); + + for (PRUint32 i = 0; i < ITERATIONS; i++) { + PRUint32 writeCount; + char* buf = PR_smprintf("%d %s", i, kTestPattern); + rv = out->Write(buf, PL_strlen(buf), &writeCount); + PR_smprintf_free(buf); + NS_ASSERTION(NS_SUCCEEDED(rv), "write failed"); + } + rv = out->Close(); + NS_ASSERTION(NS_SUCCEEDED(rv), "close failed"); + + receiver->Join(); + NS_RELEASE(receiver); + + return 0; +} diff --git a/mozilla/base/tests/makefile.win b/mozilla/base/tests/makefile.win index 4c7dfd7c5d0..2bc412985bc 100644 --- a/mozilla/base/tests/makefile.win +++ b/mozilla/base/tests/makefile.win @@ -27,6 +27,7 @@ PROG5 = .\$(OBJDIR)\PropertiesTest.exe PROG6 = .\$(OBJDIR)\TestAutoLock.exe PROG7 = .\$(OBJDIR)\TestThreads.exe PROG8 = .\$(OBJDIR)\TestObserverService.exe +PROG9 = .\$(OBJDIR)\TestPipes.exe RESFILE = timer.res PROGRAMS = $(PROG0) $(PROG1) \ !ifdef MODULAR_NETLIB @@ -37,7 +38,8 @@ PROGRAMS = $(PROG0) $(PROG1) \ $(PROG4) \ $(PROG6) \ $(PROG7) \ - $(PROG8) \ + $(PROG8) \ + $(PROG9) \ $(NULL) LINCS=-I..\src -I$(PUBLIC)\xpcom -I$(PUBLIC)\netlib -I$(PUBLIC)\raptor @@ -69,7 +71,8 @@ install:: $(PROGRAMS) $(MAKE_INSTALL) $(PROG4) $(DIST)\bin $(MAKE_INSTALL) $(PROG6) $(DIST)\bin $(MAKE_INSTALL) $(PROG7) $(DIST)\bin - $(MAKE_INSTALL) $(PROG8) $(DIST)\bin + $(MAKE_INSTALL) $(PROG8) $(DIST)\bin + $(MAKE_INSTALL) $(PROG9) $(DIST)\bin clobber:: rm -f $(DIST)\bin\TimerTest.exe @@ -120,5 +123,4 @@ $(PROG7): $(OBJDIR) TestThreads.cpp $(PROG8): $(OBJDIR) TestObserverService.cpp - - +$(PROG9): $(OBJDIR) TestPipes.cpp diff --git a/mozilla/xpcom/io/nsByteBufferInputStream.cpp b/mozilla/xpcom/io/nsByteBufferInputStream.cpp index d699a9735eb..ff8f45b9fb2 100644 --- a/mozilla/xpcom/io/nsByteBufferInputStream.cpp +++ b/mozilla/xpcom/io/nsByteBufferInputStream.cpp @@ -18,6 +18,35 @@ #include "nsIByteBufferInputStream.h" #include "nsCRT.h" +#include "prcmon.h" + +class nsByteBufferInputStream; + +//////////////////////////////////////////////////////////////////////////////// + +class nsByteBufferOutputStream : public nsIByteBufferOutputStream +{ +public: + NS_DECL_ISUPPORTS + + // nsIBaseStream methods: + NS_IMETHOD Close(void); + + // nsIOutputStream methods: + NS_IMETHOD Write(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount); + + // nsIByteBufferOutputStream methods: + NS_IMETHOD Write(nsIInputStream* fromStream, PRUint32 *aWriteCount); + + // nsByteBufferOutputStream methods: + nsByteBufferOutputStream(nsByteBufferInputStream* in); + virtual ~nsByteBufferOutputStream(); + +protected: + nsByteBufferInputStream* mInputStream; +}; + +//////////////////////////////////////////////////////////////////////////////// class nsByteBufferInputStream : public nsIByteBufferInputStream { @@ -32,13 +61,37 @@ public: NS_IMETHOD Read(char* aBuf, PRUint32 aCount, PRUint32 *aReadCount); // nsIByteBufferInputStream methods: - NS_IMETHOD Fill(nsIInputStream* stream, PRUint32 *filledAmount); - + NS_IMETHOD Fill(nsIInputStream* stream, PRUint32 *aWriteCount); + NS_IMETHOD Fill(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount); + // nsByteBufferInputStream methods: - nsByteBufferInputStream(); + nsByteBufferInputStream(PRBool blocking, PRUint32 size); virtual ~nsByteBufferInputStream(); - nsresult Init(PRUint32 size); + friend class nsByteBufferOutputStream; + + nsresult Init(void); + void SetEOF(void); + + PRBool AtEOF() { return mEOF && (mReadCursor == mWriteCursor) && !mFull; } + + PRUint32 ReadableAmount() { + if (mReadCursor < mWriteCursor) + return mWriteCursor - mReadCursor; + else if (mReadCursor == mWriteCursor && !mFull) + return 0; + else + return (mLength - mReadCursor) + mWriteCursor; + } + + PRUint32 WritableAmount() { + if (mWriteCursor < mReadCursor) + return mWriteCursor - mReadCursor; + else if (mReadCursor == mWriteCursor && mFull) + return 0; + else + return (mLength - mWriteCursor) + mReadCursor; + } void ReadChunk(char* toBuf, PRUint32 max, PRUint32 end, PRUint32 *totalRef) @@ -48,15 +101,19 @@ public: PRInt32 amt = PR_MIN(max, diff); if (amt > 0) { nsCRT::memcpy(toBuf, &mBuffer[mReadCursor], amt); +#ifdef NS_DEBUG + nsCRT::memset(&mBuffer[mReadCursor], 0xDD, amt); +#endif mReadCursor += amt; *totalRef += amt; } } - nsresult WriteChunk(nsIInputStream* in, PRUint32 end, PRUint32 *totalRef) + nsresult WriteChunk(nsIInputStream* in, + PRUint32 end, PRUint32 *totalRef) { NS_ASSERTION(mWriteCursor <= end, "bad range"); - PRInt32 amt = end - mWriteCursor; + PRUint32 amt = end - mWriteCursor; if (amt > 0) { PRUint32 readAmt; nsresult rv = in->Read(&mBuffer[mWriteCursor], amt, &readAmt); @@ -68,34 +125,100 @@ public: } protected: - char* mBuffer; - PRUint32 mLength; - PRUint32 mReadCursor; - PRUint32 mWriteCursor; - PRBool mFull; + char* mBuffer; + PRUint32 mLength; + PRUint32 mReadCursor; + PRUint32 mWriteCursor; + PRBool mFull; + PRBool mClosed; + PRBool mEOF; + PRBool mBlocking; }; //////////////////////////////////////////////////////////////////////////////// -nsByteBufferInputStream::nsByteBufferInputStream() - : mBuffer(nsnull), mLength(0), mReadCursor(0), mWriteCursor(0), mFull(PR_FALSE) +class nsDummyBufferStream : public nsIInputStream +{ +public: + NS_DECL_ISUPPORTS + + // nsIBaseStream methods: + NS_IMETHOD Close(void) { + NS_NOTREACHED("nsDummyBufferStream::Close"); + return NS_ERROR_FAILURE; + } + + // nsIInputStream methods: + NS_IMETHOD GetLength(PRUint32 *aLength) { + *aLength = mLength; + return NS_OK; + } + NS_IMETHOD Read(char* aBuf, PRUint32 aCount, PRUint32 *aReadCount) { + PRUint32 amt = PR_MIN(aCount, mLength); + if (amt > 0) { + nsCRT::memcpy(aBuf, mBuffer, amt); + mBuffer += amt; + mLength -= amt; + } + *aReadCount = amt; + return NS_OK; + } + + // nsDummyBufferStream methods: + nsDummyBufferStream(const char* buffer, PRUint32 length) + : mBuffer(buffer), mLength(length) {} + ~nsDummyBufferStream() {} + +protected: + const char* mBuffer; + PRUint32 mLength; +}; + +NS_IMETHODIMP +nsDummyBufferStream::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + NS_NOTREACHED("nsDummyBufferStream::QueryInterface"); + return NS_ERROR_FAILURE; +} + +NS_IMETHODIMP_(nsrefcnt) +nsDummyBufferStream::AddRef(void) +{ + NS_NOTREACHED("nsDummyBufferStream::AddRef"); + return 1; +} + +NS_IMETHODIMP_(nsrefcnt) +nsDummyBufferStream::Release(void) +{ + NS_NOTREACHED("nsDummyBufferStream::Release"); + return 1; +} + +//////////////////////////////////////////////////////////////////////////////// +// nsByteBufferInputStream methods: +//////////////////////////////////////////////////////////////////////////////// + +nsByteBufferInputStream::nsByteBufferInputStream(PRBool blocking, PRUint32 size) + : mBuffer(nsnull), mLength(size), mReadCursor(0), mWriteCursor(0), + mFull(PR_FALSE), mClosed(PR_FALSE), mEOF(PR_FALSE), mBlocking(blocking) { NS_INIT_REFCNT(); } nsresult -nsByteBufferInputStream::Init(PRUint32 size) +nsByteBufferInputStream::Init(void) { - mBuffer = new char[size]; + mBuffer = new char[mLength]; if (mBuffer == nsnull) return NS_ERROR_OUT_OF_MEMORY; - mLength = size; return NS_OK; } nsByteBufferInputStream::~nsByteBufferInputStream() { - Close(); + (void)Close(); + if (mBuffer) delete mBuffer; } NS_IMPL_ADDREF(nsByteBufferInputStream); @@ -108,7 +231,8 @@ nsByteBufferInputStream::QueryInterface(REFNSIID aIID, void** aInstancePtr) return NS_ERROR_NULL_POINTER; if (aIID.Equals(nsIByteBufferInputStream::GetIID()) || aIID.Equals(nsIInputStream::GetIID()) || - aIID.Equals(nsIBaseStream::GetIID())) { + aIID.Equals(nsIBaseStream::GetIID()) || + aIID.Equals(nsISupports::GetIID())) { *aInstancePtr = this; NS_ADDREF_THIS(); return NS_OK; @@ -119,105 +243,288 @@ nsByteBufferInputStream::QueryInterface(REFNSIID aIID, void** aInstancePtr) NS_IMETHODIMP nsByteBufferInputStream::Close(void) { - if (mBuffer == nsnull) - return NS_BASE_STREAM_CLOSED; - - delete mBuffer; - mBuffer = nsnull; - mLength = 0; - mReadCursor = 0; - mWriteCursor = 0; + if (mBlocking) + PR_CEnterMonitor(this); + mClosed = PR_TRUE; + if (mBlocking) { + PR_CNotify(this); // wake up the writer + PR_CExitMonitor(this); + } return NS_OK; } NS_IMETHODIMP nsByteBufferInputStream::GetLength(PRUint32 *aLength) { - if (mBuffer == nsnull) + if (mClosed) return NS_BASE_STREAM_CLOSED; - if (mReadCursor < mWriteCursor) - *aLength = mWriteCursor - mReadCursor; - else - *aLength = (mLength - mReadCursor) + mWriteCursor; + if (mBlocking) + PR_CEnterMonitor(this); + *aLength = ReadableAmount(); + if (mBlocking) + PR_CExitMonitor(this); return NS_OK; } NS_IMETHODIMP nsByteBufferInputStream::Read(char* aBuf, PRUint32 aCount, PRUint32 *aReadCount) { - if (mBuffer == nsnull) + nsresult rv = NS_OK; + if (mClosed) return NS_BASE_STREAM_CLOSED; - // wrap-around buffer: - if (mReadCursor == mWriteCursor && !mFull) { + if (AtEOF()) return NS_BASE_STREAM_EOF; - } + if (mBlocking) + PR_CEnterMonitor(this); *aReadCount = 0; - if (mReadCursor >= mWriteCursor || mFull) { + + /*while (aCount > 0)*/ { // XXX should this block trying to fill the buffer, or return ASAP? + if (ReadableAmount() == 0) { + if (mBlocking) { + PRStatus status = PR_CWait(this, PR_INTERVAL_NO_TIMEOUT); + if (status != PR_SUCCESS) { + rv = NS_ERROR_FAILURE; + goto done; + } + } + if (mEOF) { + rv = NS_BASE_STREAM_EOF; + goto done; + } + else if (!mBlocking) { + rv = NS_BASE_STREAM_WOULD_BLOCK; + goto done; + } + } + + // wrap-around buffer: PRUint32 amt = 0; - ReadChunk(aBuf, aCount, mLength, &amt); - *aReadCount += amt; - if (mReadCursor == mLength) { - mReadCursor = 0; + if (mReadCursor >= mWriteCursor || mFull) { + ReadChunk(aBuf, aCount, mLength, &amt); + *aReadCount += amt; aBuf += amt; aCount -= amt; - ReadChunk(aBuf, aCount, mWriteCursor, aReadCount); - if (mReadCursor == mWriteCursor) - mFull = PR_FALSE; + if (mReadCursor == mLength) { + mReadCursor = 0; + amt = 0; + ReadChunk(aBuf, aCount, mWriteCursor, &amt); + *aReadCount += amt; + aBuf += amt; + aCount -= amt; + } } + else { + ReadChunk(aBuf, aCount, mWriteCursor, &amt); + *aReadCount += amt; + aBuf += amt; + aCount -= amt; + } + if (*aReadCount) + mFull = PR_FALSE; + + if (mBlocking) + PR_CNotify(this); // tell the writer there's space } - else { - ReadChunk(aBuf, aCount, mWriteCursor, aReadCount); + done: + if (mBlocking) + PR_CExitMonitor(this); + return rv; +} + +NS_IMETHODIMP +nsByteBufferInputStream::Fill(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount) +{ + nsDummyBufferStream in(aBuf, aCount); + return Fill(&in, aWriteCount); +} + +NS_IMETHODIMP +nsByteBufferInputStream::Fill(nsIInputStream* stream, PRUint32 *aWriteCount) +{ + nsresult rv = NS_OK; + + if (mClosed || mEOF) + return NS_BASE_STREAM_CLOSED; + + *aWriteCount = 0; + PRUint32 aCount; + rv = stream->GetLength(&aCount); + if (NS_FAILED(rv)) return rv; + + if (mBlocking) + PR_CEnterMonitor(this); + + while (aCount > 0) { + if (WritableAmount() == 0) { + if (mBlocking) { + PRStatus status = PR_CWait(this, PR_INTERVAL_NO_TIMEOUT); + if (status != PR_SUCCESS) { + rv = NS_ERROR_FAILURE; + goto done; + } + } + if (mClosed) { + rv = NS_BASE_STREAM_CLOSED; + goto done; + } + else if (!mBlocking) { + rv = NS_BASE_STREAM_WOULD_BLOCK; + goto done; + } + } + + // wrap-around buffer: + PRUint32 amt = 0; + if (mReadCursor <= mWriteCursor && !mFull) { + rv = WriteChunk(stream, mLength, &amt); + if (NS_FAILED(rv)) goto done; + *aWriteCount += amt; + aCount -= amt; + if (mWriteCursor == mLength) { + mWriteCursor = 0; + amt = 0; + rv = WriteChunk(stream, mReadCursor, &amt); + if (NS_FAILED(rv)) goto done; + *aWriteCount += amt; + aCount -= amt; + } + } + else { + rv = WriteChunk(stream, mReadCursor, &amt); + if (NS_FAILED(rv)) goto done; + *aWriteCount += amt; + aCount -= amt; + } + if (mWriteCursor == mReadCursor) + mFull = PR_TRUE; + + if (mBlocking) + PR_CNotify(this); // tell the reader there's more } + done: + if (mBlocking) + PR_CExitMonitor(this); + return rv; +} + +void +nsByteBufferInputStream::SetEOF() +{ + if (mBlocking) + PR_CEnterMonitor(this); + mEOF = PR_TRUE; + if (mBlocking) { + PR_CNotify(this); // wake up the reader + PR_CExitMonitor(this); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// nsByteBufferOutputStream methods: +//////////////////////////////////////////////////////////////////////////////// + +nsByteBufferOutputStream::nsByteBufferOutputStream(nsByteBufferInputStream* in) + : mInputStream(in) +{ + NS_INIT_REFCNT(); + NS_ADDREF(mInputStream); +} + +nsByteBufferOutputStream::~nsByteBufferOutputStream() +{ + (void)Close(); + NS_IF_RELEASE(mInputStream); +} + +NS_IMPL_ADDREF(nsByteBufferOutputStream); +NS_IMPL_RELEASE(nsByteBufferOutputStream); + +NS_IMETHODIMP +nsByteBufferOutputStream::QueryInterface(REFNSIID aIID, void** aInstancePtr) +{ + if (aInstancePtr == nsnull) + return NS_ERROR_NULL_POINTER; + if (aIID.Equals(nsIByteBufferOutputStream::GetIID()) || + aIID.Equals(nsIOutputStream::GetIID()) || + aIID.Equals(nsIBaseStream::GetIID()) || + aIID.Equals(nsISupports::GetIID())) { + *aInstancePtr = this; + NS_ADDREF_THIS(); + return NS_OK; + } + return NS_NOINTERFACE; +} + +NS_IMETHODIMP +nsByteBufferOutputStream::Close(void) +{ + mInputStream->SetEOF(); return NS_OK; } NS_IMETHODIMP -nsByteBufferInputStream::Fill(nsIInputStream* stream, PRUint32 *filledAmount) +nsByteBufferOutputStream::Write(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount) { - if (mBuffer == nsnull) - return NS_BASE_STREAM_CLOSED; + return mInputStream->Fill(aBuf, aCount, aWriteCount); +} +NS_IMETHODIMP +nsByteBufferOutputStream::Write(nsIInputStream* fromStream, PRUint32 *aWriteCount) +{ + return mInputStream->Fill(fromStream, aWriteCount); +} + +//////////////////////////////////////////////////////////////////////////////// + +NS_BASE nsresult +NS_NewByteBufferInputStream(nsIByteBufferInputStream* *result, + PRBool blocking, PRUint32 size) +{ nsresult rv; + nsByteBufferInputStream* inStr = nsnull; - // wrap-around buffer: - *filledAmount = 0; - if (mReadCursor <= mWriteCursor && !mFull) { - rv = WriteChunk(stream, mLength, filledAmount); - if (NS_FAILED(rv)) return rv; - if (mWriteCursor == mLength) { - mWriteCursor = 0; - rv = WriteChunk(stream, mReadCursor, filledAmount); - if (NS_FAILED(rv)) return rv; - if (mWriteCursor == mReadCursor) - mFull = PR_TRUE; - } - } - else { - rv = WriteChunk(stream, mReadCursor, filledAmount); - if (NS_FAILED(rv)) return rv; + inStr = new nsByteBufferInputStream(blocking, size); + if (inStr == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + rv = inStr->Init(); + if (NS_FAILED(rv)) { + delete inStr; + return rv; } + NS_ADDREF(inStr); + *result = inStr; return NS_OK; } //////////////////////////////////////////////////////////////////////////////// NS_BASE nsresult -NS_NewByteBufferInputStream(PRUint32 size, nsIByteBufferInputStream* *result) +NS_NewPipe(nsIInputStream* *inStrResult, + nsIOutputStream* *outStrResult, + PRBool blocking, PRUint32 size) { - nsByteBufferInputStream* str = - new nsByteBufferInputStream(); - if (str == nsnull) + nsresult rv; + nsIByteBufferInputStream* in; + nsByteBufferInputStream* inStr; + nsByteBufferOutputStream* outStr; + + rv = NS_NewByteBufferInputStream(&in, blocking, size); + if (NS_FAILED(rv)) return rv; + // this cast is safe, because we know how NS_NewByteBufferInputStream works: + inStr = NS_STATIC_CAST(nsByteBufferInputStream*, in); + + outStr = new nsByteBufferOutputStream(inStr); + if (outStr == nsnull) { + NS_RELEASE(inStr); return NS_ERROR_OUT_OF_MEMORY; - nsresult rv = str->Init(size); - if (NS_FAILED(rv)) { - delete str; - return rv; } - NS_ADDREF(str); - *result = str; + NS_ADDREF(outStr); + + *inStrResult = inStr; + *outStrResult = outStr; return NS_OK; } diff --git a/mozilla/xpcom/io/nsIBaseStream.h b/mozilla/xpcom/io/nsIBaseStream.h index ffef4d25c15..bf2f734f0ec 100644 --- a/mozilla/xpcom/io/nsIBaseStream.h +++ b/mozilla/xpcom/io/nsIBaseStream.h @@ -52,6 +52,8 @@ public: #define NS_BASE_STREAM_NO_CONVERTER NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 5) /// For unichar streams #define NS_BASE_STREAM_BAD_CONVERSION NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_BASE, 6) + +#define NS_BASE_STREAM_WOULD_BLOCK NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_BASE, 7) //@} diff --git a/mozilla/xpcom/io/nsIByteBufferInputStream.h b/mozilla/xpcom/io/nsIByteBufferInputStream.h index f0408528cfb..15d0c4df79f 100644 --- a/mozilla/xpcom/io/nsIByteBufferInputStream.h +++ b/mozilla/xpcom/io/nsIByteBufferInputStream.h @@ -15,10 +15,12 @@ * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ + #ifndef nsIByteBufferInputStream_h___ #define nsIByteBufferInputStream_h___ #include "nsIInputStream.h" +#include "nsIOutputStream.h" #define NS_IBYTEBUFFERINPUTSTREAM_IID \ { /* 40767100-eb9c-11d2-931c-00104ba0fd40 */ \ @@ -30,14 +32,46 @@ class nsIByteBufferInputStream : public nsIInputStream { public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IBYTEBUFFERINPUTSTREAM_IID); - static const nsIID& GetIID() { static nsIID iid = NS_IBYTEBUFFERINPUTSTREAM_IID; return iid; } + NS_IMETHOD Fill(nsIInputStream* stream, PRUint32 *aWriteCount) = 0; + + NS_IMETHOD Fill(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount) = 0; - NS_IMETHOD Fill(nsIInputStream* stream, PRUint32 *filledAmount) = 0; }; -// Makes an byte buffer input stream: +//////////////////////////////////////////////////////////////////////////////// + +// XXX regenerate: +#define NS_IBYTEBUFFEROUTPUTSTREAM_IID \ +{ /* 924df6d0-f192-11d2-9322-000000000000 */ \ + 0x924df6d0, \ + 0xf192, \ + 0x11d2, \ + {0x93, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} \ +} + +class nsIByteBufferOutputStream : public nsIOutputStream { +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_IBYTEBUFFEROUTPUTSTREAM_IID); + + NS_IMETHOD Write(nsIInputStream* fromStream, PRUint32 *aWriteCount) = 0; + +}; + +//////////////////////////////////////////////////////////////////////////////// + extern NS_BASE nsresult -NS_NewByteBufferInputStream(PRUint32 size, nsIByteBufferInputStream* *result); +NS_NewByteBufferInputStream(nsIByteBufferInputStream* *result, + PRBool blocking = PR_FALSE, + PRUint32 size = 4096); + +extern NS_BASE nsresult +NS_NewPipe(nsIInputStream* *inStrResult, + nsIOutputStream* *outStrResult, + PRBool blocking = PR_TRUE, + PRUint32 bufferSize = 4096); + +//////////////////////////////////////////////////////////////////////////////// #endif /* nsByteBufferInputStream_h___ */ diff --git a/mozilla/xpcom/tests/TestPipes.cpp b/mozilla/xpcom/tests/TestPipes.cpp new file mode 100644 index 00000000000..064297c7097 --- /dev/null +++ b/mozilla/xpcom/tests/TestPipes.cpp @@ -0,0 +1,100 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +#include "nsIThread.h" +#include "nsIByteBufferInputStream.h" +#include "prprf.h" +#include "plstr.h" +#include + +#define KEY 0xa7 +#define ITERATIONS 333 +char kTestPattern[] = "My hovercraft is full of eels.\n"; + +class nsReceiver : public nsIRunnable { +public: + NS_DECL_ISUPPORTS + + NS_IMETHOD Run() { + nsresult rv; + char buf[101]; + PRUint32 count; + while (PR_TRUE) { + rv = mIn->Read(buf, 100, &count); + if (rv == NS_BASE_STREAM_EOF) { + printf("EOF count = %d\n", mCount); + return NS_OK; + } + if (NS_FAILED(rv)) { + printf("read failed\n"); + return rv; + } + + buf[count] = '\0'; + printf(buf); + + mCount += count; + } + return rv; + } + + nsReceiver(nsIInputStream* in) : mIn(in), mCount(0) { + NS_INIT_REFCNT(); + NS_ADDREF(in); + } + + virtual ~nsReceiver() { + NS_RELEASE(mIn); + } + +protected: + nsIInputStream* mIn; + PRUint32 mCount; +}; + +NS_IMPL_ISUPPORTS(nsReceiver, nsIRunnable::GetIID()); + +int +main() +{ + nsresult rv; + nsIInputStream* in; + nsIOutputStream* out; + + rv = NS_NewPipe(&in, &out, PR_TRUE, 40); + if (NS_FAILED(rv)) return -1; + + nsIThread* receiver; + rv = NS_NewThread(&receiver, new nsReceiver(in)); + NS_RELEASE(in); + + for (PRUint32 i = 0; i < ITERATIONS; i++) { + PRUint32 writeCount; + char* buf = PR_smprintf("%d %s", i, kTestPattern); + rv = out->Write(buf, PL_strlen(buf), &writeCount); + PR_smprintf_free(buf); + NS_ASSERTION(NS_SUCCEEDED(rv), "write failed"); + } + rv = out->Close(); + NS_ASSERTION(NS_SUCCEEDED(rv), "close failed"); + + receiver->Join(); + NS_RELEASE(receiver); + + return 0; +}