зеркало из https://github.com/mozilla/pjs.git
Added nsIPipe.idl, replacing nsPipe2.h. Fixed up some nsPipe2.cpp problems. Fixed bug in nsSegmentedBuffer segment growth. Extended TestPipes test case to cover much much more.
This commit is contained in:
Родитель
79f9ac9da3
Коммит
4324494f97
|
@ -60,14 +60,14 @@ nsBuffer::Init(PRUint32 growBySize, PRUint32 maxSize,
|
|||
|
||||
nsBuffer::~nsBuffer()
|
||||
{
|
||||
// Free any allocated pages...
|
||||
while (!PR_CLIST_IS_EMPTY(&mSegments)) {
|
||||
PRCList* header = (PRCList*)mSegments.next;
|
||||
char* segment = (char*)header;
|
||||
// Free any allocated pages...
|
||||
while (!PR_CLIST_IS_EMPTY(&mSegments)) {
|
||||
PRCList* header = (PRCList*)mSegments.next;
|
||||
char* segment = (char*)header;
|
||||
|
||||
PR_REMOVE_LINK(header); // unlink from mSegments
|
||||
(void) mAllocator->Free(segment);
|
||||
}
|
||||
PR_REMOVE_LINK(header); // unlink from mSegments
|
||||
(void) mAllocator->Free(segment);
|
||||
}
|
||||
|
||||
NS_IF_RELEASE(mObserver);
|
||||
NS_IF_RELEASE(mAllocator);
|
||||
|
|
|
@ -141,6 +141,9 @@ public:
|
|||
}
|
||||
|
||||
static PRInt32 strncmp(const char* s1, const char* s2, PRInt32 aMaxLen) {
|
||||
// inline the first test (assumes strings are not null):
|
||||
PRInt32 diff = ((const unsigned char*)s1)[0] - ((const unsigned char*)s2)[0];
|
||||
if (diff != 0) return diff;
|
||||
return PRInt32(PL_strncmp(s1,s2,aMaxLen));
|
||||
}
|
||||
|
||||
|
|
|
@ -2,4 +2,5 @@ nsIFileSpec.idl
|
|||
nsIBufferInputStream.idl
|
||||
nsIInputStream.idl
|
||||
nsIBaseStream.idl
|
||||
nsIOutputStream.idl
|
||||
nsIOutputStream.idl
|
||||
nsIPipe.idl
|
||||
|
|
|
@ -31,6 +31,7 @@ MODULE = xpcom
|
|||
XPIDL_MODULE = xpcom_io
|
||||
|
||||
XPIDLSRCS = \
|
||||
nsIPipe.idl \
|
||||
nsIFileSpec.idl \
|
||||
nsIBaseStream.idl \
|
||||
nsIInputStream.idl \
|
||||
|
@ -63,7 +64,6 @@ EXPORTS = \
|
|||
nsIStringStream.h \
|
||||
nsIUnicharInputStream.h \
|
||||
nsSpecialSystemDirectory.h \
|
||||
nsPipe2.h \
|
||||
$(NULL)
|
||||
|
||||
|
||||
|
|
|
@ -32,13 +32,13 @@ EXPORTS = \
|
|||
nsIStringStream.h \
|
||||
nsIUnicharInputStream.h \
|
||||
nsSpecialSystemDirectory.h \
|
||||
nsPipe2.h \
|
||||
$(NULL)
|
||||
|
||||
NO_XPT_GEN=1
|
||||
XPIDL_MODULE = xpcom_io
|
||||
|
||||
XPIDLSRCS = \
|
||||
.\nsIPipe.idl \
|
||||
.\nsIFileSpec.idl \
|
||||
.\nsIBaseStream.idl \
|
||||
.\nsIInputStream.idl \
|
||||
|
|
|
@ -20,6 +20,26 @@
|
|||
|
||||
interface nsIBuffer;
|
||||
|
||||
%{C++
|
||||
/**
|
||||
* The signature of the writer function passed to ReadSegments. This
|
||||
* specifies where the data should go that gets read from the buffer.
|
||||
* Implementers should return the following:
|
||||
* @return NS_OK and writeCount - if successfully wrote something
|
||||
* @return NS_BASE_STREAM_CLOSED - if no more can be written
|
||||
* @return NS_BASE_STREAM_WOULD_BLOCK - if there is currently space to write (in
|
||||
* a non-blocking mode)
|
||||
* @return <other-error> - on failure
|
||||
*/
|
||||
typedef NS_CALLBACK(nsWriteSegmentFun)(void* closure,
|
||||
const char* fromRawSegment,
|
||||
PRUint32 toOffset,
|
||||
PRUint32 count,
|
||||
PRUint32 *writeCount);
|
||||
%}
|
||||
|
||||
native nsWriteSegmentFun(nsWriteSegmentFun);
|
||||
|
||||
[scriptable, uuid(93e9a230-1955-11d3-933b-000064657374)]
|
||||
interface nsIBufferInputStream : nsIInputStream
|
||||
{
|
||||
|
@ -28,6 +48,11 @@ interface nsIBufferInputStream : nsIInputStream
|
|||
*/
|
||||
readonly attribute nsIBuffer Buffer;
|
||||
|
||||
|
||||
[noscript] unsigned long ReadSegments(in nsWriteSegmentFun writer,
|
||||
in voidStar closure,
|
||||
in unsigned long count);
|
||||
|
||||
/**
|
||||
* Searches for a string in the input stream. Since the stream has a notion
|
||||
* of EOF, it is possible that the string may at some time be in the
|
||||
|
|
|
@ -20,6 +20,26 @@
|
|||
|
||||
interface nsIBuffer;
|
||||
|
||||
%{C++
|
||||
/**
|
||||
* The signature for the reader function passed to WriteSegment. This
|
||||
* specifies where the data should come from that gets written into the buffer.
|
||||
* Implementers should return the following:
|
||||
* @return NS_OK and readCount - if successfully read something
|
||||
* @return NS_BASE_STREAM_EOF - if no more to read
|
||||
* @return NS_BASE_STREAM_WOULD_BLOCK - if there is currently no data (in
|
||||
* a non-blocking mode)
|
||||
* @return <other-error> - on failure
|
||||
*/
|
||||
typedef NS_CALLBACK(nsReadSegmentFun)(void* closure,
|
||||
char* toRawSegment,
|
||||
PRUint32 fromOffset,
|
||||
PRUint32 count,
|
||||
PRUint32 *readCount);
|
||||
%}
|
||||
|
||||
native nsReadSegmentFun(nsReadSegmentFun);
|
||||
|
||||
[scriptable, uuid(d2aaae66-1ab0-11d3-8ccd-0060b0fc14a3)]
|
||||
interface nsIBufferOutputStream : nsIOutputStream
|
||||
{
|
||||
|
@ -28,6 +48,10 @@ interface nsIBufferOutputStream : nsIOutputStream
|
|||
*/
|
||||
readonly attribute nsIBuffer Buffer;
|
||||
|
||||
[noscript] unsigned long WriteSegments(in nsReadSegmentFun reader,
|
||||
in voidStar closure,
|
||||
in unsigned long count);
|
||||
|
||||
/**
|
||||
* Writes data into the stream from an input stream.
|
||||
* Implementer's note: This method is defined by this interface in order
|
||||
|
|
|
@ -37,8 +37,14 @@ public:
|
|||
NS_DECL_NSIINPUTSTREAM
|
||||
|
||||
// nsIBufferInputStream methods:
|
||||
NS_DECL_NSIBUFFERINPUTSTREAM
|
||||
|
||||
NS_IMETHOD GetBuffer(nsIBuffer* *result);
|
||||
NS_IMETHOD ReadSegments(nsWriteSegmentFun writer, void* closure, PRUint32 count,
|
||||
PRUint32 *readCount) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
NS_IMETHOD Search(const char *forString, PRBool ignoreCase, PRBool *found, PRUint32 *offsetSearchedTo);
|
||||
NS_IMETHOD GetNonBlocking(PRBool *aNonBlocking);
|
||||
NS_IMETHOD SetNonBlocking(PRBool aNonBlocking);
|
||||
#if 0
|
||||
NS_IMETHOD Fill(const char *buf, PRUint32 count, PRUint32 *_retval);
|
||||
NS_IMETHOD FillFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval);
|
||||
|
@ -69,7 +75,15 @@ public:
|
|||
NS_DECL_NSIOUTPUTSTREAM
|
||||
|
||||
// nsIBufferOutputStream methods:
|
||||
NS_DECL_NSIBUFFEROUTPUTSTREAM
|
||||
NS_IMETHOD GetBuffer(nsIBuffer * *aBuffer);
|
||||
NS_IMETHOD WriteSegments(nsReadSegmentFun reader, void* closure, PRUint32 count,
|
||||
PRUint32 *writeCount) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
NS_IMETHOD WriteFrom(nsIInputStream* fromStream, PRUint32 aCount,
|
||||
PRUint32 *aWriteCount);
|
||||
NS_IMETHOD GetNonBlocking(PRBool *aNonBlocking);
|
||||
NS_IMETHOD SetNonBlocking(PRBool aNonBlocking);
|
||||
|
||||
// nsBufferOutputStream methods:
|
||||
nsBufferOutputStream(nsIBuffer* buf, PRBool blocking);
|
||||
|
@ -283,7 +297,24 @@ nsBufferOutputStream::~nsBufferOutputStream()
|
|||
NS_RELEASE(mBuffer);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS3(nsBufferOutputStream, nsIBufferOutputStream, nsIOutputStream, nsIBaseStream)
|
||||
NS_IMPL_ADDREF(nsBufferOutputStream);
|
||||
NS_IMPL_RELEASE(nsBufferOutputStream);
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBufferOutputStream::QueryInterface(REFNSIID aIID, void** aInstancePtr)
|
||||
{
|
||||
if (aInstancePtr == nsnull)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
if (aIID.Equals(nsIBufferOutputStream::GetIID()) ||
|
||||
aIID.Equals(nsIOutputStream::GetIID()) ||
|
||||
aIID.Equals(nsIBaseStream::GetIID()) ||
|
||||
aIID.Equals(nsCOMTypeInfo<nsISupports>::GetIID())) {
|
||||
*aInstancePtr = this;
|
||||
NS_ADDREF_THIS();
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_NOINTERFACE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBufferOutputStream::Close(void)
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
* Reserved.
|
||||
*/
|
||||
|
||||
#include "nsPipe2.h"
|
||||
#include "nsIPipe.h"
|
||||
#include "nsIBufferInputStream.h"
|
||||
#include "nsIBufferOutputStream.h"
|
||||
#include "nsSegmentedBuffer.h"
|
||||
#include "nsAutoLock.h"
|
||||
#include "nsIServiceManager.h"
|
||||
|
@ -24,7 +26,7 @@
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class nsPipe : public nsISupports
|
||||
class nsPipe : public nsIPipe
|
||||
{
|
||||
public:
|
||||
// We can't inherit from both nsIBufferInputStream and nsIBufferOutputStream
|
||||
|
@ -41,11 +43,13 @@ public:
|
|||
NS_IMETHOD Close(void);
|
||||
// nsIInputStream methods:
|
||||
NS_IMETHOD GetLength(PRUint32 *result);
|
||||
NS_IMETHOD ReadSegments(nsWriteSegmentFun writer, void* closure, PRUint32 count,
|
||||
PRUint32 *readCount);
|
||||
NS_IMETHOD Read(char* toBuf, PRUint32 bufLen, PRUint32 *readCount);
|
||||
// nsIBufferInputStream methods:
|
||||
NS_IMETHOD GetBuffer(nsIBuffer * *aBuffer);
|
||||
NS_IMETHOD GetBuffer(nsIBuffer * *aBuffer) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
NS_IMETHOD ReadSegments(nsWriteSegmentFun writer, void* closure, PRUint32 count,
|
||||
PRUint32 *readCount);
|
||||
NS_IMETHOD Search(const char *forString, PRBool ignoreCase, PRBool *found,
|
||||
PRUint32 *offsetSearchedTo);
|
||||
NS_IMETHOD GetNonBlocking(PRBool *aNonBlocking);
|
||||
|
@ -65,12 +69,14 @@ public:
|
|||
NS_IMETHOD_(nsrefcnt) Release(void);
|
||||
// nsIBaseStream methods:
|
||||
NS_IMETHOD Close(void);
|
||||
NS_IMETHOD WriteSegments(nsReadSegmentFun reader, void* closure, PRUint32 count,
|
||||
PRUint32 *writeCount);
|
||||
NS_IMETHOD Write(const char* fromBuf, PRUint32 bufLen, PRUint32 *writeCount);
|
||||
NS_IMETHOD Flush(void);
|
||||
// nsIBufferOutputStream methods:
|
||||
NS_IMETHOD GetBuffer(nsIBuffer * *aBuffer);
|
||||
NS_IMETHOD GetBuffer(nsIBuffer * *aBuffer) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
NS_IMETHOD WriteSegments(nsReadSegmentFun reader, void* closure, PRUint32 count,
|
||||
PRUint32 *writeCount);
|
||||
NS_IMETHOD WriteFrom(nsIInputStream* fromStream, PRUint32 count, PRUint32 *writeCount);
|
||||
NS_IMETHOD GetNonBlocking(PRBool *aNonBlocking);
|
||||
NS_IMETHOD SetNonBlocking(PRBool aNonBlocking);
|
||||
|
@ -86,10 +92,44 @@ public:
|
|||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIPipe methods:
|
||||
NS_IMETHOD Initialize(PRUint32 segmentSize, PRUint32 maxSize,
|
||||
nsIPipeObserver *observer, nsIAllocator *segmentAllocator) {
|
||||
nsresult rv;
|
||||
rv = mBuffer.Init(segmentSize, maxSize, segmentAllocator);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
mObserver = observer;
|
||||
NS_IF_ADDREF(mObserver);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetInputStream(nsIBufferInputStream * *aInputStream) {
|
||||
*aInputStream = &mInput;
|
||||
NS_IF_ADDREF(*aInputStream);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetOutputStream(nsIBufferOutputStream * *aOutputStream) {
|
||||
*aOutputStream = &mOutput;
|
||||
NS_IF_ADDREF(*aOutputStream);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD GetObserver(nsIPipeObserver* *result) {
|
||||
*result = mObserver;
|
||||
NS_IF_ADDREF(*result);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD SetObserver(nsIPipeObserver* obs) {
|
||||
NS_IF_RELEASE(mObserver);
|
||||
mObserver = obs;
|
||||
NS_IF_ADDREF(mObserver);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsPipe methods:
|
||||
nsPipe(PRUint32 segmentSize, PRUint32 maxSize,
|
||||
nsIAllocator* allocator = nsnull,
|
||||
nsIPipeObserver* observer = nsnull);
|
||||
nsPipe();
|
||||
virtual ~nsPipe();
|
||||
|
||||
nsPipeInputStream* GetInputStream() { return &mInput; }
|
||||
|
@ -126,10 +166,8 @@ protected:
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsPipe methods:
|
||||
|
||||
nsPipe::nsPipe(PRUint32 segmentSize, PRUint32 maxSize,
|
||||
nsIAllocator* allocator, nsIPipeObserver* observer)
|
||||
: mBuffer(segmentSize, maxSize, allocator),
|
||||
mObserver(observer),
|
||||
nsPipe::nsPipe()
|
||||
: mObserver(nsnull),
|
||||
mReadCursor(nsnull),
|
||||
mReadLimit(nsnull),
|
||||
mWriteCursor(nsnull),
|
||||
|
@ -137,7 +175,6 @@ nsPipe::nsPipe(PRUint32 segmentSize, PRUint32 maxSize,
|
|||
mCondition(NS_OK)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
NS_IF_ADDREF(mObserver);
|
||||
}
|
||||
|
||||
nsPipe::~nsPipe()
|
||||
|
@ -167,7 +204,8 @@ nsPipe::QueryInterface(const nsIID& aIID, void** aInstancePtr)
|
|||
NS_ADDREF_THIS();
|
||||
return NS_OK;
|
||||
}
|
||||
if (aIID.Equals(nsCOMTypeInfo<nsISupports>::GetIID())) {
|
||||
if (aIID.Equals(nsIPipe::GetIID()) ||
|
||||
aIID.Equals(nsCOMTypeInfo<nsISupports>::GetIID())) {
|
||||
*aInstancePtr = this;
|
||||
NS_ADDREF_THIS();
|
||||
return NS_OK;
|
||||
|
@ -228,8 +266,6 @@ nsPipe::GetWriteSegment(char* *resultSegment,
|
|||
char* seg = mBuffer.AppendNewSegment();
|
||||
if (seg == nsnull) {
|
||||
// buffer is full
|
||||
if (mObserver)
|
||||
return mObserver->OnFull();
|
||||
return NS_OK;
|
||||
}
|
||||
mWriteCursor = seg;
|
||||
|
@ -318,8 +354,12 @@ nsPipe::nsPipeInputStream::ReadSegments(nsWriteSegmentFun writer,
|
|||
rv = pipe->mCondition;
|
||||
if (*readCount > 0 || NS_FAILED(rv))
|
||||
goto done; // don't Fill if we've got something
|
||||
if (pipe->mObserver) {
|
||||
rv = pipe->mObserver->OnEmpty(pipe);
|
||||
if (NS_FAILED(rv)) goto done;
|
||||
}
|
||||
rv = Fill();
|
||||
if (NS_FAILED(rv))
|
||||
if (rv == NS_BASE_STREAM_WOULD_BLOCK || NS_FAILED(rv))
|
||||
goto done;
|
||||
// else we filled the pipe, so go around again
|
||||
continue;
|
||||
|
@ -332,12 +372,12 @@ nsPipe::nsPipeInputStream::ReadSegments(nsWriteSegmentFun writer,
|
|||
NS_ASSERTION(rv != NS_BASE_STREAM_EOF, "Write should not return EOF");
|
||||
if (NS_FAILED(rv))
|
||||
goto done;
|
||||
if (writeCount == 0) {
|
||||
if (writeCount == 0 || rv == NS_BASE_STREAM_WOULD_BLOCK) {
|
||||
rv = pipe->mCondition;
|
||||
if (*readCount > 0 || NS_FAILED(rv))
|
||||
goto done; // don't Fill if we've got something
|
||||
rv = Fill();
|
||||
if (NS_FAILED(rv))
|
||||
if (rv == NS_BASE_STREAM_WOULD_BLOCK || NS_FAILED(rv))
|
||||
goto done;
|
||||
// else we filled the pipe, so go around again
|
||||
continue;
|
||||
|
@ -353,11 +393,13 @@ nsPipe::nsPipeInputStream::ReadSegments(nsWriteSegmentFun writer,
|
|||
pipe->mReadCursor = nsnull;
|
||||
pipe->mReadLimit = nsnull;
|
||||
PRBool empty = pipe->mBuffer.DeleteFirstSegment();
|
||||
if (empty && pipe->mObserver) {
|
||||
rv = pipe->mObserver->OnEmpty();
|
||||
#if 0
|
||||
if (empty && pipe->mObserver && *readCount == 0) {
|
||||
rv = pipe->mObserver->OnEmpty(pipe);
|
||||
if (NS_FAILED(rv))
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
done:
|
||||
|
@ -416,12 +458,6 @@ nsPipe::nsPipeInputStream::Read(char* toBuf, PRUint32 bufLen, PRUint32 *readCoun
|
|||
return ReadSegments(nsWriteToRawBuffer, toBuf, bufLen, readCount);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPipe::nsPipeInputStream::GetBuffer(nsIBuffer * *aBuffer)
|
||||
{
|
||||
return NS_ERROR_FAILURE; // obsolete method
|
||||
}
|
||||
|
||||
#define COMPARE(s1, s2, i) \
|
||||
(ignoreCase \
|
||||
? nsCRT::strncasecmp((const char *)s1, (const char *)s2, (PRUint32)i) \
|
||||
|
@ -560,12 +596,12 @@ nsPipe::nsPipeOutputStream::WriteSegments(nsReadSegmentFun reader,
|
|||
{
|
||||
nsAutoCMonitor mon(pipe);
|
||||
|
||||
*writeCount = 0;
|
||||
if (NS_FAILED(pipe->mCondition)) {
|
||||
rv = pipe->mCondition;
|
||||
goto done;
|
||||
}
|
||||
|
||||
*writeCount = 0;
|
||||
while (count > 0) {
|
||||
PRUint32 writeBufLen;
|
||||
char* writeBuf;
|
||||
|
@ -573,6 +609,10 @@ nsPipe::nsPipeOutputStream::WriteSegments(nsReadSegmentFun reader,
|
|||
if (NS_FAILED(rv))
|
||||
goto done;
|
||||
if (writeBufLen == 0) {
|
||||
if (pipe->mObserver && *writeCount == 0) {
|
||||
rv = pipe->mObserver->OnFull(pipe);
|
||||
if (NS_FAILED(rv)) goto done;
|
||||
}
|
||||
rv = Flush();
|
||||
if (rv == NS_BASE_STREAM_WOULD_BLOCK || NS_FAILED(rv))
|
||||
goto done;
|
||||
|
@ -590,10 +630,11 @@ nsPipe::nsPipeOutputStream::WriteSegments(nsReadSegmentFun reader,
|
|||
goto done;
|
||||
}
|
||||
if (readCount == 0) {
|
||||
// if the place we're putting the data would block (probably ran
|
||||
// out of room) just return what we were able to write so far
|
||||
rv = Flush();
|
||||
if (rv == NS_BASE_STREAM_WOULD_BLOCK || NS_FAILED(rv))
|
||||
// The reader didn't have anything else to put in the buffer, so
|
||||
// call flush to notify the guy downstream, hoping that he'll somehow
|
||||
// wake up the guy upstream to eventually produce more data for us.
|
||||
nsresult rv2 = Flush();
|
||||
if (rv2 == NS_BASE_STREAM_WOULD_BLOCK || NS_FAILED(rv2))
|
||||
goto done;
|
||||
// else we flushed, so go around again
|
||||
continue;
|
||||
|
@ -617,7 +658,7 @@ nsPipe::nsPipeOutputStream::WriteSegments(nsReadSegmentFun reader,
|
|||
} // exit monitor
|
||||
|
||||
if (pipe->mObserver && *writeCount > 0) {
|
||||
pipe->mObserver->OnWrite(*writeCount);
|
||||
pipe->mObserver->OnWrite(pipe, *writeCount);
|
||||
}
|
||||
return *writeCount == 0 ? rv : NS_OK;
|
||||
}
|
||||
|
@ -658,8 +699,8 @@ nsPipe::nsPipeOutputStream::Flush(void)
|
|||
if (firstTime && amt == 0) {
|
||||
// If we think we needed to flush, yet there's nothing
|
||||
// in the buffer to read, we must have not been able to
|
||||
// allocate any segments. Return out of memory:
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
// allocate any segments.
|
||||
return NS_BASE_STREAM_WOULD_BLOCK;
|
||||
}
|
||||
if (NS_FAILED(rv) || amt == 0) return rv;
|
||||
firstTime = PR_FALSE;
|
||||
|
@ -678,12 +719,6 @@ nsPipe::nsPipeOutputStream::Flush(void)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPipe::nsPipeOutputStream::GetBuffer(nsIBuffer * *aBuffer)
|
||||
{
|
||||
return NS_ERROR_FAILURE; // obsolete method
|
||||
}
|
||||
|
||||
static NS_METHOD
|
||||
nsReadFromInputStream(void* closure,
|
||||
char* toRawSegment,
|
||||
|
@ -739,9 +774,14 @@ NS_NewPipe(nsIBufferInputStream* *inStrResult,
|
|||
#endif
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsPipe* pipe = new nsPipe(segmentSize, maxSize, alloc, observer);
|
||||
nsPipe* pipe = new nsPipe();
|
||||
if (pipe == nsnull)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
rv = pipe->Initialize(segmentSize, maxSize, observer, alloc);
|
||||
if (NS_FAILED(rv)) {
|
||||
delete pipe;
|
||||
return rv;
|
||||
}
|
||||
*inStrResult = pipe->GetInputStream();
|
||||
*outStrResult = pipe->GetOutputStream();
|
||||
NS_ADDREF(*inStrResult);
|
||||
|
|
|
@ -41,6 +41,7 @@ public:
|
|||
NS_IMETHOD OnEmpty() = 0;
|
||||
};
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* The signature for the reader function passed to WriteSegment. This
|
||||
* specifies where the data should come from that gets written into the buffer.
|
||||
|
@ -72,6 +73,7 @@ typedef NS_CALLBACK(nsWriteSegmentFun)(void* closure,
|
|||
PRUint32 toOffset,
|
||||
PRUint32 count,
|
||||
PRUint32 *writeCount);
|
||||
#endif
|
||||
|
||||
#define NS_PIPE_DEFAULT_SEGMENT_SIZE 4096
|
||||
#define NS_PIPE_DEFAULT_BUFFER_SIZE (1024*1024)
|
||||
|
|
|
@ -19,49 +19,60 @@
|
|||
#include "nsSegmentedBuffer.h"
|
||||
#include "nsCRT.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DEBUG_MEMSET(addr, value, count) nsCRT::memset(addr, value, count)
|
||||
#else
|
||||
#define DEBUG_MEMSET(addr, value, count) /* nothing */
|
||||
#endif
|
||||
|
||||
nsSegmentedBuffer::nsSegmentedBuffer(PRUint32 segmentSize, PRUint32 maxSize,
|
||||
nsIAllocator* allocator)
|
||||
: mSegmentSize(segmentSize), mMaxSize(maxSize),
|
||||
mSegAllocator(allocator), mSegmentArray(nsnull),
|
||||
mSegmentArrayCount(NS_SEGMENTARRAY_INITIAL_COUNT),
|
||||
nsSegmentedBuffer::nsSegmentedBuffer()
|
||||
: mSegmentSize(0), mMaxSize(0),
|
||||
mSegAllocator(nsnull), mSegmentArray(nsnull),
|
||||
mSegmentArrayCount(0),
|
||||
mFirstSegmentIndex(0), mLastSegmentIndex(0)
|
||||
{
|
||||
}
|
||||
|
||||
nsSegmentedBuffer::~nsSegmentedBuffer()
|
||||
{
|
||||
Empty();
|
||||
NS_IF_RELEASE(mSegAllocator);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsSegmentedBuffer::Init(PRUint32 segmentSize, PRUint32 maxSize,
|
||||
nsIAllocator* allocator)
|
||||
{
|
||||
if (mSegmentArrayCount != 0)
|
||||
return NS_ERROR_FAILURE; // initialized more than once
|
||||
mSegmentSize = segmentSize;
|
||||
mMaxSize = maxSize;
|
||||
mSegAllocator = allocator;
|
||||
if (mSegAllocator == nsnull) {
|
||||
mSegAllocator = nsAllocator::GetGlobalAllocator();
|
||||
}
|
||||
else {
|
||||
NS_ADDREF(mSegAllocator);
|
||||
}
|
||||
}
|
||||
|
||||
nsSegmentedBuffer::~nsSegmentedBuffer()
|
||||
{
|
||||
Empty();
|
||||
NS_RELEASE(mSegAllocator);
|
||||
#if 0 // testing...
|
||||
mSegmentArrayCount = 2;
|
||||
#else
|
||||
mSegmentArrayCount = NS_SEGMENTARRAY_INITIAL_COUNT;
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
char*
|
||||
nsSegmentedBuffer::AppendNewSegment()
|
||||
{
|
||||
if (GetSize() >= mMaxSize)
|
||||
return nsnull;
|
||||
|
||||
if (mSegmentArray == nsnull) {
|
||||
PRUint32 bytes = mSegmentArrayCount * sizeof(char*);
|
||||
mSegmentArray = (char**)nsAllocator::Alloc(bytes);
|
||||
if (mSegmentArray == nsnull)
|
||||
return nsnull;
|
||||
DEBUG_MEMSET(mSegmentArray, 0, bytes);
|
||||
nsCRT::memset(mSegmentArray, 0, bytes);
|
||||
}
|
||||
|
||||
|
||||
if (IsFull()) {
|
||||
PRUint32 newArraySize = mSegmentArrayCount * 2;
|
||||
PRUint32 bytes = newArraySize * sizeof(char*);
|
||||
if (bytes > mMaxSize)
|
||||
return nsnull;
|
||||
char** newSegArray = (char**)nsAllocator::Realloc(mSegmentArray, bytes);
|
||||
if (newSegArray == nsnull)
|
||||
return nsnull;
|
||||
|
@ -72,10 +83,14 @@ nsSegmentedBuffer::AppendNewSegment()
|
|||
nsCRT::memcpy(&mSegmentArray[mSegmentArrayCount],
|
||||
mSegmentArray,
|
||||
mLastSegmentIndex * sizeof(char*));
|
||||
DEBUG_MEMSET(mSegmentArray, 0, mLastSegmentIndex * sizeof(char*));
|
||||
nsCRT::memset(mSegmentArray, 0, mLastSegmentIndex * sizeof(char*));
|
||||
mLastSegmentIndex += mSegmentArrayCount;
|
||||
DEBUG_MEMSET(&mSegmentArray[mLastSegmentIndex],
|
||||
0, (newArraySize - mLastSegmentIndex) * sizeof(char*));
|
||||
nsCRT::memset(&mSegmentArray[mLastSegmentIndex], 0,
|
||||
(newArraySize - mLastSegmentIndex) * sizeof(char*));
|
||||
}
|
||||
else {
|
||||
nsCRT::memset(&mSegmentArray[mLastSegmentIndex], 0,
|
||||
(newArraySize - mLastSegmentIndex) * sizeof(char*));
|
||||
}
|
||||
mSegmentArrayCount = newArraySize;
|
||||
}
|
||||
|
@ -124,18 +139,36 @@ nsSegmentedBuffer::Empty()
|
|||
NS_COM void
|
||||
TestSegmentedBuffer()
|
||||
{
|
||||
nsSegmentedBuffer* mgr = new nsSegmentedBuffer(4, 8);
|
||||
NS_ASSERTION(mgr, "out of memory");
|
||||
mgr->AppendNewSegment();
|
||||
mgr->AppendNewSegment();
|
||||
mgr->AppendNewSegment();
|
||||
mgr->DeleteFirstSegment();
|
||||
mgr->DeleteFirstSegment();
|
||||
mgr->AppendNewSegment();
|
||||
mgr->AppendNewSegment();
|
||||
mgr->AppendNewSegment();
|
||||
mgr->DeleteFirstSegment();
|
||||
delete mgr;
|
||||
nsSegmentedBuffer* buf = new nsSegmentedBuffer();
|
||||
NS_ASSERTION(buf, "out of memory");
|
||||
buf->Init(4, 16);
|
||||
char* seg;
|
||||
PRBool empty;
|
||||
seg = buf->AppendNewSegment();
|
||||
NS_ASSERTION(seg, "AppendNewSegment failed");
|
||||
seg = buf->AppendNewSegment();
|
||||
NS_ASSERTION(seg, "AppendNewSegment failed");
|
||||
seg = buf->AppendNewSegment();
|
||||
NS_ASSERTION(seg, "AppendNewSegment failed");
|
||||
empty = buf->DeleteFirstSegment();
|
||||
NS_ASSERTION(!empty, "DeleteFirstSegment failed");
|
||||
empty = buf->DeleteFirstSegment();
|
||||
NS_ASSERTION(!empty, "DeleteFirstSegment failed");
|
||||
seg = buf->AppendNewSegment();
|
||||
NS_ASSERTION(seg, "AppendNewSegment failed");
|
||||
seg = buf->AppendNewSegment();
|
||||
NS_ASSERTION(seg, "AppendNewSegment failed");
|
||||
seg = buf->AppendNewSegment();
|
||||
NS_ASSERTION(seg, "AppendNewSegment failed");
|
||||
empty = buf->DeleteFirstSegment();
|
||||
NS_ASSERTION(!empty, "DeleteFirstSegment failed");
|
||||
empty = buf->DeleteFirstSegment();
|
||||
NS_ASSERTION(!empty, "DeleteFirstSegment failed");
|
||||
empty = buf->DeleteFirstSegment();
|
||||
NS_ASSERTION(!empty, "DeleteFirstSegment failed");
|
||||
empty = buf->DeleteFirstSegment();
|
||||
NS_ASSERTION(empty, "DeleteFirstSegment failed");
|
||||
delete buf;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -25,10 +25,12 @@
|
|||
class nsSegmentedBuffer
|
||||
{
|
||||
public:
|
||||
nsSegmentedBuffer(PRUint32 segmentSize, PRUint32 maxSize,
|
||||
nsIAllocator* allocator = nsnull);
|
||||
nsSegmentedBuffer();
|
||||
~nsSegmentedBuffer();
|
||||
|
||||
nsresult Init(PRUint32 segmentSize, PRUint32 maxSize,
|
||||
nsIAllocator* allocator = nsnull);
|
||||
|
||||
char* AppendNewSegment(); // pushes at end
|
||||
|
||||
// returns true if no more segments remain:
|
||||
|
|
|
@ -28,8 +28,9 @@
|
|||
#include "prinrval.h"
|
||||
#include "plstr.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include <stdio.h>
|
||||
#include "nsPipe2.h" // new implementation
|
||||
#include "nsIPipe.h" // new implementation
|
||||
#include "nsAutoLock.h"
|
||||
#include <stdlib.h> // for rand
|
||||
|
||||
|
@ -128,7 +129,7 @@ TestPipe(nsIInputStream* in, nsIOutputStream* out)
|
|||
|
||||
thread->Join();
|
||||
|
||||
printf("write %d bytes, time = %dms\n", total,
|
||||
printf("wrote %d bytes, time = %dms\n", total,
|
||||
PR_IntervalToMilliseconds(end - start));
|
||||
NS_ASSERTION(receiver->GetBytesRead() == total, "didn't read everything");
|
||||
|
||||
|
@ -148,6 +149,7 @@ public:
|
|||
nsresult rv;
|
||||
char buf[101];
|
||||
PRUint32 count;
|
||||
PRUint32 total = 0;
|
||||
while (PR_TRUE) {
|
||||
rv = mIn->Read(buf, 100, &count);
|
||||
if (rv == NS_BASE_STREAM_EOF) {
|
||||
|
@ -162,7 +164,9 @@ public:
|
|||
if (gTrace)
|
||||
printf("read %d bytes: %s\n", count, buf);
|
||||
Received(count);
|
||||
total += count;
|
||||
}
|
||||
printf("read %d bytes\n", total);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -212,7 +216,8 @@ TestShortWrites(nsIInputStream* in, nsIOutputStream* out)
|
|||
rv = NS_NewThread(&thread, receiver);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
for (PRUint32 i = 0; i < ITERATIONS/100; i++) {
|
||||
PRUint32 total = 0;
|
||||
for (PRUint32 i = 0; i < ITERATIONS; i++) {
|
||||
PRUint32 writeCount;
|
||||
char* buf = PR_smprintf("%d %s", i, kTestPattern);
|
||||
PRUint32 len = nsCRT::strlen(buf);
|
||||
|
@ -221,6 +226,7 @@ TestShortWrites(nsIInputStream* in, nsIOutputStream* out)
|
|||
rv = out->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);
|
||||
|
@ -233,6 +239,7 @@ TestShortWrites(nsIInputStream* in, nsIOutputStream* out)
|
|||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
thread->Join();
|
||||
printf("wrote %d bytes\n", total);
|
||||
|
||||
NS_RELEASE(thread);
|
||||
NS_RELEASE(receiver);
|
||||
|
@ -242,6 +249,221 @@ TestShortWrites(nsIInputStream* in, nsIOutputStream* out)
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class nsPipeObserver : public nsIPipeObserver {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD OnFull(nsIPipe *pipe) {
|
||||
printf("OnFull pipe=%p\n", pipe);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnWrite(nsIPipe *pipe, PRUint32 amount) {
|
||||
printf("OnWrite pipe=%p amount=%d\n", pipe, amount);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnEmpty(nsIPipe *pipe) {
|
||||
printf("OnEmpty pipe=%p\n", pipe);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsPipeObserver() { NS_INIT_REFCNT(); }
|
||||
virtual ~nsPipeObserver() {}
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsPipeObserver, nsIPipeObserver::GetIID());
|
||||
|
||||
nsresult
|
||||
TestPipeObserver()
|
||||
{
|
||||
nsresult rv;
|
||||
nsPipeObserver* obs = new nsPipeObserver();
|
||||
if (obs == nsnull) return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(obs);
|
||||
|
||||
printf("TestPipeObserver: OnWrite, OnFull and OnEmpty should be called once each.\n");
|
||||
nsIBufferInputStream* in;
|
||||
nsIBufferOutputStream* out;
|
||||
rv = NS_NewPipe(&in, &out, obs, 20, 20);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = in->SetNonBlocking(PR_TRUE);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
rv = out->SetNonBlocking(PR_TRUE);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
char buf[] = "puirt a beul: a style of Gaelic vocal music intended for dancing.";
|
||||
PRUint32 cnt;
|
||||
// this should print OnWrite message:
|
||||
rv = out->Write(buf, 20, &cnt);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
NS_ASSERTION(cnt == 20, "Write failed");
|
||||
|
||||
// this should print OnFull message:
|
||||
rv = out->Write(buf + 20, 1, &cnt);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
NS_ASSERTION(cnt == 0, "Write failed");
|
||||
|
||||
char buf2[20];
|
||||
rv = in->Read(buf2, 20, &cnt);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
NS_ASSERTION(cnt == 20, "Read failed");
|
||||
NS_ASSERTION(nsCRT::strncmp(buf, buf2, 20) == 0, "Read wrong stuff");
|
||||
|
||||
// this should print OnEmpty message:
|
||||
rv = in->Read(buf2, 1, &cnt);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
NS_ASSERTION(cnt == 0, "Read failed");
|
||||
|
||||
NS_RELEASE(obs);
|
||||
NS_RELEASE(in);
|
||||
NS_RELEASE(out);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class nsPump : public nsIPipeObserver, public nsIRunnable {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_IMETHOD OnFull(nsIPipe *pipe) {
|
||||
printf("OnFull pipe=%p\n", pipe);
|
||||
nsAutoCMonitor mon(this);
|
||||
mon.Notify();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnWrite(nsIPipe *pipe, PRUint32 amount) {
|
||||
printf("OnWrite pipe=%p amount=%d\n", pipe, amount);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnEmpty(nsIPipe *pipe) {
|
||||
printf("OnEmpty pipe=%p\n", pipe);
|
||||
nsAutoCMonitor mon(this);
|
||||
mon.Notify();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
nsresult rv;
|
||||
PRUint32 count;
|
||||
while (PR_TRUE) {
|
||||
nsAutoCMonitor mon(this);
|
||||
rv = mOut->WriteFrom(mIn, -1, &count);
|
||||
if (rv == NS_BASE_STREAM_EOF) {
|
||||
printf("EOF count = %d\n", mCount);
|
||||
rv = NS_OK;
|
||||
break;
|
||||
}
|
||||
if (NS_FAILED(rv)) {
|
||||
printf("Write failed\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (gTrace) {
|
||||
printf("Wrote: %d\n", count);
|
||||
}
|
||||
mCount += count;
|
||||
}
|
||||
mOut->Close();
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsPump(nsIBufferInputStream* in,
|
||||
nsIBufferOutputStream* out)
|
||||
: mIn(in), mOut(out), mCount(0) {
|
||||
NS_INIT_REFCNT();
|
||||
}
|
||||
|
||||
virtual ~nsPump() {
|
||||
}
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIBufferInputStream> mIn;
|
||||
nsCOMPtr<nsIBufferOutputStream> mOut;
|
||||
PRUint32 mCount;
|
||||
};
|
||||
|
||||
NS_IMPL_ADDREF(nsPump);
|
||||
NS_IMPL_RELEASE(nsPump);
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPump::QueryInterface(REFNSIID aIID,
|
||||
void** aInstancePtr)
|
||||
{
|
||||
// not used in this test
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TestChainedPipes()
|
||||
{
|
||||
nsresult rv;
|
||||
printf("TestChainedPipes\n");
|
||||
|
||||
nsIBufferInputStream* in1;
|
||||
nsIBufferOutputStream* out1;
|
||||
rv = NS_NewPipe(&in1, &out1, nsnull, 20, 1999);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsIBufferInputStream* in2;
|
||||
nsIBufferOutputStream* out2;
|
||||
rv = NS_NewPipe(&in2, &out2, nsnull, 200, 401);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsIThread* thread;
|
||||
nsPump* pump = new nsPump(in1, out2);
|
||||
if (pump == nsnull) return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(pump);
|
||||
|
||||
rv = NS_NewThread(&thread, pump);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsIThread* receiverThread;
|
||||
nsReceiver* receiver = new nsReceiver(in2);
|
||||
if (receiver == nsnull) return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(receiver);
|
||||
|
||||
rv = NS_NewThread(&receiverThread, receiver);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
PRUint32 total = 0;
|
||||
for (PRUint32 i = 0; i < ITERATIONS; i++) {
|
||||
PRUint32 writeCount;
|
||||
char* buf = PR_smprintf("%d %s", i, kTestPattern);
|
||||
PRUint32 len = nsCRT::strlen(buf);
|
||||
len = len * rand() / RAND_MAX;
|
||||
len = PR_MAX(1, len);
|
||||
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);
|
||||
}
|
||||
printf("wrote total of %d bytes\n", total);
|
||||
rv = out1->Close();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
thread->Join();
|
||||
receiverThread->Join();
|
||||
|
||||
NS_RELEASE(thread);
|
||||
NS_RELEASE(pump);
|
||||
NS_RELEASE(receiverThread);
|
||||
NS_RELEASE(receiver);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void
|
||||
RunTests(PRUint32 segSize, PRUint32 segCount)
|
||||
{
|
||||
|
@ -327,6 +549,10 @@ main(int argc, char* argv[])
|
|||
return -1;
|
||||
}
|
||||
#endif
|
||||
rv = TestPipeObserver();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "TestPipeObserver failed");
|
||||
rv = TestChainedPipes();
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "TestChainedPipes failed");
|
||||
RunTests(16, 1);
|
||||
RunTests(4096, 16);
|
||||
return 0;
|
||||
|
|
Загрузка…
Ссылка в новой задаче