/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
private:
nsCOMPtr<nsIInputStream> mSource;
nsCOMPtr<nsIOutputStream> mSink;
nsCOMPtr<nsIEventTarget> mEventTarget;
nsWriteSegmentFun mWriter; // for implementing ReadSegments void* mClosure; // for implementing ReadSegments
Maybe<Mutex> mLock; // synchronize access to mSinkIsValid bool mSinkIsValid; // False if TeeWriteEvent fails
};
class nsInputStreamTeeWriteEvent : public Runnable { public: // aTee's lock is held across construction of this object
nsInputStreamTeeWriteEvent(constchar* aBuf, uint32_t aCount,
nsIOutputStream* aSink, nsInputStreamTee* aTee)
: mozilla::Runnable("nsInputStreamTeeWriteEvent") { // copy the buffer - will be free'd by dtor
mBuf = (char*)malloc(aCount); if (mBuf) {
memcpy(mBuf, (char*)aBuf, aCount);
}
mCount = aCount;
mSink = aSink; bool isNonBlocking;
mSink->IsNonBlocking(&isNonBlocking);
NS_ASSERTION(isNonBlocking == false, "mSink is nonblocking");
mTee = aTee;
}
NS_IMETHOD Run() override { if (!mBuf) {
NS_WARNING( "nsInputStreamTeeWriteEvent::Run() " "memory not allocated\n"); return NS_OK;
}
MOZ_ASSERT(mSink, "mSink is null!");
// The output stream could have been invalidated between when // this event was dispatched and now, so check before writing. if (!mTee->SinkIsValid()) { return NS_OK;
}
private: char* mBuf;
uint32_t mCount;
nsCOMPtr<nsIOutputStream> mSink; // back pointer to the tee that created this runnable
RefPtr<nsInputStreamTee> mTee;
};
nsresult nsInputStreamTee::TeeSegment(constchar* aBuf, uint32_t aCount) { if (!mSink) { return NS_OK; // nothing to do
} if (mLock) { // asynchronous case
NS_ASSERTION(mEventTarget, "mEventTarget is null, mLock is not null."); if (!SinkIsValid()) { return NS_OK; // nothing to do
}
nsCOMPtr<nsIRunnable> event = new nsInputStreamTeeWriteEvent(aBuf, aCount, mSink, this);
LOG(("nsInputStreamTee::TeeSegment [%p] dispatching write %u bytes\n", this,
aCount)); return mEventTarget->Dispatch(event, NS_DISPATCH_NORMAL);
} else { // synchronous case
NS_ASSERTION(!mEventTarget, "mEventTarget is not null, mLock is null.");
nsresult rv;
uint32_t totalBytesWritten = 0; while (aCount) {
uint32_t bytesWritten = 0;
rv = mSink->Write(aBuf + totalBytesWritten, aCount, &bytesWritten); if (NS_FAILED(rv)) { // ok, this is not a fatal error... just drop our reference to mSink // and continue on as if nothing happened.
NS_WARNING("Write failed (non-fatal)"); // catch possible misuse of the input stream tee
NS_ASSERTION(rv != NS_BASE_STREAM_WOULD_BLOCK, "sink must be a blocking stream");
mSink = nullptr; break;
}
totalBytesWritten += bytesWritten;
NS_ASSERTION(bytesWritten <= aCount, "wrote too much");
aCount -= bytesWritten;
} return NS_OK;
}
}
NS_IMETHODIMP
nsInputStreamTee::SetEventTarget(nsIEventTarget* aEventTarget) {
mEventTarget = aEventTarget; if (mEventTarget) { // Only need synchronization if this is an async tee
mLock.emplace("nsInputStreamTee.mLock");
} return NS_OK;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.