void nsPipe::AdvanceWriteCursor(PRUint32 bytesWritten) { NS_ASSERTION(bytesWritten, "dont call if no bytes written"); nsPipeEvents events; { nsAutoMonitor mon(mMonitor); LOG(("OOO advancing write cursor by %u\n", bytesWritten)); char *newWriteCursor = mWriteCursor + bytesWritten; NS_ASSERTION(newWriteCursor <= mWriteLimit, "write cursor exceeds limit"); // update read limit if reading in the same segment if (mWriteSegment == 0 && mReadLimit == mWriteCursor) mReadLimit = newWriteCursor; mWriteCursor = newWriteCursor; NS_ASSERTION(mReadCursor != mWriteCursor, "read cursor is bad"); // update the writable flag on the output stream if (mWriteCursor == mWriteLimit) { if (mBuffer.GetSize() >= mBuffer.GetMaxSize()) mOutput.SetWritable(PR_FALSE); } // notify input stream that pipe now contains additional data if (mInput.OnInputReadable(bytesWritten, events)) mon.Notify(); } }
void nsPipe::AdvanceReadCursor(PRUint32 bytesRead) { NS_ASSERTION(bytesRead, "dont call if no bytes read"); nsPipeEvents events; { nsAutoMonitor mon(mMonitor); LOG(("III advancing read cursor by %u\n", bytesRead)); NS_ASSERTION(bytesRead <= mBuffer.GetSegmentSize(), "read too much"); mReadCursor += bytesRead; NS_ASSERTION(mReadCursor <= mReadLimit, "read cursor exceeds limit"); mInput.ReduceAvailable(bytesRead); if (mReadCursor == mReadLimit) { // we've reached the limit of how much we can read from this segment. // if at the end of this segment, then we must discard this segment. // if still writing in this segment then bail because we're not done // with the segment and have to wait for now... if (mWriteSegment == 0 && mWriteLimit > mWriteCursor) { NS_ASSERTION(mReadLimit == mWriteCursor, "unexpected state"); return; } // shift write segment index (-1 indicates an empty buffer). --mWriteSegment; // done with this segment mBuffer.DeleteFirstSegment(); LOG(("III deleting first segment\n")); if (mWriteSegment == -1) { // buffer is completely empty mReadCursor = nsnull; mReadLimit = nsnull; mWriteCursor = nsnull; mWriteLimit = nsnull; } else { // advance read cursor and limit to next buffer segment mReadCursor = mBuffer.GetSegment(0); if (mWriteSegment == 0) mReadLimit = mWriteCursor; else mReadLimit = mReadCursor + mBuffer.GetSegmentSize(); } // we've free'd up a segment, so notify output stream that pipe has // room for a new segment. if (mOutput.OnOutputWritable(events)) mon.Notify(); } } }
void nsPipe::AdvanceWriteCursor(PRUint32 bytesWritten) { NS_ASSERTION(bytesWritten, "don't call if no bytes written"); nsPipeEvents events; { MonitorAutoEnter mon(mMonitor); LOG(("OOO advancing write cursor by %u\n", bytesWritten)); char *newWriteCursor = mWriteCursor + bytesWritten; NS_ASSERTION(newWriteCursor <= mWriteLimit, "write cursor exceeds limit"); // update read limit if reading in the same segment if (mWriteSegment == 0 && mReadLimit == mWriteCursor) mReadLimit = newWriteCursor; mWriteCursor = newWriteCursor; // The only way mReadCursor == mWriteCursor is if: // // - mReadCursor is at the start of a segment (which, based on how // nsSegmentedBuffer works, means that this segment is the "first" // segment) // - mWriteCursor points at the location past the end of the current // write segment (so the current write filled the current write // segment, so we've incremented mWriteCursor to point past the end // of it) // - the segment to which data has just been written is located // exactly one segment's worth of bytes before the first segment // where mReadCursor is located // // Consequently, the byte immediately after the end of the current // write segment is the first byte of the first segment, so // mReadCursor == mWriteCursor. (Another way to think about this is // to consider the buffer architecture diagram above, but consider it // with an arena allocator which allocates from the *end* of the // arena to the *beginning* of the arena.) NS_ASSERTION(mReadCursor != mWriteCursor || (mBuffer.GetSegment(0) == mReadCursor && mWriteCursor == mWriteLimit), "read cursor is bad"); // update the writable flag on the output stream if (mWriteCursor == mWriteLimit) { if (mBuffer.GetSize() >= mBuffer.GetMaxSize()) mOutput.SetWritable(PR_FALSE); } // notify input stream that pipe now contains additional data if (mInput.OnInputReadable(bytesWritten, events)) mon.Notify(); } }
NS_IMETHODIMP nsPipe::Init(PRBool nonBlockingIn, PRBool nonBlockingOut, PRUint32 segmentSize, PRUint32 segmentCount, nsIMemory *segmentAlloc) { mMonitor = PR_NewMonitor(); if (!mMonitor) return NS_ERROR_OUT_OF_MEMORY; if (segmentSize == 0) segmentSize = DEFAULT_SEGMENT_SIZE; if (segmentCount == 0) segmentCount = DEFAULT_SEGMENT_COUNT; // protect against overflow PRUint32 maxCount = PRUint32(-1) / segmentSize; if (segmentCount > maxCount) segmentCount = maxCount; nsresult rv = mBuffer.Init(segmentSize, segmentSize * segmentCount, segmentAlloc); if (NS_FAILED(rv)) return rv; mInput.SetNonBlocking(nonBlockingIn); mOutput.SetNonBlocking(nonBlockingOut); return NS_OK; }
void nsPipe::PeekSegment(PRUint32 index, char *&cursor, char *&limit) { if (index == 0) { NS_ASSERTION(!mReadCursor || mBuffer.GetSegmentCount(), "unexpected state"); cursor = mReadCursor; limit = mReadLimit; } else { PRUint32 numSegments = mBuffer.GetSegmentCount(); if (index >= numSegments) cursor = limit = nsnull; else { cursor = mBuffer.GetSegment(index); if (mWriteSegment == (PRInt32) index) limit = mWriteCursor; else limit = cursor + mBuffer.GetSegmentSize(); } } }
nsresult nsPipe::GetWriteSegment(char *&segment, PRUint32 &segmentLen) { nsAutoMonitor mon(mMonitor); if (NS_FAILED(mStatus)) return mStatus; // write cursor and limit may both be null indicating an empty buffer. if (mWriteCursor == mWriteLimit) { char *seg = mBuffer.AppendNewSegment(); // pipe is full if (seg == nsnull) return NS_BASE_STREAM_WOULD_BLOCK; LOG(("OOO appended new segment\n")); mWriteCursor = seg; mWriteLimit = mWriteCursor + mBuffer.GetSegmentSize(); ++mWriteSegment; } // make sure read cursor is initialized if (mReadCursor == nsnull) { NS_ASSERTION(mWriteSegment == 0, "unexpected null read cursor"); mReadCursor = mReadLimit = mWriteCursor; } // check to see if we can roll-back our read and write cursors to the // beginning of the current/first segment. this is purely an optimization. if (mReadCursor == mWriteCursor && mWriteSegment == 0) { char *head = mBuffer.GetSegment(0); LOG(("OOO rolling back write cursor %u bytes\n", mWriteCursor - head)); mWriteCursor = mReadCursor = mReadLimit = head; } segment = mWriteCursor; segmentLen = mWriteLimit - mWriteCursor; return NS_OK; }