LCOV - code coverage report
Current view: directory - xpcom/io - nsPipe3.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 495 388 78.4 %
Date: 2012-06-02 Functions: 84 67 79.8 %

       1                 : /* ***** BEGIN LICENSE BLOCK *****
       2                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       3                 :  *
       4                 :  * The contents of this file are subject to the Mozilla Public License Version
       5                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       6                 :  * the License. You may obtain a copy of the License at
       7                 :  * http://www.mozilla.org/MPL/
       8                 :  *
       9                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      10                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      11                 :  * for the specific language governing rights and limitations under the
      12                 :  * License.
      13                 :  *
      14                 :  * The Original Code is Mozilla.
      15                 :  *
      16                 :  * The Initial Developer of the Original Code is
      17                 :  * Netscape Communications Corporation.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2002
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *   Darin Fisher <darin@netscape.com>
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      26                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : #include "mozilla/ReentrantMonitor.h"
      39                 : #include "nsIPipe.h"
      40                 : #include "nsIEventTarget.h"
      41                 : #include "nsISeekableStream.h"
      42                 : #include "nsIProgrammingLanguage.h"
      43                 : #include "nsSegmentedBuffer.h"
      44                 : #include "nsStreamUtils.h"
      45                 : #include "nsCOMPtr.h"
      46                 : #include "nsCRT.h"
      47                 : #include "prlog.h"
      48                 : #include "nsIClassInfoImpl.h"
      49                 : #include "nsAtomicRefcnt.h"
      50                 : #include "nsAlgorithm.h"
      51                 : 
      52                 : using namespace mozilla;
      53                 : 
      54                 : #if defined(PR_LOGGING)
      55                 : //
      56                 : // set NSPR_LOG_MODULES=nsPipe:5
      57                 : //
      58            1464 : static PRLogModuleInfo *gPipeLog = PR_NewLogModule("nsPipe");
      59                 : #define LOG(args) PR_LOG(gPipeLog, PR_LOG_DEBUG, args)
      60                 : #else
      61                 : #define LOG(args)
      62                 : #endif
      63                 : 
      64                 : #define DEFAULT_SEGMENT_SIZE  4096
      65                 : #define DEFAULT_SEGMENT_COUNT 16
      66                 : 
      67                 : class nsPipe;
      68                 : class nsPipeEvents;
      69                 : class nsPipeInputStream;
      70                 : class nsPipeOutputStream;
      71                 : 
      72                 : //-----------------------------------------------------------------------------
      73                 : 
      74                 : // this class is used to delay notifications until the end of a particular
      75                 : // scope.  it helps avoid the complexity of issuing callbacks while inside
      76                 : // a critical section.
      77                 : class nsPipeEvents
      78                 : {
      79                 : public:
      80          211781 :     nsPipeEvents() { }
      81                 :    ~nsPipeEvents();
      82                 : 
      83           28604 :     inline void NotifyInputReady(nsIAsyncInputStream *stream,
      84                 :                                  nsIInputStreamCallback *callback)
      85                 :     {
      86           28604 :         NS_ASSERTION(!mInputCallback, "already have an input event");
      87           28604 :         mInputStream = stream;
      88           28604 :         mInputCallback = callback;
      89           28604 :     }
      90                 : 
      91           12854 :     inline void NotifyOutputReady(nsIAsyncOutputStream *stream,
      92                 :                                   nsIOutputStreamCallback *callback)
      93                 :     {
      94           12854 :         NS_ASSERTION(!mOutputCallback, "already have an output event");
      95           12854 :         mOutputStream = stream;
      96           12854 :         mOutputCallback = callback;
      97           12854 :     }
      98                 : 
      99                 : private:
     100                 :     nsCOMPtr<nsIAsyncInputStream>     mInputStream;
     101                 :     nsCOMPtr<nsIInputStreamCallback>  mInputCallback;
     102                 :     nsCOMPtr<nsIAsyncOutputStream>    mOutputStream;
     103                 :     nsCOMPtr<nsIOutputStreamCallback> mOutputCallback;
     104                 : };
     105                 : 
     106                 : //-----------------------------------------------------------------------------
     107                 : 
     108                 : // the input end of a pipe (allocated as a member of the pipe).
     109                 : class nsPipeInputStream : public nsIAsyncInputStream
     110                 :                         , public nsISeekableStream
     111                 :                         , public nsISearchableInputStream
     112                 :                         , public nsIClassInfo
     113           18617 : {
     114                 : public:
     115                 :     // since this class will be allocated as a member of the pipe, we do not
     116                 :     // need our own ref count.  instead, we share the lifetime (the ref count)
     117                 :     // of the entire pipe.  this macro is just convenience since it does not
     118                 :     // declare a mRefCount variable; however, don't let the name fool you...
     119                 :     // we are not inheriting from nsPipe ;-)
     120                 :     NS_DECL_ISUPPORTS_INHERITED
     121                 : 
     122                 :     NS_DECL_NSIINPUTSTREAM
     123                 :     NS_DECL_NSIASYNCINPUTSTREAM
     124                 :     NS_DECL_NSISEEKABLESTREAM
     125                 :     NS_DECL_NSISEARCHABLEINPUTSTREAM
     126                 :     NS_DECL_NSICLASSINFO
     127                 : 
     128           18632 :     nsPipeInputStream(nsPipe *pipe)
     129                 :         : mPipe(pipe)
     130                 :         , mReaderRefCnt(0)
     131                 :         , mLogicalOffset(0)
     132                 :         , mBlocking(true)
     133                 :         , mBlocked(false)
     134                 :         , mAvailable(0)
     135           18632 :         , mCallbackFlags(0)
     136           18632 :         { }
     137                 : 
     138                 :     nsresult Fill();
     139           18631 :     void SetNonBlocking(bool aNonBlocking) { mBlocking = !aNonBlocking; }
     140                 : 
     141           18471 :     PRUint32 Available() { return mAvailable; }
     142           22321 :     void     ReduceAvailable(PRUint32 avail) { mAvailable -= avail; }
     143                 : 
     144                 :     // synchronously wait for the pipe to become readable.
     145                 :     nsresult Wait();
     146                 : 
     147                 :     // these functions return true to indicate that the pipe's monitor should
     148                 :     // be notified, to wake up a blocked reader if any.
     149                 :     bool     OnInputReadable(PRUint32 bytesWritten, nsPipeEvents &);
     150                 :     bool     OnInputException(nsresult, nsPipeEvents &);
     151                 : 
     152                 : private:
     153                 :     nsPipe                        *mPipe;
     154                 : 
     155                 :     // separate refcnt so that we know when to close the consumer
     156                 :     nsrefcnt                       mReaderRefCnt;
     157                 :     PRInt64                        mLogicalOffset;
     158                 :     bool                           mBlocking;
     159                 : 
     160                 :     // these variables can only be accessed while inside the pipe's monitor
     161                 :     bool                           mBlocked;
     162                 :     PRUint32                       mAvailable;
     163                 :     nsCOMPtr<nsIInputStreamCallback> mCallback;
     164                 :     PRUint32                       mCallbackFlags;
     165                 : };
     166                 : 
     167                 : //-----------------------------------------------------------------------------
     168                 : 
     169                 : // the output end of a pipe (allocated as a member of the pipe).
     170                 : class nsPipeOutputStream : public nsIAsyncOutputStream
     171                 :                          , public nsIClassInfo
     172           18617 : {
     173                 : public:
     174                 :     // since this class will be allocated as a member of the pipe, we do not
     175                 :     // need our own ref count.  instead, we share the lifetime (the ref count)
     176                 :     // of the entire pipe.  this macro is just convenience since it does not
     177                 :     // declare a mRefCount variable; however, don't let the name fool you...
     178                 :     // we are not inheriting from nsPipe ;-)
     179                 :     NS_DECL_ISUPPORTS_INHERITED
     180                 : 
     181                 :     NS_DECL_NSIOUTPUTSTREAM
     182                 :     NS_DECL_NSIASYNCOUTPUTSTREAM
     183                 :     NS_DECL_NSICLASSINFO
     184                 : 
     185           18632 :     nsPipeOutputStream(nsPipe *pipe)
     186                 :         : mPipe(pipe)
     187                 :         , mWriterRefCnt(0)
     188                 :         , mLogicalOffset(0)
     189                 :         , mBlocking(true)
     190                 :         , mBlocked(false)
     191                 :         , mWritable(true)
     192           18632 :         , mCallbackFlags(0)
     193           18632 :         { }
     194                 : 
     195           18631 :     void SetNonBlocking(bool aNonBlocking) { mBlocking = !aNonBlocking; }
     196             105 :     void SetWritable(bool writable) { mWritable = writable; }
     197                 : 
     198                 :     // synchronously wait for the pipe to become writable.
     199                 :     nsresult Wait();
     200                 : 
     201                 :     // these functions return true to indicate that the pipe's monitor should
     202                 :     // be notified, to wake up a blocked writer if any.
     203                 :     bool     OnOutputWritable(nsPipeEvents &);
     204                 :     bool     OnOutputException(nsresult, nsPipeEvents &);
     205                 : 
     206                 : private:
     207                 :     nsPipe                         *mPipe;
     208                 : 
     209                 :     // separate refcnt so that we know when to close the producer
     210                 :     nsrefcnt                        mWriterRefCnt;
     211                 :     PRInt64                         mLogicalOffset;
     212                 :     bool                            mBlocking;
     213                 : 
     214                 :     // these variables can only be accessed while inside the pipe's monitor
     215                 :     bool                            mBlocked;
     216                 :     bool                            mWritable;
     217                 :     nsCOMPtr<nsIOutputStreamCallback> mCallback;
     218                 :     PRUint32                        mCallbackFlags;
     219                 : };
     220                 : 
     221                 : //-----------------------------------------------------------------------------
     222                 : 
     223                 : class nsPipe : public nsIPipe
     224                 : {
     225                 : public:
     226                 :     friend class nsPipeInputStream;
     227                 :     friend class nsPipeOutputStream;
     228                 : 
     229                 :     NS_DECL_ISUPPORTS
     230                 :     NS_DECL_NSIPIPE
     231                 : 
     232                 :     // nsPipe methods:
     233                 :     nsPipe();
     234                 : 
     235                 : private:
     236                 :     ~nsPipe();
     237                 : 
     238                 : public:
     239                 :     //
     240                 :     // methods below may only be called while inside the pipe's monitor
     241                 :     //
     242                 : 
     243                 :     void PeekSegment(PRUint32 n, char *&cursor, char *&limit);
     244                 : 
     245                 :     //
     246                 :     // methods below may be called while outside the pipe's monitor
     247                 :     //
     248                 :  
     249                 :     nsresult GetReadSegment(const char *&segment, PRUint32 &segmentLen);
     250                 :     void     AdvanceReadCursor(PRUint32 count);
     251                 : 
     252                 :     nsresult GetWriteSegment(char *&segment, PRUint32 &segmentLen);
     253                 :     void     AdvanceWriteCursor(PRUint32 count);
     254                 : 
     255                 :     void     OnPipeException(nsresult reason, bool outputOnly = false);
     256                 : 
     257                 : protected:
     258                 :     // We can't inherit from both nsIInputStream and nsIOutputStream
     259                 :     // because they collide on their Close method. Consequently we nest their
     260                 :     // implementations to avoid the extra object allocation.
     261                 :     nsPipeInputStream   mInput;
     262                 :     nsPipeOutputStream  mOutput;
     263                 : 
     264                 :     ReentrantMonitor    mReentrantMonitor;
     265                 :     nsSegmentedBuffer   mBuffer;
     266                 : 
     267                 :     char*               mReadCursor;
     268                 :     char*               mReadLimit;
     269                 : 
     270                 :     PRInt32             mWriteSegment;
     271                 :     char*               mWriteCursor;
     272                 :     char*               mWriteLimit;
     273                 : 
     274                 :     nsresult            mStatus;
     275                 :     bool                mInited;
     276                 : };
     277                 : 
     278                 : //
     279                 : // NOTES on buffer architecture:
     280                 : //
     281                 : //       +-----------------+ - - mBuffer.GetSegment(0)
     282                 : //       |                 |
     283                 : //       + - - - - - - - - + - - mReadCursor
     284                 : //       |/////////////////|
     285                 : //       |/////////////////|
     286                 : //       |/////////////////|
     287                 : //       |/////////////////|
     288                 : //       +-----------------+ - - mReadLimit
     289                 : //                |
     290                 : //       +-----------------+
     291                 : //       |/////////////////|
     292                 : //       |/////////////////|
     293                 : //       |/////////////////|
     294                 : //       |/////////////////|
     295                 : //       |/////////////////|
     296                 : //       |/////////////////|
     297                 : //       +-----------------+
     298                 : //                |
     299                 : //       +-----------------+ - - mBuffer.GetSegment(mWriteSegment)
     300                 : //       |/////////////////|
     301                 : //       |/////////////////|
     302                 : //       |/////////////////|
     303                 : //       + - - - - - - - - + - - mWriteCursor
     304                 : //       |                 |
     305                 : //       |                 |
     306                 : //       +-----------------+ - - mWriteLimit
     307                 : //
     308                 : // (shaded region contains data)
     309                 : //
     310                 : // NOTE: on some systems (notably OS/2), the heap allocator uses an arena for
     311                 : // small allocations (e.g., 64 byte allocations).  this means that buffers may
     312                 : // be allocated back-to-back.  in the diagram above, for example, mReadLimit
     313                 : // would actually be pointing at the beginning of the next segment.  when
     314                 : // making changes to this file, please keep this fact in mind.
     315                 : //
     316                 : 
     317                 : //-----------------------------------------------------------------------------
     318                 : // nsPipe methods:
     319                 : //-----------------------------------------------------------------------------
     320                 : 
     321           18632 : nsPipe::nsPipe()
     322                 :     : mInput(this)
     323                 :     , mOutput(this)
     324                 :     , mReentrantMonitor("nsPipe.mReentrantMonitor")
     325                 :     , mReadCursor(nsnull)
     326                 :     , mReadLimit(nsnull)
     327                 :     , mWriteSegment(-1)
     328                 :     , mWriteCursor(nsnull)
     329                 :     , mWriteLimit(nsnull)
     330                 :     , mStatus(NS_OK)
     331           18632 :     , mInited(false)
     332                 : {
     333           18632 : }
     334                 : 
     335           18617 : nsPipe::~nsPipe()
     336                 : {
     337           18617 : }
     338                 : 
     339         1131883 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsPipe, nsIPipe)
     340                 : 
     341                 : NS_IMETHODIMP
     342           18631 : nsPipe::Init(bool nonBlockingIn,
     343                 :              bool nonBlockingOut,
     344                 :              PRUint32 segmentSize,
     345                 :              PRUint32 segmentCount,
     346                 :              nsIMemory *segmentAlloc)
     347                 : {
     348           18631 :     mInited = true;
     349                 : 
     350           18631 :     if (segmentSize == 0)
     351            5852 :         segmentSize = DEFAULT_SEGMENT_SIZE;
     352           18631 :     if (segmentCount == 0)
     353              92 :         segmentCount = DEFAULT_SEGMENT_COUNT;
     354                 : 
     355                 :     // protect against overflow
     356           18631 :     PRUint32 maxCount = PRUint32(-1) / segmentSize;
     357           18631 :     if (segmentCount > maxCount)
     358            8728 :         segmentCount = maxCount;
     359                 : 
     360           18631 :     nsresult rv = mBuffer.Init(segmentSize, segmentSize * segmentCount, segmentAlloc);
     361           18631 :     if (NS_FAILED(rv))
     362               0 :         return rv;
     363                 : 
     364           18631 :     mInput.SetNonBlocking(nonBlockingIn);
     365           18631 :     mOutput.SetNonBlocking(nonBlockingOut);
     366           18631 :     return NS_OK;
     367                 : }
     368                 : 
     369                 : NS_IMETHODIMP
     370           18643 : nsPipe::GetInputStream(nsIAsyncInputStream **aInputStream)
     371                 : {
     372           18643 :     NS_ADDREF(*aInputStream = &mInput);
     373           18643 :     return NS_OK;
     374                 : }
     375                 : 
     376                 : NS_IMETHODIMP
     377           21532 : nsPipe::GetOutputStream(nsIAsyncOutputStream **aOutputStream)
     378                 : {
     379           21532 :     NS_ENSURE_TRUE(mInited, NS_ERROR_NOT_INITIALIZED);
     380           21531 :     NS_ADDREF(*aOutputStream = &mOutput);
     381           21531 :     return NS_OK;
     382                 : }
     383                 : 
     384                 : void
     385               0 : nsPipe::PeekSegment(PRUint32 index, char *&cursor, char *&limit)
     386                 : {
     387               0 :     if (index == 0) {
     388               0 :         NS_ASSERTION(!mReadCursor || mBuffer.GetSegmentCount(), "unexpected state");
     389               0 :         cursor = mReadCursor;
     390               0 :         limit = mReadLimit;
     391                 :     }
     392                 :     else {
     393               0 :         PRUint32 numSegments = mBuffer.GetSegmentCount();
     394               0 :         if (index >= numSegments)
     395               0 :             cursor = limit = nsnull;
     396                 :         else {
     397               0 :             cursor = mBuffer.GetSegment(index);
     398               0 :             if (mWriteSegment == (PRInt32) index)
     399               0 :                 limit = mWriteCursor;
     400                 :             else
     401               0 :                 limit = cursor + mBuffer.GetSegmentSize();
     402                 :         }
     403                 :     }
     404               0 : }
     405                 : 
     406                 : nsresult
     407           41175 : nsPipe::GetReadSegment(const char *&segment, PRUint32 &segmentLen)
     408                 : {
     409           82350 :     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     410                 : 
     411           41175 :     if (mReadCursor == mReadLimit)
     412           18810 :         return NS_FAILED(mStatus) ? mStatus : NS_BASE_STREAM_WOULD_BLOCK;
     413                 : 
     414           22365 :     segment    = mReadCursor;
     415           22365 :     segmentLen = mReadLimit - mReadCursor;
     416           22365 :     return NS_OK;
     417                 : }
     418                 : 
     419                 : void
     420           22321 : nsPipe::AdvanceReadCursor(PRUint32 bytesRead)
     421                 : {
     422           22321 :     NS_ASSERTION(bytesRead, "don't call if no bytes read");
     423                 : 
     424           44642 :     nsPipeEvents events;
     425                 :     {
     426           44642 :         ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     427                 : 
     428           22321 :         LOG(("III advancing read cursor by %u\n", bytesRead));
     429           22321 :         NS_ASSERTION(bytesRead <= mBuffer.GetSegmentSize(), "read too much");
     430                 : 
     431           22321 :         mReadCursor += bytesRead;
     432           22321 :         NS_ASSERTION(mReadCursor <= mReadLimit, "read cursor exceeds limit");
     433                 : 
     434           22321 :         mInput.ReduceAvailable(bytesRead);
     435                 : 
     436           22321 :         if (mReadCursor == mReadLimit) {
     437                 :             // we've reached the limit of how much we can read from this segment.
     438                 :             // if at the end of this segment, then we must discard this segment.
     439                 : 
     440                 :             // if still writing in this segment then bail because we're not done
     441                 :             // with the segment and have to wait for now...
     442           21282 :             if (mWriteSegment == 0 && mWriteLimit > mWriteCursor) {
     443           20170 :                 NS_ASSERTION(mReadLimit == mWriteCursor, "unexpected state");
     444                 :                 return;
     445                 :             }
     446                 : 
     447                 :             // shift write segment index (-1 indicates an empty buffer).
     448            1112 :             --mWriteSegment;
     449                 : 
     450                 :             // done with this segment
     451            1112 :             mBuffer.DeleteFirstSegment();
     452            1112 :             LOG(("III deleting first segment\n"));
     453                 : 
     454            1112 :             if (mWriteSegment == -1) {
     455                 :                 // buffer is completely empty
     456             132 :                 mReadCursor = nsnull;
     457             132 :                 mReadLimit = nsnull;
     458             132 :                 mWriteCursor = nsnull;
     459             132 :                 mWriteLimit = nsnull;
     460                 :             }
     461                 :             else {
     462                 :                 // advance read cursor and limit to next buffer segment
     463             980 :                 mReadCursor = mBuffer.GetSegment(0);
     464             980 :                 if (mWriteSegment == 0)
     465             203 :                     mReadLimit = mWriteCursor;
     466                 :                 else
     467             777 :                     mReadLimit = mReadCursor + mBuffer.GetSegmentSize();
     468                 :             }
     469                 : 
     470                 :             // we've free'd up a segment, so notify output stream that pipe has
     471                 :             // room for a new segment.
     472            1112 :             if (mOutput.OnOutputWritable(events))
     473               0 :                 mon.Notify();
     474                 :         }
     475                 :     }
     476                 : }
     477                 : 
     478                 : nsresult
     479           80507 : nsPipe::GetWriteSegment(char *&segment, PRUint32 &segmentLen)
     480                 : {
     481          161014 :     ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     482                 : 
     483           80507 :     if (NS_FAILED(mStatus))
     484              89 :         return mStatus;
     485                 : 
     486                 :     // write cursor and limit may both be null indicating an empty buffer.
     487           80418 :     if (mWriteCursor == mWriteLimit) {
     488           17045 :         char *seg = mBuffer.AppendNewSegment();
     489                 :         // pipe is full
     490           17045 :         if (seg == nsnull)
     491              31 :             return NS_BASE_STREAM_WOULD_BLOCK;
     492           17014 :         LOG(("OOO appended new segment\n"));
     493           17014 :         mWriteCursor = seg;
     494           17014 :         mWriteLimit = mWriteCursor + mBuffer.GetSegmentSize();
     495           17014 :         ++mWriteSegment;
     496                 :     }
     497                 : 
     498                 :     // make sure read cursor is initialized
     499           80387 :     if (mReadCursor == nsnull) {
     500           15998 :         NS_ASSERTION(mWriteSegment == 0, "unexpected null read cursor");
     501           15998 :         mReadCursor = mReadLimit = mWriteCursor;
     502                 :     }
     503                 : 
     504                 :     // check to see if we can roll-back our read and write cursors to the 
     505                 :     // beginning of the current/first segment.  this is purely an optimization.
     506           80387 :     if (mReadCursor == mWriteCursor && mWriteSegment == 0) {
     507           28687 :         char *head = mBuffer.GetSegment(0);
     508           28687 :         LOG(("OOO rolling back write cursor %u bytes\n", mWriteCursor - head));
     509           28687 :         mWriteCursor = mReadCursor = mReadLimit = head;
     510                 :     }
     511                 : 
     512           80387 :     segment    = mWriteCursor;
     513           80387 :     segmentLen = mWriteLimit - mWriteCursor;
     514           80387 :     return NS_OK;
     515                 : }
     516                 : 
     517                 : void
     518           72083 : nsPipe::AdvanceWriteCursor(PRUint32 bytesWritten)
     519                 : {
     520           72083 :     NS_ASSERTION(bytesWritten, "don't call if no bytes written");
     521                 : 
     522          144166 :     nsPipeEvents events;
     523                 :     {
     524          144166 :         ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     525                 : 
     526           72083 :         LOG(("OOO advancing write cursor by %u\n", bytesWritten));
     527                 : 
     528           72083 :         char *newWriteCursor = mWriteCursor + bytesWritten;
     529           72083 :         NS_ASSERTION(newWriteCursor <= mWriteLimit, "write cursor exceeds limit");
     530                 : 
     531                 :         // update read limit if reading in the same segment
     532           72083 :         if (mWriteSegment == 0 && mReadLimit == mWriteCursor)
     533           21875 :             mReadLimit = newWriteCursor;
     534                 : 
     535           72083 :         mWriteCursor = newWriteCursor;
     536                 : 
     537                 :         // The only way mReadCursor == mWriteCursor is if:
     538                 :         //
     539                 :         // - mReadCursor is at the start of a segment (which, based on how
     540                 :         //   nsSegmentedBuffer works, means that this segment is the "first"
     541                 :         //   segment)
     542                 :         // - mWriteCursor points at the location past the end of the current
     543                 :         //   write segment (so the current write filled the current write
     544                 :         //   segment, so we've incremented mWriteCursor to point past the end
     545                 :         //   of it)
     546                 :         // - the segment to which data has just been written is located
     547                 :         //   exactly one segment's worth of bytes before the first segment
     548                 :         //   where mReadCursor is located
     549                 :         //
     550                 :         // Consequently, the byte immediately after the end of the current
     551                 :         // write segment is the first byte of the first segment, so
     552                 :         // mReadCursor == mWriteCursor.  (Another way to think about this is
     553                 :         // to consider the buffer architecture diagram above, but consider it
     554                 :         // with an arena allocator which allocates from the *end* of the
     555                 :         // arena to the *beginning* of the arena.)
     556           72083 :         NS_ASSERTION(mReadCursor != mWriteCursor ||
     557                 :                      (mBuffer.GetSegment(0) == mReadCursor &&
     558                 :                       mWriteCursor == mWriteLimit),
     559                 :                      "read cursor is bad");
     560                 : 
     561                 :         // update the writable flag on the output stream
     562           72083 :         if (mWriteCursor == mWriteLimit) {
     563            1148 :             if (mBuffer.GetSize() >= mBuffer.GetMaxSize())
     564             105 :                 mOutput.SetWritable(false);
     565                 :         }
     566                 : 
     567                 :         // notify input stream that pipe now contains additional data
     568           72083 :         if (mInput.OnInputReadable(bytesWritten, events))
     569               0 :             mon.Notify();
     570                 :     }
     571           72083 : }
     572                 : 
     573                 : void
     574           66927 : nsPipe::OnPipeException(nsresult reason, bool outputOnly)
     575                 : {
     576           66927 :     LOG(("PPP nsPipe::OnPipeException [reason=%x output-only=%d]\n",
     577                 :         reason, outputOnly));
     578                 : 
     579          133854 :     nsPipeEvents events;
     580                 :     {
     581          133854 :         ReentrantMonitorAutoEnter mon(mReentrantMonitor);
     582                 : 
     583                 :         // if we've already hit an exception, then ignore this one.
     584           66927 :         if (NS_FAILED(mStatus))
     585                 :             return;
     586                 : 
     587           18617 :         mStatus = reason;
     588                 : 
     589                 :         // an output-only exception applies to the input end if the pipe has
     590                 :         // zero bytes available.
     591           18617 :         if (outputOnly && !mInput.Available())
     592            9855 :             outputOnly = false;
     593                 : 
     594           18617 :         if (!outputOnly)
     595           10001 :             if (mInput.OnInputException(reason, events))
     596               0 :                 mon.Notify();
     597                 : 
     598           18617 :         if (mOutput.OnOutputException(reason, events))
     599               0 :             mon.Notify();
     600                 :     }
     601                 : }
     602                 : 
     603                 : //-----------------------------------------------------------------------------
     604                 : // nsPipeEvents methods:
     605                 : //-----------------------------------------------------------------------------
     606                 : 
     607          423562 : nsPipeEvents::~nsPipeEvents()
     608                 : {
     609                 :     // dispatch any pending events
     610                 : 
     611          211781 :     if (mInputCallback) {
     612           28604 :         mInputCallback->OnInputStreamReady(mInputStream);
     613           28604 :         mInputCallback = 0;
     614           28604 :         mInputStream = 0;
     615                 :     }
     616          211781 :     if (mOutputCallback) {
     617           12854 :         mOutputCallback->OnOutputStreamReady(mOutputStream);
     618           12854 :         mOutputCallback = 0;
     619           12854 :         mOutputStream = 0;
     620                 :     }
     621          211781 : }
     622                 : 
     623                 : //-----------------------------------------------------------------------------
     624                 : // nsPipeInputStream methods:
     625                 : //-----------------------------------------------------------------------------
     626                 : 
     627          317208 : NS_IMPL_QUERY_INTERFACE5(nsPipeInputStream,
     628                 :                          nsIInputStream,
     629                 :                          nsIAsyncInputStream,
     630                 :                          nsISeekableStream,
     631                 :                          nsISearchableInputStream,
     632                 :                          nsIClassInfo)
     633                 : 
     634           13029 : NS_IMPL_CI_INTERFACE_GETTER4(nsPipeInputStream,
     635                 :                              nsIInputStream,
     636                 :                              nsIAsyncInputStream,
     637                 :                              nsISeekableStream,
     638           13029 :                              nsISearchableInputStream)
     639                 : 
     640           39139 : NS_IMPL_THREADSAFE_CI(nsPipeInputStream)
     641                 : 
     642                 : nsresult
     643               0 : nsPipeInputStream::Wait()
     644                 : {
     645               0 :     NS_ASSERTION(mBlocking, "wait on non-blocking pipe input stream");
     646                 : 
     647               0 :     ReentrantMonitorAutoEnter mon(mPipe->mReentrantMonitor);
     648                 : 
     649               0 :     while (NS_SUCCEEDED(mPipe->mStatus) && (mAvailable == 0)) {
     650               0 :         LOG(("III pipe input: waiting for data\n"));
     651                 : 
     652               0 :         mBlocked = true;
     653               0 :         mon.Wait();
     654               0 :         mBlocked = false;
     655                 : 
     656               0 :         LOG(("III pipe input: woke up [pipe-status=%x available=%u]\n",
     657                 :             mPipe->mStatus, mAvailable));
     658                 :     }
     659                 : 
     660               0 :     return mPipe->mStatus == NS_BASE_STREAM_CLOSED ? NS_OK : mPipe->mStatus;
     661                 : }
     662                 : 
     663                 : bool
     664           72083 : nsPipeInputStream::OnInputReadable(PRUint32 bytesWritten, nsPipeEvents &events)
     665                 : {
     666           72083 :     bool result = false;
     667                 : 
     668           72083 :     mAvailable += bytesWritten;
     669                 : 
     670           72083 :     if (mCallback && !(mCallbackFlags & WAIT_CLOSURE_ONLY)) {
     671           10634 :         events.NotifyInputReady(this, mCallback);
     672           10634 :         mCallback = 0;
     673           10634 :         mCallbackFlags = 0;
     674                 :     }
     675           61449 :     else if (mBlocked)
     676               0 :         result = true;
     677                 : 
     678           72083 :     return result;
     679                 : }
     680                 : 
     681                 : bool
     682           10001 : nsPipeInputStream::OnInputException(nsresult reason, nsPipeEvents &events)
     683                 : {
     684           10001 :     LOG(("nsPipeInputStream::OnInputException [this=%x reason=%x]\n",
     685                 :         this, reason));
     686                 : 
     687           10001 :     bool result = false;
     688                 : 
     689           10001 :     NS_ASSERTION(NS_FAILED(reason), "huh? successful exception");
     690                 : 
     691                 :     // force count of available bytes to zero.
     692           10001 :     mAvailable = 0;
     693                 : 
     694           10001 :     if (mCallback) {
     695            3475 :         events.NotifyInputReady(this, mCallback);
     696            3475 :         mCallback = 0;
     697            3475 :         mCallbackFlags = 0;
     698                 :     }
     699            6526 :     else if (mBlocked)
     700               0 :         result = true;
     701                 : 
     702           10001 :     return result;
     703                 : }
     704                 : 
     705                 : NS_IMETHODIMP_(nsrefcnt)
     706          308164 : nsPipeInputStream::AddRef(void)
     707                 : {
     708          308164 :     NS_AtomicIncrementRefcnt(mReaderRefCnt);
     709          308164 :     return mPipe->AddRef();
     710                 : }
     711                 : 
     712                 : NS_IMETHODIMP_(nsrefcnt)
     713          308134 : nsPipeInputStream::Release(void)
     714                 : {
     715          308134 :     if (NS_AtomicDecrementRefcnt(mReaderRefCnt) == 0)
     716           18616 :         Close();
     717          308134 :     return mPipe->Release();
     718                 : }
     719                 : 
     720                 : NS_IMETHODIMP
     721           31039 : nsPipeInputStream::CloseWithStatus(nsresult reason)
     722                 : {
     723           31039 :     LOG(("III CloseWithStatus [this=%x reason=%x]\n", this, reason));
     724                 : 
     725           31039 :     if (NS_SUCCEEDED(reason))
     726            8259 :         reason = NS_BASE_STREAM_CLOSED;
     727                 : 
     728           31039 :     mPipe->OnPipeException(reason);
     729           31039 :     return NS_OK;
     730                 : }
     731                 : 
     732                 : NS_IMETHODIMP
     733           22235 : nsPipeInputStream::Close()
     734                 : {
     735           22235 :     return CloseWithStatus(NS_BASE_STREAM_CLOSED);
     736                 : }
     737                 : 
     738                 : NS_IMETHODIMP
     739           31486 : nsPipeInputStream::Available(PRUint32 *result)
     740                 : {
     741           62972 :     ReentrantMonitorAutoEnter mon(mPipe->mReentrantMonitor);
     742                 : 
     743                 :     // return error if pipe closed
     744           31486 :     if (!mAvailable && NS_FAILED(mPipe->mStatus))
     745            9024 :         return mPipe->mStatus;
     746                 : 
     747           22462 :     *result = mAvailable;
     748           22462 :     return NS_OK;
     749                 : }
     750                 : 
     751                 : NS_IMETHODIMP
     752           34372 : nsPipeInputStream::ReadSegments(nsWriteSegmentFun writer, 
     753                 :                                 void *closure,  
     754                 :                                 PRUint32 count,
     755                 :                                 PRUint32 *readCount)
     756                 : {
     757           34372 :     LOG(("III ReadSegments [this=%x count=%u]\n", this, count));
     758                 : 
     759           34372 :     nsresult rv = NS_OK;
     760                 : 
     761                 :     const char *segment;
     762                 :     PRUint32 segmentLen;
     763                 : 
     764           34372 :     *readCount = 0;
     765           91109 :     while (count) {
     766           41175 :         rv = mPipe->GetReadSegment(segment, segmentLen);
     767           41175 :         if (NS_FAILED(rv)) {
     768                 :             // ignore this error if we've already read something.
     769           18810 :             if (*readCount > 0) {
     770            6460 :                 rv = NS_OK;
     771            6460 :                 break;
     772                 :             }
     773           12350 :             if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
     774                 :                 // pipe is empty
     775            9261 :                 if (!mBlocking)
     776            9261 :                     break;
     777                 :                 // wait for some data to be written to the pipe
     778               0 :                 rv = Wait();
     779               0 :                 if (NS_SUCCEEDED(rv))
     780               0 :                     continue;
     781                 :             }
     782                 :             // ignore this error, just return.
     783            3089 :             if (rv == NS_BASE_STREAM_CLOSED) {
     784            3089 :                 rv = NS_OK;
     785            3089 :                 break;
     786                 :             }
     787               0 :             mPipe->OnPipeException(rv);
     788               0 :             break;
     789                 :         }
     790                 : 
     791                 :         // read no more than count
     792           22365 :         if (segmentLen > count)
     793            1038 :             segmentLen = count;
     794                 : 
     795           22365 :         PRUint32 writeCount, originalLen = segmentLen;
     796           67051 :         while (segmentLen) {
     797           22370 :             writeCount = 0;
     798                 : 
     799           22370 :             rv = writer(this, closure, segment, *readCount, segmentLen, &writeCount);
     800                 : 
     801           22370 :             if (NS_FAILED(rv) || writeCount == 0) {
     802              49 :                 count = 0;
     803                 :                 // any errors returned from the writer end here: do not
     804                 :                 // propagate to the caller of ReadSegments.
     805              49 :                 rv = NS_OK;
     806              49 :                 break;
     807                 :             }
     808                 : 
     809           22321 :             NS_ASSERTION(writeCount <= segmentLen, "wrote more than expected");
     810           22321 :             segment += writeCount;
     811           22321 :             segmentLen -= writeCount;
     812           22321 :             count -= writeCount;
     813           22321 :             *readCount += writeCount;
     814           22321 :             mLogicalOffset += writeCount;
     815                 :         }
     816                 : 
     817           22365 :         if (segmentLen < originalLen)
     818           22321 :             mPipe->AdvanceReadCursor(originalLen - segmentLen);
     819                 :     }
     820                 : 
     821           34372 :     return rv;
     822                 : }
     823                 : 
     824                 : NS_IMETHODIMP
     825           15057 : nsPipeInputStream::Read(char* toBuf, PRUint32 bufLen, PRUint32 *readCount)
     826                 : {
     827           15057 :     return ReadSegments(NS_CopySegmentToBuffer, toBuf, bufLen, readCount);
     828                 : }
     829                 : 
     830                 : NS_IMETHODIMP
     831            3204 : nsPipeInputStream::IsNonBlocking(bool *aNonBlocking)
     832                 : {
     833            3204 :     *aNonBlocking = !mBlocking;
     834            3204 :     return NS_OK;
     835                 : }
     836                 : 
     837                 : NS_IMETHODIMP
     838           28640 : nsPipeInputStream::AsyncWait(nsIInputStreamCallback *callback,
     839                 :                              PRUint32 flags,
     840                 :                              PRUint32 requestedCount,
     841                 :                              nsIEventTarget *target)
     842                 : {
     843           28640 :     LOG(("III AsyncWait [this=%x]\n", this));
     844                 : 
     845           57280 :     nsPipeEvents pipeEvents;
     846                 :     {
     847           57280 :         ReentrantMonitorAutoEnter mon(mPipe->mReentrantMonitor);
     848                 : 
     849                 :         // replace a pending callback
     850           28640 :         mCallback = 0;
     851           28640 :         mCallbackFlags = 0;
     852                 : 
     853           28640 :         if (!callback)
     854               0 :             return NS_OK;
     855                 : 
     856           57280 :         nsCOMPtr<nsIInputStreamCallback> proxy;
     857           28640 :         if (target) {
     858           19365 :             nsresult rv = NS_NewInputStreamReadyEvent(getter_AddRefs(proxy),
     859           19365 :                                                       callback, target);
     860           19365 :             if (NS_FAILED(rv)) return rv;
     861           19365 :             callback = proxy;
     862                 :         }
     863                 : 
     864           34326 :         if (NS_FAILED(mPipe->mStatus) ||
     865            5686 :                 (mAvailable && !(flags & WAIT_CLOSURE_ONLY))) {
     866                 :             // stream is already closed or readable; post event.
     867           14495 :             pipeEvents.NotifyInputReady(this, callback);
     868                 :         }
     869                 :         else {
     870                 :             // queue up callback object to be notified when data becomes available
     871           14145 :             mCallback = callback;
     872           14145 :             mCallbackFlags = flags;
     873                 :         }
     874                 :     }
     875           28640 :     return NS_OK;
     876                 : }
     877                 : 
     878                 : NS_IMETHODIMP
     879               0 : nsPipeInputStream::Seek(PRInt32 whence, PRInt64 offset)
     880                 : {
     881               0 :     NS_NOTREACHED("nsPipeInputStream::Seek");
     882               0 :     return NS_ERROR_NOT_IMPLEMENTED;
     883                 : }
     884                 : 
     885                 : NS_IMETHODIMP
     886            7826 : nsPipeInputStream::Tell(PRInt64 *offset)
     887                 : {
     888           15652 :     ReentrantMonitorAutoEnter mon(mPipe->mReentrantMonitor);
     889                 : 
     890                 :     // return error if pipe closed
     891            7826 :     if (!mAvailable && NS_FAILED(mPipe->mStatus))
     892            2790 :         return mPipe->mStatus;
     893                 : 
     894            5036 :     *offset = mLogicalOffset;
     895            5036 :     return NS_OK;
     896                 : }
     897                 : 
     898                 : NS_IMETHODIMP
     899               0 : nsPipeInputStream::SetEOF()
     900                 : {
     901               0 :     NS_NOTREACHED("nsPipeInputStream::SetEOF");
     902               0 :     return NS_ERROR_NOT_IMPLEMENTED;
     903                 : }
     904                 : 
     905                 : #define COMPARE(s1, s2, i)                                                 \
     906                 :     (ignoreCase                                                            \
     907                 :      ? nsCRT::strncasecmp((const char *)s1, (const char *)s2, (PRUint32)i) \
     908                 :      : nsCRT::strncmp((const char *)s1, (const char *)s2, (PRUint32)i))
     909                 : 
     910                 : NS_IMETHODIMP
     911               0 : nsPipeInputStream::Search(const char *forString, 
     912                 :                           bool ignoreCase,
     913                 :                           bool *found,
     914                 :                           PRUint32 *offsetSearchedTo)
     915                 : {
     916               0 :     LOG(("III Search [for=%s ic=%u]\n", forString, ignoreCase));
     917                 : 
     918               0 :     ReentrantMonitorAutoEnter mon(mPipe->mReentrantMonitor);
     919                 : 
     920                 :     char *cursor1, *limit1;
     921               0 :     PRUint32 index = 0, offset = 0;
     922               0 :     PRUint32 strLen = strlen(forString);
     923                 : 
     924               0 :     mPipe->PeekSegment(0, cursor1, limit1);
     925               0 :     if (cursor1 == limit1) {
     926               0 :         *found = false;
     927               0 :         *offsetSearchedTo = 0;
     928               0 :         LOG(("  result [found=%u offset=%u]\n", *found, *offsetSearchedTo));
     929               0 :         return NS_OK;
     930                 :     }
     931                 : 
     932               0 :     while (true) {
     933               0 :         PRUint32 i, len1 = limit1 - cursor1;
     934                 : 
     935                 :         // check if the string is in the buffer segment
     936               0 :         for (i = 0; i < len1 - strLen + 1; i++) {
     937               0 :             if (COMPARE(&cursor1[i], forString, strLen) == 0) {
     938               0 :                 *found = true;
     939               0 :                 *offsetSearchedTo = offset + i;
     940               0 :                 LOG(("  result [found=%u offset=%u]\n", *found, *offsetSearchedTo));
     941               0 :                 return NS_OK;
     942                 :             }
     943                 :         }
     944                 : 
     945                 :         // get the next segment
     946                 :         char *cursor2, *limit2;
     947                 :         PRUint32 len2;
     948                 : 
     949               0 :         index++;
     950               0 :         offset += len1;
     951                 : 
     952               0 :         mPipe->PeekSegment(index, cursor2, limit2);
     953               0 :         if (cursor2 == limit2) {
     954               0 :             *found = false;
     955               0 :             *offsetSearchedTo = offset - strLen + 1;
     956               0 :             LOG(("  result [found=%u offset=%u]\n", *found, *offsetSearchedTo));
     957               0 :             return NS_OK;
     958                 :         }
     959               0 :         len2 = limit2 - cursor2;
     960                 : 
     961                 :         // check if the string is straddling the next buffer segment
     962               0 :         PRUint32 lim = NS_MIN(strLen, len2 + 1);
     963               0 :         for (i = 0; i < lim; ++i) {
     964               0 :             PRUint32 strPart1Len = strLen - i - 1;
     965               0 :             PRUint32 strPart2Len = strLen - strPart1Len;
     966               0 :             const char* strPart2 = &forString[strLen - strPart2Len];
     967               0 :             PRUint32 bufSeg1Offset = len1 - strPart1Len;
     968               0 :             if (COMPARE(&cursor1[bufSeg1Offset], forString, strPart1Len) == 0 &&
     969               0 :                 COMPARE(cursor2, strPart2, strPart2Len) == 0) {
     970               0 :                 *found = true;
     971               0 :                 *offsetSearchedTo = offset - strPart1Len;
     972               0 :                 LOG(("  result [found=%u offset=%u]\n", *found, *offsetSearchedTo));
     973               0 :                 return NS_OK;
     974                 :             }
     975                 :         }
     976                 : 
     977                 :         // finally continue with the next buffer
     978               0 :         cursor1 = cursor2;
     979               0 :         limit1 = limit2;
     980                 :     }
     981                 : 
     982                 :     NS_NOTREACHED("can't get here");
     983                 :     return NS_ERROR_UNEXPECTED;    // keep compiler happy
     984                 : }
     985                 : 
     986                 : //-----------------------------------------------------------------------------
     987                 : // nsPipeOutputStream methods:
     988                 : //-----------------------------------------------------------------------------
     989                 : 
     990          210609 : NS_IMPL_QUERY_INTERFACE3(nsPipeOutputStream,
     991                 :                          nsIOutputStream,
     992                 :                          nsIAsyncOutputStream,
     993                 :                          nsIClassInfo)
     994                 : 
     995           11321 : NS_IMPL_CI_INTERFACE_GETTER2(nsPipeOutputStream,
     996                 :                              nsIOutputStream,
     997           11321 :                              nsIAsyncOutputStream)
     998                 : 
     999           34098 : NS_IMPL_THREADSAFE_CI(nsPipeOutputStream)
    1000                 : 
    1001                 : nsresult
    1002               0 : nsPipeOutputStream::Wait()
    1003                 : {
    1004               0 :     NS_ASSERTION(mBlocking, "wait on non-blocking pipe output stream");
    1005                 : 
    1006               0 :     ReentrantMonitorAutoEnter mon(mPipe->mReentrantMonitor);
    1007                 : 
    1008               0 :     if (NS_SUCCEEDED(mPipe->mStatus) && !mWritable) {
    1009               0 :         LOG(("OOO pipe output: waiting for space\n"));
    1010               0 :         mBlocked = true;
    1011               0 :         mon.Wait();
    1012               0 :         mBlocked = false;
    1013               0 :         LOG(("OOO pipe output: woke up [pipe-status=%x writable=%u]\n",
    1014                 :             mPipe->mStatus, mWritable));
    1015                 :     }
    1016                 : 
    1017               0 :     return mPipe->mStatus == NS_BASE_STREAM_CLOSED ? NS_OK : mPipe->mStatus;
    1018                 : }
    1019                 : 
    1020                 : bool
    1021            1112 : nsPipeOutputStream::OnOutputWritable(nsPipeEvents &events)
    1022                 : {
    1023            1112 :     bool result = false;
    1024                 : 
    1025            1112 :     mWritable = true;
    1026                 : 
    1027            1112 :     if (mCallback && !(mCallbackFlags & WAIT_CLOSURE_ONLY)) {
    1028              28 :         events.NotifyOutputReady(this, mCallback);
    1029              28 :         mCallback = 0;
    1030              28 :         mCallbackFlags = 0;
    1031                 :     }
    1032            1084 :     else if (mBlocked)
    1033               0 :         result = true;
    1034                 : 
    1035            1112 :     return result;
    1036                 : }
    1037                 : 
    1038                 : bool
    1039           18617 : nsPipeOutputStream::OnOutputException(nsresult reason, nsPipeEvents &events)
    1040                 : {
    1041           18617 :     LOG(("nsPipeOutputStream::OnOutputException [this=%x reason=%x]\n",
    1042                 :         this, reason));
    1043                 : 
    1044           18617 :     bool result = false;
    1045                 : 
    1046           18617 :     NS_ASSERTION(NS_FAILED(reason), "huh? successful exception");
    1047           18617 :     mWritable = false;
    1048                 : 
    1049           18617 :     if (mCallback) {
    1050            5770 :         events.NotifyOutputReady(this, mCallback);
    1051            5770 :         mCallback = 0;
    1052            5770 :         mCallbackFlags = 0;
    1053                 :     }
    1054           12847 :     else if (mBlocked)
    1055               0 :         result = true;
    1056                 : 
    1057           18617 :     return result;
    1058                 : }
    1059                 : 
    1060                 : 
    1061                 : NS_IMETHODIMP_(nsrefcnt)
    1062          176952 : nsPipeOutputStream::AddRef()
    1063                 : {
    1064          176952 :     NS_AtomicIncrementRefcnt(mWriterRefCnt);
    1065          176952 :     return mPipe->AddRef();
    1066                 : }
    1067                 : 
    1068                 : NS_IMETHODIMP_(nsrefcnt)
    1069          176936 : nsPipeOutputStream::Release()
    1070                 : {
    1071          176936 :     if (NS_AtomicDecrementRefcnt(mWriterRefCnt) == 0)
    1072           18618 :         Close();
    1073          176936 :     return mPipe->Release();
    1074                 : }
    1075                 : 
    1076                 : NS_IMETHODIMP
    1077           35799 : nsPipeOutputStream::CloseWithStatus(nsresult reason)
    1078                 : {
    1079           35799 :     LOG(("OOO CloseWithStatus [this=%x reason=%x]\n", this, reason));
    1080                 : 
    1081           35799 :     if (NS_SUCCEEDED(reason))
    1082            2881 :         reason = NS_BASE_STREAM_CLOSED;
    1083                 : 
    1084                 :     // input stream may remain open
    1085           35799 :     mPipe->OnPipeException(reason, true);
    1086           35799 :     return NS_OK;
    1087                 : }
    1088                 : 
    1089                 : NS_IMETHODIMP
    1090           29624 : nsPipeOutputStream::Close()
    1091                 : {
    1092           29624 :     return CloseWithStatus(NS_BASE_STREAM_CLOSED);
    1093                 : }
    1094                 : 
    1095                 : NS_IMETHODIMP
    1096           79795 : nsPipeOutputStream::WriteSegments(nsReadSegmentFun reader,
    1097                 :                                   void* closure,
    1098                 :                                   PRUint32 count,
    1099                 :                                   PRUint32 *writeCount)
    1100                 : {
    1101           79795 :     LOG(("OOO WriteSegments [this=%x count=%u]\n", this, count));
    1102                 : 
    1103           79795 :     nsresult rv = NS_OK;
    1104                 : 
    1105                 :     char *segment;
    1106                 :     PRUint32 segmentLen;
    1107                 : 
    1108           79795 :     *writeCount = 0;
    1109          239977 :     while (count) {
    1110           80507 :         rv = mPipe->GetWriteSegment(segment, segmentLen);
    1111           80507 :         if (NS_FAILED(rv)) {
    1112             120 :             if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
    1113                 :                 // pipe is full
    1114              31 :                 if (!mBlocking) {
    1115                 :                     // ignore this error if we've already written something
    1116              31 :                     if (*writeCount > 0)
    1117               5 :                         rv = NS_OK;
    1118              31 :                     break;
    1119                 :                 }
    1120                 :                 // wait for the pipe to have an empty segment.
    1121               0 :                 rv = Wait();
    1122               0 :                 if (NS_SUCCEEDED(rv))
    1123               0 :                     continue;
    1124                 :             }
    1125              89 :             mPipe->OnPipeException(rv);
    1126              89 :             break;
    1127                 :         }
    1128                 : 
    1129                 :         // write no more than count
    1130           80387 :         if (segmentLen > count)
    1131           64423 :             segmentLen = count;
    1132                 : 
    1133           80387 :         PRUint32 readCount, originalLen = segmentLen;
    1134          232857 :         while (segmentLen) {
    1135           86900 :             readCount = 0;
    1136                 : 
    1137           86900 :             rv = reader(this, closure, segment, *writeCount, segmentLen, &readCount);
    1138                 : 
    1139           86900 :             if (NS_FAILED(rv) || readCount == 0) {
    1140           14817 :                 count = 0;
    1141                 :                 // any errors returned from the reader end here: do not
    1142                 :                 // propagate to the caller of WriteSegments.
    1143           14817 :                 rv = NS_OK;
    1144           14817 :                 break;
    1145                 :             }
    1146                 : 
    1147           72083 :             NS_ASSERTION(readCount <= segmentLen, "read more than expected");
    1148           72083 :             segment += readCount;
    1149           72083 :             segmentLen -= readCount;
    1150           72083 :             count -= readCount;
    1151           72083 :             *writeCount += readCount;
    1152           72083 :             mLogicalOffset += readCount;
    1153                 :         }
    1154                 : 
    1155           80387 :         if (segmentLen < originalLen)
    1156           72083 :             mPipe->AdvanceWriteCursor(originalLen - segmentLen);
    1157                 :     }
    1158                 : 
    1159           79795 :     return rv;
    1160                 : }
    1161                 : 
    1162                 : static NS_METHOD
    1163           65225 : nsReadFromRawBuffer(nsIOutputStream* outStr,
    1164                 :                     void* closure,
    1165                 :                     char* toRawSegment,
    1166                 :                     PRUint32 offset,
    1167                 :                     PRUint32 count,
    1168                 :                     PRUint32 *readCount)
    1169                 : {
    1170           65225 :     const char* fromBuf = (const char*)closure;
    1171           65225 :     memcpy(toRawSegment, &fromBuf[offset], count);
    1172           65225 :     *readCount = count;
    1173           65225 :     return NS_OK;
    1174                 : }
    1175                 : 
    1176                 : NS_IMETHODIMP
    1177           64591 : nsPipeOutputStream::Write(const char* fromBuf,
    1178                 :                           PRUint32 bufLen, 
    1179                 :                           PRUint32 *writeCount)
    1180                 : {
    1181           64591 :     return WriteSegments(nsReadFromRawBuffer, (void*)fromBuf, bufLen, writeCount);
    1182                 : }
    1183                 : 
    1184                 : NS_IMETHODIMP
    1185               8 : nsPipeOutputStream::Flush(void)
    1186                 : {
    1187                 :     // nothing to do
    1188               8 :     return NS_OK;
    1189                 : }
    1190                 : 
    1191                 : static NS_METHOD
    1192              40 : nsReadFromInputStream(nsIOutputStream* outStr,
    1193                 :                       void* closure,
    1194                 :                       char* toRawSegment, 
    1195                 :                       PRUint32 offset,
    1196                 :                       PRUint32 count,
    1197                 :                       PRUint32 *readCount)
    1198                 : {
    1199              40 :     nsIInputStream* fromStream = (nsIInputStream*)closure;
    1200              40 :     return fromStream->Read(toRawSegment, count, readCount);
    1201                 : }
    1202                 : 
    1203                 : NS_IMETHODIMP
    1204              40 : nsPipeOutputStream::WriteFrom(nsIInputStream* fromStream,
    1205                 :                               PRUint32 count,
    1206                 :                               PRUint32 *writeCount)
    1207                 : {
    1208              40 :     return WriteSegments(nsReadFromInputStream, fromStream, count, writeCount);
    1209                 : }
    1210                 : 
    1211                 : NS_IMETHODIMP
    1212               1 : nsPipeOutputStream::IsNonBlocking(bool *aNonBlocking)
    1213                 : {
    1214               1 :     *aNonBlocking = !mBlocking;
    1215               1 :     return NS_OK;
    1216                 : }
    1217                 : 
    1218                 : NS_IMETHODIMP
    1219           21810 : nsPipeOutputStream::AsyncWait(nsIOutputStreamCallback *callback,
    1220                 :                               PRUint32 flags,
    1221                 :                               PRUint32 requestedCount,
    1222                 :                               nsIEventTarget *target)
    1223                 : {
    1224           21810 :     LOG(("OOO AsyncWait [this=%x]\n", this));
    1225                 : 
    1226           43620 :     nsPipeEvents pipeEvents;
    1227                 :     {
    1228           43620 :         ReentrantMonitorAutoEnter mon(mPipe->mReentrantMonitor);
    1229                 : 
    1230                 :         // replace a pending callback
    1231           21809 :         mCallback = 0;
    1232           21810 :         mCallbackFlags = 0;
    1233                 : 
    1234           21810 :         if (!callback)
    1235               0 :             return NS_OK;
    1236                 : 
    1237           43620 :         nsCOMPtr<nsIOutputStreamCallback> proxy;
    1238           21810 :         if (target) {
    1239           18277 :             nsresult rv = NS_NewOutputStreamReadyEvent(getter_AddRefs(proxy),
    1240           18277 :                                                        callback, target);
    1241           18277 :             if (NS_FAILED(rv)) return rv;
    1242           18277 :             callback = proxy;
    1243                 :         }
    1244                 : 
    1245           43571 :         if (NS_FAILED(mPipe->mStatus) ||
    1246           21761 :                 (mWritable && !(flags & WAIT_CLOSURE_ONLY))) {
    1247                 :             // stream is already closed or writable; post event.
    1248            7056 :             pipeEvents.NotifyOutputReady(this, callback);
    1249                 :         }
    1250                 :         else {
    1251                 :             // queue up callback object to be notified when data becomes available
    1252           14754 :             mCallback = callback;
    1253           14754 :             mCallbackFlags = flags;
    1254                 :         }
    1255                 :     }
    1256           21810 :     return NS_OK;
    1257                 : }
    1258                 : 
    1259                 : ////////////////////////////////////////////////////////////////////////////////
    1260                 : 
    1261                 : nsresult
    1262            1132 : NS_NewPipe(nsIInputStream **pipeIn,
    1263                 :            nsIOutputStream **pipeOut,
    1264                 :            PRUint32 segmentSize,
    1265                 :            PRUint32 maxSize,
    1266                 :            bool nonBlockingInput,
    1267                 :            bool nonBlockingOutput,
    1268                 :            nsIMemory *segmentAlloc)
    1269                 : {
    1270            1132 :     if (segmentSize == 0)
    1271               0 :         segmentSize = DEFAULT_SEGMENT_SIZE;
    1272                 : 
    1273                 :     // Handle maxSize of PR_UINT32_MAX as a special case
    1274                 :     PRUint32 segmentCount;
    1275            1132 :     if (maxSize == PR_UINT32_MAX)
    1276             418 :         segmentCount = PR_UINT32_MAX;
    1277                 :     else
    1278             714 :         segmentCount = maxSize / segmentSize;
    1279                 : 
    1280                 :     nsIAsyncInputStream *in;
    1281                 :     nsIAsyncOutputStream *out;
    1282                 :     nsresult rv = NS_NewPipe2(&in, &out, nonBlockingInput, nonBlockingOutput,
    1283            1132 :                               segmentSize, segmentCount, segmentAlloc);
    1284            1132 :     if (NS_FAILED(rv)) return rv;
    1285                 : 
    1286            1132 :     *pipeIn = in;
    1287            1132 :     *pipeOut = out;
    1288            1132 :     return NS_OK;
    1289                 : }
    1290                 : 
    1291                 : nsresult
    1292           10215 : NS_NewPipe2(nsIAsyncInputStream **pipeIn,
    1293                 :             nsIAsyncOutputStream **pipeOut,
    1294                 :             bool nonBlockingInput,
    1295                 :             bool nonBlockingOutput,
    1296                 :             PRUint32 segmentSize,
    1297                 :             PRUint32 segmentCount,
    1298                 :             nsIMemory *segmentAlloc)
    1299                 : {
    1300                 :     nsresult rv;
    1301                 : 
    1302           10215 :     nsPipe *pipe = new nsPipe();
    1303           10215 :     if (!pipe)
    1304               0 :         return NS_ERROR_OUT_OF_MEMORY;
    1305                 : 
    1306                 :     rv = pipe->Init(nonBlockingInput,
    1307                 :                     nonBlockingOutput,
    1308                 :                     segmentSize,
    1309                 :                     segmentCount,
    1310           10215 :                     segmentAlloc);
    1311           10215 :     if (NS_FAILED(rv)) {
    1312               0 :         NS_ADDREF(pipe);
    1313               0 :         NS_RELEASE(pipe);
    1314               0 :         return rv;
    1315                 :     }
    1316                 : 
    1317           10215 :     pipe->GetInputStream(pipeIn);
    1318           10215 :     pipe->GetOutputStream(pipeOut);
    1319           10215 :     return NS_OK;
    1320                 : }
    1321                 : 
    1322                 : nsresult
    1323            8417 : nsPipeConstructor(nsISupports *outer, REFNSIID iid, void **result)
    1324                 : {
    1325            8417 :     if (outer)
    1326               0 :         return NS_ERROR_NO_AGGREGATION;
    1327            8417 :     nsPipe *pipe = new nsPipe();
    1328            8417 :     if (!pipe)
    1329               0 :         return NS_ERROR_OUT_OF_MEMORY;
    1330            8417 :     NS_ADDREF(pipe);
    1331            8417 :     nsresult rv = pipe->QueryInterface(iid, result);
    1332            8417 :     NS_RELEASE(pipe);
    1333            8417 :     return rv;
    1334            4392 : }
    1335                 : 
    1336                 : ////////////////////////////////////////////////////////////////////////////////

Generated by: LCOV version 1.7