1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/cache2/CacheFileInputStream.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,672 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "CacheLog.h" 1.9 +#include "CacheFileInputStream.h" 1.10 + 1.11 +#include "CacheFile.h" 1.12 +#include "nsStreamUtils.h" 1.13 +#include "nsThreadUtils.h" 1.14 +#include <algorithm> 1.15 + 1.16 +namespace mozilla { 1.17 +namespace net { 1.18 + 1.19 +NS_IMPL_ADDREF(CacheFileInputStream) 1.20 +NS_IMETHODIMP_(MozExternalRefCountType) 1.21 +CacheFileInputStream::Release() 1.22 +{ 1.23 + NS_PRECONDITION(0 != mRefCnt, "dup release"); 1.24 + nsrefcnt count = --mRefCnt; 1.25 + NS_LOG_RELEASE(this, count, "CacheFileInputStream"); 1.26 + 1.27 + if (0 == count) { 1.28 + mRefCnt = 1; 1.29 + delete (this); 1.30 + return 0; 1.31 + } 1.32 + 1.33 + if (count == 1) { 1.34 + mFile->RemoveInput(this); 1.35 + } 1.36 + 1.37 + return count; 1.38 +} 1.39 + 1.40 +NS_INTERFACE_MAP_BEGIN(CacheFileInputStream) 1.41 + NS_INTERFACE_MAP_ENTRY(nsIInputStream) 1.42 + NS_INTERFACE_MAP_ENTRY(nsIAsyncInputStream) 1.43 + NS_INTERFACE_MAP_ENTRY(nsISeekableStream) 1.44 + NS_INTERFACE_MAP_ENTRY(mozilla::net::CacheFileChunkListener) 1.45 + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream) 1.46 +NS_INTERFACE_MAP_END_THREADSAFE 1.47 + 1.48 +CacheFileInputStream::CacheFileInputStream(CacheFile *aFile) 1.49 + : mFile(aFile) 1.50 + , mPos(0) 1.51 + , mClosed(false) 1.52 + , mStatus(NS_OK) 1.53 + , mWaitingForUpdate(false) 1.54 + , mListeningForChunk(-1) 1.55 + , mInReadSegments(false) 1.56 + , mCallbackFlags(0) 1.57 +{ 1.58 + LOG(("CacheFileInputStream::CacheFileInputStream() [this=%p]", this)); 1.59 + MOZ_COUNT_CTOR(CacheFileInputStream); 1.60 +} 1.61 + 1.62 +CacheFileInputStream::~CacheFileInputStream() 1.63 +{ 1.64 + LOG(("CacheFileInputStream::~CacheFileInputStream() [this=%p]", this)); 1.65 + MOZ_COUNT_DTOR(CacheFileInputStream); 1.66 +} 1.67 + 1.68 +// nsIInputStream 1.69 +NS_IMETHODIMP 1.70 +CacheFileInputStream::Close() 1.71 +{ 1.72 + LOG(("CacheFileInputStream::Close() [this=%p]", this)); 1.73 + return CloseWithStatus(NS_OK); 1.74 +} 1.75 + 1.76 +NS_IMETHODIMP 1.77 +CacheFileInputStream::Available(uint64_t *_retval) 1.78 +{ 1.79 + CacheFileAutoLock lock(mFile); 1.80 + MOZ_ASSERT(!mInReadSegments); 1.81 + 1.82 + if (mClosed) { 1.83 + LOG(("CacheFileInputStream::Available() - Stream is closed. [this=%p, " 1.84 + "status=0x%08x]", this, mStatus)); 1.85 + return NS_FAILED(mStatus) ? mStatus : NS_BASE_STREAM_CLOSED; 1.86 + } 1.87 + 1.88 + EnsureCorrectChunk(false); 1.89 + if (NS_FAILED(mStatus)) 1.90 + return mStatus; 1.91 + 1.92 + *_retval = 0; 1.93 + 1.94 + if (mChunk) { 1.95 + int64_t canRead; 1.96 + const char *buf; 1.97 + CanRead(&canRead, &buf); 1.98 + 1.99 + if (canRead > 0) 1.100 + *_retval = canRead; 1.101 + else if (canRead == 0 && !mFile->mOutput) 1.102 + return NS_BASE_STREAM_CLOSED; 1.103 + } 1.104 + 1.105 + LOG(("CacheFileInputStream::Available() [this=%p, retval=%lld]", 1.106 + this, *_retval)); 1.107 + 1.108 + return NS_OK; 1.109 +} 1.110 + 1.111 +NS_IMETHODIMP 1.112 +CacheFileInputStream::Read(char *aBuf, uint32_t aCount, uint32_t *_retval) 1.113 +{ 1.114 + CacheFileAutoLock lock(mFile); 1.115 + MOZ_ASSERT(!mInReadSegments); 1.116 + 1.117 + LOG(("CacheFileInputStream::Read() [this=%p, count=%d]", this, aCount)); 1.118 + 1.119 + nsresult rv; 1.120 + 1.121 + if (mClosed) { 1.122 + LOG(("CacheFileInputStream::Read() - Stream is closed. [this=%p, " 1.123 + "status=0x%08x]", this, mStatus)); 1.124 + 1.125 + if NS_FAILED(mStatus) 1.126 + return mStatus; 1.127 + 1.128 + *_retval = 0; 1.129 + return NS_OK; 1.130 + } 1.131 + 1.132 + EnsureCorrectChunk(false); 1.133 + if (NS_FAILED(mStatus)) 1.134 + return mStatus; 1.135 + 1.136 + if (!mChunk) { 1.137 + if (mListeningForChunk == -1) { 1.138 + LOG((" no chunk, returning 0 read and NS_OK")); 1.139 + *_retval = 0; 1.140 + return NS_OK; 1.141 + } 1.142 + else { 1.143 + LOG((" waiting for chuck, returning WOULD_BLOCK")); 1.144 + return NS_BASE_STREAM_WOULD_BLOCK; 1.145 + } 1.146 + } 1.147 + 1.148 + int64_t canRead; 1.149 + const char *buf; 1.150 + CanRead(&canRead, &buf); 1.151 + 1.152 + if (canRead < 0) { 1.153 + // file was truncated ??? 1.154 + MOZ_ASSERT(false, "SetEOF is currenty not implemented?!"); 1.155 + *_retval = 0; 1.156 + rv = NS_OK; 1.157 + } 1.158 + else if (canRead > 0) { 1.159 + *_retval = std::min(static_cast<uint32_t>(canRead), aCount); 1.160 + memcpy(aBuf, buf, *_retval); 1.161 + mPos += *_retval; 1.162 + 1.163 + EnsureCorrectChunk(!(canRead < aCount && mPos % kChunkSize == 0)); 1.164 + 1.165 + rv = NS_OK; 1.166 + } 1.167 + else { 1.168 + if (mFile->mOutput) 1.169 + rv = NS_BASE_STREAM_WOULD_BLOCK; 1.170 + else { 1.171 + *_retval = 0; 1.172 + rv = NS_OK; 1.173 + } 1.174 + } 1.175 + 1.176 + LOG(("CacheFileInputStream::Read() [this=%p, rv=0x%08x, retval=%d", 1.177 + this, rv, *_retval)); 1.178 + 1.179 + return rv; 1.180 +} 1.181 + 1.182 +NS_IMETHODIMP 1.183 +CacheFileInputStream::ReadSegments(nsWriteSegmentFun aWriter, void *aClosure, 1.184 + uint32_t aCount, uint32_t *_retval) 1.185 +{ 1.186 + CacheFileAutoLock lock(mFile); 1.187 + MOZ_ASSERT(!mInReadSegments); 1.188 + 1.189 + LOG(("CacheFileInputStream::ReadSegments() [this=%p, count=%d]", 1.190 + this, aCount)); 1.191 + 1.192 + nsresult rv; 1.193 + 1.194 + if (mClosed) { 1.195 + LOG(("CacheFileInputStream::ReadSegments() - Stream is closed. [this=%p, " 1.196 + "status=0x%08x]", this, mStatus)); 1.197 + 1.198 + if NS_FAILED(mStatus) 1.199 + return mStatus; 1.200 + 1.201 + *_retval = 0; 1.202 + return NS_OK; 1.203 + } 1.204 + 1.205 + EnsureCorrectChunk(false); 1.206 + if (NS_FAILED(mStatus)) 1.207 + return mStatus; 1.208 + 1.209 + if (!mChunk) { 1.210 + if (mListeningForChunk == -1) { 1.211 + *_retval = 0; 1.212 + return NS_OK; 1.213 + } 1.214 + else { 1.215 + return NS_BASE_STREAM_WOULD_BLOCK; 1.216 + } 1.217 + } 1.218 + 1.219 + int64_t canRead; 1.220 + const char *buf; 1.221 + CanRead(&canRead, &buf); 1.222 + 1.223 + if (canRead < 0) { 1.224 + // file was truncated ??? 1.225 + MOZ_ASSERT(false, "SetEOF is currenty not implemented?!"); 1.226 + *_retval = 0; 1.227 + rv = NS_OK; 1.228 + } 1.229 + else if (canRead > 0) { 1.230 + uint32_t toRead = std::min(static_cast<uint32_t>(canRead), aCount); 1.231 + 1.232 + // We need to release the lock to avoid lock re-entering 1.233 +#ifdef DEBUG 1.234 + int64_t oldPos = mPos; 1.235 +#endif 1.236 + mInReadSegments = true; 1.237 + lock.Unlock(); 1.238 + rv = aWriter(this, aClosure, buf, 0, toRead, _retval); 1.239 + lock.Lock(); 1.240 + mInReadSegments = false; 1.241 +#ifdef DEBUG 1.242 + MOZ_ASSERT(oldPos == mPos); 1.243 +#endif 1.244 + 1.245 + if (NS_SUCCEEDED(rv)) { 1.246 + MOZ_ASSERT(*_retval <= toRead, 1.247 + "writer should not write more than we asked it to write"); 1.248 + mPos += *_retval; 1.249 + } 1.250 + 1.251 + EnsureCorrectChunk(!(canRead < aCount && mPos % kChunkSize == 0)); 1.252 + 1.253 + rv = NS_OK; 1.254 + } 1.255 + else { 1.256 + if (mFile->mOutput) 1.257 + rv = NS_BASE_STREAM_WOULD_BLOCK; 1.258 + else { 1.259 + *_retval = 0; 1.260 + rv = NS_OK; 1.261 + } 1.262 + } 1.263 + 1.264 + LOG(("CacheFileInputStream::ReadSegments() [this=%p, rv=0x%08x, retval=%d", 1.265 + this, rv, *_retval)); 1.266 + 1.267 + return rv; 1.268 +} 1.269 + 1.270 +NS_IMETHODIMP 1.271 +CacheFileInputStream::IsNonBlocking(bool *_retval) 1.272 +{ 1.273 + *_retval = true; 1.274 + return NS_OK; 1.275 +} 1.276 + 1.277 +// nsIAsyncInputStream 1.278 +NS_IMETHODIMP 1.279 +CacheFileInputStream::CloseWithStatus(nsresult aStatus) 1.280 +{ 1.281 + CacheFileAutoLock lock(mFile); 1.282 + MOZ_ASSERT(!mInReadSegments); 1.283 + 1.284 + LOG(("CacheFileInputStream::CloseWithStatus() [this=%p, aStatus=0x%08x]", 1.285 + this, aStatus)); 1.286 + 1.287 + if (mClosed) { 1.288 + MOZ_ASSERT(!mCallback); 1.289 + return NS_OK; 1.290 + } 1.291 + 1.292 + mClosed = true; 1.293 + mStatus = NS_FAILED(aStatus) ? aStatus : NS_BASE_STREAM_CLOSED; 1.294 + 1.295 + if (mChunk) 1.296 + ReleaseChunk(); 1.297 + 1.298 + // TODO propagate error from input stream to other streams ??? 1.299 + 1.300 + MaybeNotifyListener(); 1.301 + 1.302 + return NS_OK; 1.303 +} 1.304 + 1.305 +NS_IMETHODIMP 1.306 +CacheFileInputStream::AsyncWait(nsIInputStreamCallback *aCallback, 1.307 + uint32_t aFlags, 1.308 + uint32_t aRequestedCount, 1.309 + nsIEventTarget *aEventTarget) 1.310 +{ 1.311 + CacheFileAutoLock lock(mFile); 1.312 + MOZ_ASSERT(!mInReadSegments); 1.313 + 1.314 + LOG(("CacheFileInputStream::AsyncWait() [this=%p, callback=%p, flags=%d, " 1.315 + "requestedCount=%d, eventTarget=%p]", this, aCallback, aFlags, 1.316 + aRequestedCount, aEventTarget)); 1.317 + 1.318 + mCallback = aCallback; 1.319 + mCallbackFlags = aFlags; 1.320 + 1.321 + if (!mCallback) { 1.322 + if (mWaitingForUpdate) { 1.323 + mChunk->CancelWait(this); 1.324 + mWaitingForUpdate = false; 1.325 + } 1.326 + return NS_OK; 1.327 + } 1.328 + 1.329 + if (mClosed) { 1.330 + NotifyListener(); 1.331 + return NS_OK; 1.332 + } 1.333 + 1.334 + EnsureCorrectChunk(false); 1.335 + 1.336 + MaybeNotifyListener(); 1.337 + 1.338 + return NS_OK; 1.339 +} 1.340 + 1.341 +// nsISeekableStream 1.342 +NS_IMETHODIMP 1.343 +CacheFileInputStream::Seek(int32_t whence, int64_t offset) 1.344 +{ 1.345 + CacheFileAutoLock lock(mFile); 1.346 + MOZ_ASSERT(!mInReadSegments); 1.347 + 1.348 + LOG(("CacheFileInputStream::Seek() [this=%p, whence=%d, offset=%lld]", 1.349 + this, whence, offset)); 1.350 + 1.351 + if (mClosed) { 1.352 + LOG(("CacheFileInputStream::Seek() - Stream is closed. [this=%p]", this)); 1.353 + return NS_BASE_STREAM_CLOSED; 1.354 + } 1.355 + 1.356 + int64_t newPos = offset; 1.357 + switch (whence) { 1.358 + case NS_SEEK_SET: 1.359 + break; 1.360 + case NS_SEEK_CUR: 1.361 + newPos += mPos; 1.362 + break; 1.363 + case NS_SEEK_END: 1.364 + newPos += mFile->mDataSize; 1.365 + break; 1.366 + default: 1.367 + NS_ERROR("invalid whence"); 1.368 + return NS_ERROR_INVALID_ARG; 1.369 + } 1.370 + mPos = newPos; 1.371 + EnsureCorrectChunk(true); 1.372 + 1.373 + LOG(("CacheFileInputStream::Seek() [this=%p, pos=%lld]", this, mPos)); 1.374 + return NS_OK; 1.375 +} 1.376 + 1.377 +NS_IMETHODIMP 1.378 +CacheFileInputStream::Tell(int64_t *_retval) 1.379 +{ 1.380 + CacheFileAutoLock lock(mFile); 1.381 + MOZ_ASSERT(!mInReadSegments); 1.382 + 1.383 + if (mClosed) { 1.384 + LOG(("CacheFileInputStream::Tell() - Stream is closed. [this=%p]", this)); 1.385 + return NS_BASE_STREAM_CLOSED; 1.386 + } 1.387 + 1.388 + *_retval = mPos; 1.389 + 1.390 + LOG(("CacheFileInputStream::Tell() [this=%p, retval=%lld]", this, *_retval)); 1.391 + return NS_OK; 1.392 +} 1.393 + 1.394 +NS_IMETHODIMP 1.395 +CacheFileInputStream::SetEOF() 1.396 +{ 1.397 + MOZ_ASSERT(false, "Don't call SetEOF on cache input stream"); 1.398 + return NS_ERROR_NOT_IMPLEMENTED; 1.399 +} 1.400 + 1.401 +// CacheFileChunkListener 1.402 +nsresult 1.403 +CacheFileInputStream::OnChunkRead(nsresult aResult, CacheFileChunk *aChunk) 1.404 +{ 1.405 + MOZ_CRASH("CacheFileInputStream::OnChunkRead should not be called!"); 1.406 + return NS_ERROR_UNEXPECTED; 1.407 +} 1.408 + 1.409 +nsresult 1.410 +CacheFileInputStream::OnChunkWritten(nsresult aResult, CacheFileChunk *aChunk) 1.411 +{ 1.412 + MOZ_CRASH("CacheFileInputStream::OnChunkWritten should not be called!"); 1.413 + return NS_ERROR_UNEXPECTED; 1.414 +} 1.415 + 1.416 +nsresult 1.417 +CacheFileInputStream::OnChunkAvailable(nsresult aResult, uint32_t aChunkIdx, 1.418 + CacheFileChunk *aChunk) 1.419 +{ 1.420 + CacheFileAutoLock lock(mFile); 1.421 + MOZ_ASSERT(!mInReadSegments); 1.422 + 1.423 + LOG(("CacheFileInputStream::OnChunkAvailable() [this=%p, result=0x%08x, " 1.424 + "idx=%d, chunk=%p]", this, aResult, aChunkIdx, aChunk)); 1.425 + 1.426 + MOZ_ASSERT(mListeningForChunk != -1); 1.427 + 1.428 + if (mListeningForChunk != static_cast<int64_t>(aChunkIdx)) { 1.429 + // This is not a chunk that we're waiting for 1.430 + LOG(("CacheFileInputStream::OnChunkAvailable() - Notification is for a " 1.431 + "different chunk. [this=%p, listeningForChunk=%lld]", 1.432 + this, mListeningForChunk)); 1.433 + 1.434 + return NS_OK; 1.435 + } 1.436 + 1.437 + MOZ_ASSERT(!mChunk); 1.438 + MOZ_ASSERT(!mWaitingForUpdate); 1.439 + mListeningForChunk = -1; 1.440 + 1.441 + if (mClosed) { 1.442 + MOZ_ASSERT(!mCallback); 1.443 + 1.444 + LOG(("CacheFileInputStream::OnChunkAvailable() - Stream is closed, " 1.445 + "ignoring notification. [this=%p]", this)); 1.446 + 1.447 + return NS_OK; 1.448 + } 1.449 + 1.450 + if (NS_SUCCEEDED(aResult)) { 1.451 + mChunk = aChunk; 1.452 + } else if (aResult != NS_ERROR_NOT_AVAILABLE) { 1.453 + // We store the error in mStatus, so we can propagate it later to consumer 1.454 + // in Read(), Available() etc. We need to handle NS_ERROR_NOT_AVAILABLE 1.455 + // differently since it is returned when the requested chunk is not 1.456 + // available and there is no writer that could create it, i.e. it means that 1.457 + // we've reached the end of the file. 1.458 + mStatus = aResult; 1.459 + } 1.460 + 1.461 + MaybeNotifyListener(); 1.462 + 1.463 + return NS_OK; 1.464 +} 1.465 + 1.466 +nsresult 1.467 +CacheFileInputStream::OnChunkUpdated(CacheFileChunk *aChunk) 1.468 +{ 1.469 + CacheFileAutoLock lock(mFile); 1.470 + MOZ_ASSERT(!mInReadSegments); 1.471 + 1.472 + LOG(("CacheFileInputStream::OnChunkUpdated() [this=%p, idx=%d]", 1.473 + this, aChunk->Index())); 1.474 + 1.475 + if (!mWaitingForUpdate) { 1.476 + LOG(("CacheFileInputStream::OnChunkUpdated() - Ignoring notification since " 1.477 + "mWaitingforUpdate == false. [this=%p]", this)); 1.478 + 1.479 + return NS_OK; 1.480 + } 1.481 + else { 1.482 + mWaitingForUpdate = false; 1.483 + } 1.484 + 1.485 + MOZ_ASSERT(mChunk == aChunk); 1.486 + 1.487 + MaybeNotifyListener(); 1.488 + 1.489 + return NS_OK; 1.490 +} 1.491 + 1.492 +void 1.493 +CacheFileInputStream::ReleaseChunk() 1.494 +{ 1.495 + mFile->AssertOwnsLock(); 1.496 + 1.497 + LOG(("CacheFileInputStream::ReleaseChunk() [this=%p, idx=%d]", 1.498 + this, mChunk->Index())); 1.499 + 1.500 + if (mWaitingForUpdate) { 1.501 + LOG(("CacheFileInputStream::ReleaseChunk() - Canceling waiting for update. " 1.502 + "[this=%p]", this)); 1.503 + 1.504 + mChunk->CancelWait(this); 1.505 + mWaitingForUpdate = false; 1.506 + } 1.507 + 1.508 + mFile->ReleaseOutsideLock(mChunk.forget().take()); 1.509 +} 1.510 + 1.511 +void 1.512 +CacheFileInputStream::EnsureCorrectChunk(bool aReleaseOnly) 1.513 +{ 1.514 + mFile->AssertOwnsLock(); 1.515 + 1.516 + LOG(("CacheFileInputStream::EnsureCorrectChunk() [this=%p, releaseOnly=%d]", 1.517 + this, aReleaseOnly)); 1.518 + 1.519 + nsresult rv; 1.520 + 1.521 + uint32_t chunkIdx = mPos / kChunkSize; 1.522 + 1.523 + if (mChunk) { 1.524 + if (mChunk->Index() == chunkIdx) { 1.525 + // we have a correct chunk 1.526 + LOG(("CacheFileInputStream::EnsureCorrectChunk() - Have correct chunk " 1.527 + "[this=%p, idx=%d]", this, chunkIdx)); 1.528 + 1.529 + return; 1.530 + } 1.531 + else { 1.532 + ReleaseChunk(); 1.533 + } 1.534 + } 1.535 + 1.536 + MOZ_ASSERT(!mWaitingForUpdate); 1.537 + 1.538 + if (aReleaseOnly) 1.539 + return; 1.540 + 1.541 + if (mListeningForChunk == static_cast<int64_t>(chunkIdx)) { 1.542 + // We're already waiting for this chunk 1.543 + LOG(("CacheFileInputStream::EnsureCorrectChunk() - Already listening for " 1.544 + "chunk %lld [this=%p]", mListeningForChunk, this)); 1.545 + 1.546 + return; 1.547 + } 1.548 + 1.549 + rv = mFile->GetChunkLocked(chunkIdx, false, this, getter_AddRefs(mChunk)); 1.550 + if (NS_FAILED(rv)) { 1.551 + LOG(("CacheFileInputStream::EnsureCorrectChunk() - GetChunkLocked failed. " 1.552 + "[this=%p, idx=%d, rv=0x%08x]", this, chunkIdx, rv)); 1.553 + if (rv != NS_ERROR_NOT_AVAILABLE) { 1.554 + // We store the error in mStatus, so we can propagate it later to consumer 1.555 + // in Read(), Available() etc. We need to handle NS_ERROR_NOT_AVAILABLE 1.556 + // differently since it is returned when the requested chunk is not 1.557 + // available and there is no writer that could create it, i.e. it means 1.558 + // that we've reached the end of the file. 1.559 + mStatus = rv; 1.560 + } 1.561 + } 1.562 + else if (!mChunk) { 1.563 + mListeningForChunk = static_cast<int64_t>(chunkIdx); 1.564 + } 1.565 + 1.566 + MaybeNotifyListener(); 1.567 +} 1.568 + 1.569 +void 1.570 +CacheFileInputStream::CanRead(int64_t *aCanRead, const char **aBuf) 1.571 +{ 1.572 + mFile->AssertOwnsLock(); 1.573 + 1.574 + MOZ_ASSERT(mChunk); 1.575 + MOZ_ASSERT(mPos / kChunkSize == mChunk->Index()); 1.576 + 1.577 + uint32_t chunkOffset = mPos - (mPos / kChunkSize) * kChunkSize; 1.578 + *aCanRead = mChunk->DataSize() - chunkOffset; 1.579 + *aBuf = mChunk->BufForReading() + chunkOffset; 1.580 + 1.581 + LOG(("CacheFileInputStream::CanRead() [this=%p, canRead=%lld]", 1.582 + this, *aCanRead)); 1.583 +} 1.584 + 1.585 +void 1.586 +CacheFileInputStream::NotifyListener() 1.587 +{ 1.588 + mFile->AssertOwnsLock(); 1.589 + 1.590 + LOG(("CacheFileInputStream::NotifyListener() [this=%p]", this)); 1.591 + 1.592 + MOZ_ASSERT(mCallback); 1.593 + 1.594 + if (!mCallbackTarget) 1.595 + mCallbackTarget = NS_GetCurrentThread(); 1.596 + 1.597 + nsCOMPtr<nsIInputStreamCallback> asyncCallback = 1.598 + NS_NewInputStreamReadyEvent(mCallback, mCallbackTarget); 1.599 + 1.600 + mCallback = nullptr; 1.601 + mCallbackTarget = nullptr; 1.602 + 1.603 + asyncCallback->OnInputStreamReady(this); 1.604 +} 1.605 + 1.606 +void 1.607 +CacheFileInputStream::MaybeNotifyListener() 1.608 +{ 1.609 + mFile->AssertOwnsLock(); 1.610 + 1.611 + LOG(("CacheFileInputStream::MaybeNotifyListener() [this=%p, mCallback=%p, " 1.612 + "mClosed=%d, mStatus=0x%08x, mChunk=%p, mListeningForChunk=%lld, " 1.613 + "mWaitingForUpdate=%d]", this, mCallback.get(), mClosed, mStatus, 1.614 + mChunk.get(), mListeningForChunk, mWaitingForUpdate)); 1.615 + 1.616 + if (!mCallback) 1.617 + return; 1.618 + 1.619 + if (mClosed || NS_FAILED(mStatus)) { 1.620 + NotifyListener(); 1.621 + return; 1.622 + } 1.623 + 1.624 + if (!mChunk) { 1.625 + if (mListeningForChunk == -1) { 1.626 + // EOF, should we notify even if mCallbackFlags == WAIT_CLOSURE_ONLY ?? 1.627 + NotifyListener(); 1.628 + } 1.629 + return; 1.630 + } 1.631 + 1.632 + MOZ_ASSERT(mPos / kChunkSize == mChunk->Index()); 1.633 + 1.634 + if (mWaitingForUpdate) 1.635 + return; 1.636 + 1.637 + int64_t canRead; 1.638 + const char *buf; 1.639 + CanRead(&canRead, &buf); 1.640 + 1.641 + if (canRead > 0) { 1.642 + if (!(mCallbackFlags & WAIT_CLOSURE_ONLY)) 1.643 + NotifyListener(); 1.644 + } 1.645 + else if (canRead == 0) { 1.646 + if (!mFile->mOutput) { 1.647 + // EOF 1.648 + NotifyListener(); 1.649 + } 1.650 + else { 1.651 + mChunk->WaitForUpdate(this); 1.652 + mWaitingForUpdate = true; 1.653 + } 1.654 + } 1.655 + else { 1.656 + // Output have set EOF before mPos? 1.657 + MOZ_ASSERT(false, "SetEOF is currenty not implemented?!"); 1.658 + NotifyListener(); 1.659 + } 1.660 +} 1.661 + 1.662 +// Memory reporting 1.663 + 1.664 +size_t 1.665 +CacheFileInputStream::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const 1.666 +{ 1.667 + // Everything the stream keeps a reference to is already reported somewhere else. 1.668 + // mFile reports itself. 1.669 + // mChunk reported as part of CacheFile. 1.670 + // mCallback is usually CacheFile or a class that is reported elsewhere. 1.671 + return mallocSizeOf(this); 1.672 +} 1.673 + 1.674 +} // net 1.675 +} // mozilla