/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: NPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Netscape Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Pierre Phaneuf * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the NPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the NPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsIBuffer.h" #include "nsIThread.h" #include "nsIComponentManager.h" #include "nsIServiceManager.h" #include "nsAutoLock.h" #include "nsIPageManager.h" #include "nsCRT.h" #include "prprf.h" #include "prmem.h" #include "prinrval.h" #include PRBool gVerbose = PR_FALSE; class Reader : public nsIRunnable { public: NS_DECL_ISUPPORTS NS_IMETHOD Run() { nsresult rv; nsAutoCMonitor mon(this); char buf[100]; PRUint32 readCnt; const char* readBuf; rv = mReadBuffer->GetReadSegment(0, &readBuf, &readCnt); if (NS_FAILED(rv)) return rv; while (!(mDone && readCnt == 0)) { rv = mReadBuffer->Read(buf, 99, &readCnt); if (NS_FAILED(rv)) { printf("read failed\n"); return rv; } if (readCnt == 0) { if (mDone) break; mon.Notify(); // wake up writer mon.Wait(); // wait for more rv = mReadBuffer->GetReadSegment(0, &readBuf, &readCnt); if (NS_FAILED(rv)) return rv; } else { if (gVerbose) { buf[readCnt] = 0; printf(buf); } mBytesRead += readCnt; } } if (gVerbose) printf("reader done\n"); return rv; } Reader(nsIBuffer* readBuffer) : mReadBuffer(readBuffer), mBytesRead(0), mDone(PR_FALSE) { NS_INIT_ISUPPORTS(); NS_ADDREF(mReadBuffer); } virtual ~Reader() { NS_RELEASE(mReadBuffer); if (gVerbose) printf("bytes read = %d\n", mBytesRead); } void SetEOF() { mDone = PR_TRUE; } PRUint32 GetBytesRead() { return mBytesRead; } protected: nsIBuffer* mReadBuffer; PRUint32 mBytesRead; PRBool mDone; }; NS_IMPL_ISUPPORTS1(Reader, nsIRunnable) //////////////////////////////////////////////////////////////////////////////// #define ITERATIONS 20000 nsresult WriteMessages(nsIBuffer* buffer) { nsresult rv; nsIThread* thread; Reader* reader = new Reader(buffer); NS_ADDREF(reader); rv = NS_NewThread(&thread, reader, 0, PR_JOINABLE_THREAD); if (NS_FAILED(rv)) { printf("failed to create thread\n"); return rv; } char* mem = nsnull; char* buf = nsnull; PRUint32 total = 0; PRUint32 cnt = 0; PRUint32 bufLen = 0; PRIntervalTime start = PR_IntervalNow(); for (PRUint32 i = 0; i < ITERATIONS;) { if (bufLen == 0) { PR_FREEIF(mem); mem = PR_smprintf("%d. My hovercraft is full of eels.\n", i); buf = mem; NS_ASSERTION(buf, "out of memory"); bufLen = nsCRT::strlen(buf); i++; } rv = buffer->Write(buf, bufLen, &cnt); if (NS_FAILED(rv)) { printf("failed to write %d\n", i); return rv; } if (cnt == 0) { nsAutoCMonitor mon(reader); mon.Notify(); // wake up reader mon.Wait(); // and wait for reader to read all } else { total += cnt; buf += cnt; bufLen -= cnt; } } PR_FREEIF(mem); { reader->SetEOF(); nsAutoCMonitor mon(reader); mon.Notify(); // wake up reader } if (NS_FAILED(rv)) return rv; rv = thread->Join(); PRIntervalTime end = PR_IntervalNow(); if (NS_FAILED(rv)) return rv; printf("writer done: %d bytes %d ms\n", total, PR_IntervalToMilliseconds(end - start)); NS_ASSERTION(reader->GetBytesRead() == total, "didn't read everything"); NS_RELEASE(reader); NS_RELEASE(thread); NS_RELEASE(buffer); return NS_OK; } //////////////////////////////////////////////////////////////////////////////// nsresult TestMallocBuffers(PRUint32 growByPages, PRUint32 pageCount) { nsresult rv; nsIBuffer* buffer; printf("Malloc Buffer Test: %d pages, grow by %d pages\n", pageCount, growByPages); rv = NS_NewBuffer(&buffer, NS_PAGEMGR_PAGE_SIZE * growByPages, NS_PAGEMGR_PAGE_SIZE * pageCount, nsnull); if (NS_FAILED(rv)) { printf("failed to create buffer\n"); return rv; } rv = WriteMessages(buffer); return rv; } nsresult TestPageBuffers(PRUint32 growByPages, PRUint32 pageCount) { nsresult rv; nsIBuffer* buffer; printf("Page Buffer Test: %d pages, grow by %d pages\n", pageCount, growByPages); rv = NS_NewPageBuffer(&buffer, NS_PAGEMGR_PAGE_SIZE * growByPages, NS_PAGEMGR_PAGE_SIZE * pageCount, nsnull); if (NS_FAILED(rv)) { printf("failed to create buffer\n"); return rv; } rv = WriteMessages(buffer); return rv; } //////////////////////////////////////////////////////////////////////////////// void TestSearch(const char* delim, PRUint32 segDataSize) { nsresult rv; nsIBuffer* buffer; // need at least 2 segments to test boundary conditions: PRUint32 bufDataSize = segDataSize * 2; PRUint32 segSize = segDataSize + nsIBuffer::SEGMENT_OVERHEAD; PRUint32 bufSize = segSize * 2; rv = NS_NewBuffer(&buffer, segSize, bufSize, nsnull); NS_ASSERTION(NS_SUCCEEDED(rv), "NewBuffer failed"); PRUint32 i, j, amt; PRUint32 delimLen = nsCRT::strlen(delim); for (i = 0; i < bufDataSize; i++) { // first fill the buffer for (j = 0; j < i; j++) { rv = buffer->Write("-", 1, &amt); NS_ASSERTION(NS_SUCCEEDED(rv) && amt == 1, "Write failed"); } rv = buffer->Write(delim, delimLen, &amt); NS_ASSERTION(NS_SUCCEEDED(rv), "Write failed"); if (i + amt < bufDataSize) { for (j = i + amt; j < bufDataSize; j++) { rv = buffer->Write("+", 1, &amt); NS_ASSERTION(NS_SUCCEEDED(rv) && amt == 1, "Write failed"); } } // now search for the delimiter PRBool found; PRUint32 offset; rv = buffer->Search(delim, PR_FALSE, &found, &offset); NS_ASSERTION(NS_SUCCEEDED(rv), "Search failed"); // print the results char* bufferContents = new char[bufDataSize + 1]; rv = buffer->Read(bufferContents, bufDataSize, &amt); NS_ASSERTION(NS_SUCCEEDED(rv) && amt == bufDataSize, "Read failed"); bufferContents[bufDataSize] = '\0'; printf("Buffer: %s\nDelim: %s %s offset: %d\n", bufferContents, delim, (found ? "found" : "not found"), offset); } } //////////////////////////////////////////////////////////////////////////////// NS_METHOD FailingReader(void* closure, char* toRawSegment, PRUint32 fromOffset, PRUint32 count, PRUint32 *readCount) { nsresult* rv = (nsresult*)closure; *readCount = 0; return *rv; } nsresult TestWriteSegments(nsresult error) { nsresult rv; nsIBuffer* buffer; printf("WriteSegments Test: error %x\n", error); rv = NS_NewBuffer(&buffer, 10, 10, nsnull); if (NS_FAILED(rv)) { printf("failed to create buffer\n"); return rv; } PRUint32 writeCount; rv = buffer->WriteSegments(FailingReader, &error, 1, &writeCount); NS_ASSERTION(rv == error, "WriteSegments failed"); NS_RELEASE(buffer); return NS_OK; } //////////////////////////////////////////////////////////////////////////////// NS_METHOD FailingWriter(void* closure, const char* fromRawSegment, PRUint32 toOffset, PRUint32 count, PRUint32 *writeCount) { nsresult* rv = (nsresult*)closure; *writeCount = 0; return *rv; } nsresult TestReadSegments(nsresult error) { nsresult rv; nsIBuffer* buffer; printf("ReadSegments Test: error %x\n", error); rv = NS_NewBuffer(&buffer, 10, 10, nsnull); if (NS_FAILED(rv)) { printf("failed to create buffer\n"); return rv; } PRUint32 writeCount; rv = buffer->Write("x", 1, &writeCount); NS_ASSERTION(NS_SUCCEEDED(rv) && writeCount == 1, "Write failed"); PRUint32 readCount; rv = buffer->ReadSegments(FailingWriter, &error, 1, &readCount); NS_ASSERTION(rv == error, "ReadSegments failed"); NS_RELEASE(buffer); return NS_OK; } //////////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { nsresult rv; nsIServiceManager* servMgr; if (argc >= 2 && nsCRT::strcmp(argv[1], "-verbose") == 0) { gVerbose = PR_TRUE; } rv = NS_InitXPCOM2(&servMgr, NULL, NULL); if (NS_FAILED(rv)) return rv; rv = TestWriteSegments(NS_OK); NS_ASSERTION(NS_SUCCEEDED(rv), "TestWriteSegments failed"); rv = TestWriteSegments(NS_ERROR_FAILURE); NS_ASSERTION(NS_SUCCEEDED(rv), "TestWriteSegments failed"); rv = TestWriteSegments(NS_BASE_STREAM_CLOSED); NS_ASSERTION(NS_SUCCEEDED(rv), "TestWriteSegments failed"); rv = TestWriteSegments(NS_BASE_STREAM_WOULD_BLOCK); NS_ASSERTION(NS_SUCCEEDED(rv), "TestWriteSegments failed"); rv = TestReadSegments(NS_OK); NS_ASSERTION(NS_SUCCEEDED(rv), "TestReadSegments failed"); rv = TestReadSegments(NS_ERROR_FAILURE); NS_ASSERTION(NS_SUCCEEDED(rv), "TestReadSegments failed"); // rv = TestReadSegments(NS_BASE_STREAM_CLOSED); // NS_ASSERTION(NS_SUCCEEDED(rv), "TestReadSegments failed"); rv = TestReadSegments(NS_BASE_STREAM_WOULD_BLOCK); NS_ASSERTION(NS_SUCCEEDED(rv), "TestReadSegments failed"); rv = TestMallocBuffers(1, 1); NS_ASSERTION(NS_SUCCEEDED(rv), "TestMallocBuffers failed"); rv = TestPageBuffers(1, 1); NS_ASSERTION(NS_SUCCEEDED(rv), "TestPageBuffers failed"); rv = TestMallocBuffers(1, 10); NS_ASSERTION(NS_SUCCEEDED(rv), "TestMallocBuffers failed"); rv = TestPageBuffers(1, 10); NS_ASSERTION(NS_SUCCEEDED(rv), "TestPageBuffers failed"); rv = TestMallocBuffers(5, 10); NS_ASSERTION(NS_SUCCEEDED(rv), "TestMallocBuffers failed"); rv = TestPageBuffers(5, 10); NS_ASSERTION(NS_SUCCEEDED(rv), "TestPageBuffers failed"); TestSearch("foo", 8); TestSearch("bar", 6); TestSearch("baz", 2); return 0; } ////////////////////////////////////////////////////////////////////////////////