void nsPipe::OnPipeException(nsresult reason, PRBool outputOnly) { LOG(("PPP nsPipe::OnPipeException [reason=%x output-only=%d]\n", reason, outputOnly)); nsPipeEvents events; { nsAutoMonitor mon(mMonitor); // if we've already hit an exception, then ignore this one. if (NS_FAILED(mStatus)) return; mStatus = reason; // an output-only exception applies to the input end if the pipe has // zero bytes available. if (outputOnly && !mInput.Available()) outputOnly = PR_FALSE; if (!outputOnly) if (mInput.OnInputException(reason, events)) mon.Notify(); if (mOutput.OnOutputException(reason, events)) mon.Notify(); } }
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(); } }
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::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(); } }