|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 #include "CacheLog.h" |
|
6 #include "CacheFileInputStream.h" |
|
7 |
|
8 #include "CacheFile.h" |
|
9 #include "nsStreamUtils.h" |
|
10 #include "nsThreadUtils.h" |
|
11 #include <algorithm> |
|
12 |
|
13 namespace mozilla { |
|
14 namespace net { |
|
15 |
|
16 NS_IMPL_ADDREF(CacheFileInputStream) |
|
17 NS_IMETHODIMP_(MozExternalRefCountType) |
|
18 CacheFileInputStream::Release() |
|
19 { |
|
20 NS_PRECONDITION(0 != mRefCnt, "dup release"); |
|
21 nsrefcnt count = --mRefCnt; |
|
22 NS_LOG_RELEASE(this, count, "CacheFileInputStream"); |
|
23 |
|
24 if (0 == count) { |
|
25 mRefCnt = 1; |
|
26 delete (this); |
|
27 return 0; |
|
28 } |
|
29 |
|
30 if (count == 1) { |
|
31 mFile->RemoveInput(this); |
|
32 } |
|
33 |
|
34 return count; |
|
35 } |
|
36 |
|
37 NS_INTERFACE_MAP_BEGIN(CacheFileInputStream) |
|
38 NS_INTERFACE_MAP_ENTRY(nsIInputStream) |
|
39 NS_INTERFACE_MAP_ENTRY(nsIAsyncInputStream) |
|
40 NS_INTERFACE_MAP_ENTRY(nsISeekableStream) |
|
41 NS_INTERFACE_MAP_ENTRY(mozilla::net::CacheFileChunkListener) |
|
42 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream) |
|
43 NS_INTERFACE_MAP_END_THREADSAFE |
|
44 |
|
45 CacheFileInputStream::CacheFileInputStream(CacheFile *aFile) |
|
46 : mFile(aFile) |
|
47 , mPos(0) |
|
48 , mClosed(false) |
|
49 , mStatus(NS_OK) |
|
50 , mWaitingForUpdate(false) |
|
51 , mListeningForChunk(-1) |
|
52 , mInReadSegments(false) |
|
53 , mCallbackFlags(0) |
|
54 { |
|
55 LOG(("CacheFileInputStream::CacheFileInputStream() [this=%p]", this)); |
|
56 MOZ_COUNT_CTOR(CacheFileInputStream); |
|
57 } |
|
58 |
|
59 CacheFileInputStream::~CacheFileInputStream() |
|
60 { |
|
61 LOG(("CacheFileInputStream::~CacheFileInputStream() [this=%p]", this)); |
|
62 MOZ_COUNT_DTOR(CacheFileInputStream); |
|
63 } |
|
64 |
|
65 // nsIInputStream |
|
66 NS_IMETHODIMP |
|
67 CacheFileInputStream::Close() |
|
68 { |
|
69 LOG(("CacheFileInputStream::Close() [this=%p]", this)); |
|
70 return CloseWithStatus(NS_OK); |
|
71 } |
|
72 |
|
73 NS_IMETHODIMP |
|
74 CacheFileInputStream::Available(uint64_t *_retval) |
|
75 { |
|
76 CacheFileAutoLock lock(mFile); |
|
77 MOZ_ASSERT(!mInReadSegments); |
|
78 |
|
79 if (mClosed) { |
|
80 LOG(("CacheFileInputStream::Available() - Stream is closed. [this=%p, " |
|
81 "status=0x%08x]", this, mStatus)); |
|
82 return NS_FAILED(mStatus) ? mStatus : NS_BASE_STREAM_CLOSED; |
|
83 } |
|
84 |
|
85 EnsureCorrectChunk(false); |
|
86 if (NS_FAILED(mStatus)) |
|
87 return mStatus; |
|
88 |
|
89 *_retval = 0; |
|
90 |
|
91 if (mChunk) { |
|
92 int64_t canRead; |
|
93 const char *buf; |
|
94 CanRead(&canRead, &buf); |
|
95 |
|
96 if (canRead > 0) |
|
97 *_retval = canRead; |
|
98 else if (canRead == 0 && !mFile->mOutput) |
|
99 return NS_BASE_STREAM_CLOSED; |
|
100 } |
|
101 |
|
102 LOG(("CacheFileInputStream::Available() [this=%p, retval=%lld]", |
|
103 this, *_retval)); |
|
104 |
|
105 return NS_OK; |
|
106 } |
|
107 |
|
108 NS_IMETHODIMP |
|
109 CacheFileInputStream::Read(char *aBuf, uint32_t aCount, uint32_t *_retval) |
|
110 { |
|
111 CacheFileAutoLock lock(mFile); |
|
112 MOZ_ASSERT(!mInReadSegments); |
|
113 |
|
114 LOG(("CacheFileInputStream::Read() [this=%p, count=%d]", this, aCount)); |
|
115 |
|
116 nsresult rv; |
|
117 |
|
118 if (mClosed) { |
|
119 LOG(("CacheFileInputStream::Read() - Stream is closed. [this=%p, " |
|
120 "status=0x%08x]", this, mStatus)); |
|
121 |
|
122 if NS_FAILED(mStatus) |
|
123 return mStatus; |
|
124 |
|
125 *_retval = 0; |
|
126 return NS_OK; |
|
127 } |
|
128 |
|
129 EnsureCorrectChunk(false); |
|
130 if (NS_FAILED(mStatus)) |
|
131 return mStatus; |
|
132 |
|
133 if (!mChunk) { |
|
134 if (mListeningForChunk == -1) { |
|
135 LOG((" no chunk, returning 0 read and NS_OK")); |
|
136 *_retval = 0; |
|
137 return NS_OK; |
|
138 } |
|
139 else { |
|
140 LOG((" waiting for chuck, returning WOULD_BLOCK")); |
|
141 return NS_BASE_STREAM_WOULD_BLOCK; |
|
142 } |
|
143 } |
|
144 |
|
145 int64_t canRead; |
|
146 const char *buf; |
|
147 CanRead(&canRead, &buf); |
|
148 |
|
149 if (canRead < 0) { |
|
150 // file was truncated ??? |
|
151 MOZ_ASSERT(false, "SetEOF is currenty not implemented?!"); |
|
152 *_retval = 0; |
|
153 rv = NS_OK; |
|
154 } |
|
155 else if (canRead > 0) { |
|
156 *_retval = std::min(static_cast<uint32_t>(canRead), aCount); |
|
157 memcpy(aBuf, buf, *_retval); |
|
158 mPos += *_retval; |
|
159 |
|
160 EnsureCorrectChunk(!(canRead < aCount && mPos % kChunkSize == 0)); |
|
161 |
|
162 rv = NS_OK; |
|
163 } |
|
164 else { |
|
165 if (mFile->mOutput) |
|
166 rv = NS_BASE_STREAM_WOULD_BLOCK; |
|
167 else { |
|
168 *_retval = 0; |
|
169 rv = NS_OK; |
|
170 } |
|
171 } |
|
172 |
|
173 LOG(("CacheFileInputStream::Read() [this=%p, rv=0x%08x, retval=%d", |
|
174 this, rv, *_retval)); |
|
175 |
|
176 return rv; |
|
177 } |
|
178 |
|
179 NS_IMETHODIMP |
|
180 CacheFileInputStream::ReadSegments(nsWriteSegmentFun aWriter, void *aClosure, |
|
181 uint32_t aCount, uint32_t *_retval) |
|
182 { |
|
183 CacheFileAutoLock lock(mFile); |
|
184 MOZ_ASSERT(!mInReadSegments); |
|
185 |
|
186 LOG(("CacheFileInputStream::ReadSegments() [this=%p, count=%d]", |
|
187 this, aCount)); |
|
188 |
|
189 nsresult rv; |
|
190 |
|
191 if (mClosed) { |
|
192 LOG(("CacheFileInputStream::ReadSegments() - Stream is closed. [this=%p, " |
|
193 "status=0x%08x]", this, mStatus)); |
|
194 |
|
195 if NS_FAILED(mStatus) |
|
196 return mStatus; |
|
197 |
|
198 *_retval = 0; |
|
199 return NS_OK; |
|
200 } |
|
201 |
|
202 EnsureCorrectChunk(false); |
|
203 if (NS_FAILED(mStatus)) |
|
204 return mStatus; |
|
205 |
|
206 if (!mChunk) { |
|
207 if (mListeningForChunk == -1) { |
|
208 *_retval = 0; |
|
209 return NS_OK; |
|
210 } |
|
211 else { |
|
212 return NS_BASE_STREAM_WOULD_BLOCK; |
|
213 } |
|
214 } |
|
215 |
|
216 int64_t canRead; |
|
217 const char *buf; |
|
218 CanRead(&canRead, &buf); |
|
219 |
|
220 if (canRead < 0) { |
|
221 // file was truncated ??? |
|
222 MOZ_ASSERT(false, "SetEOF is currenty not implemented?!"); |
|
223 *_retval = 0; |
|
224 rv = NS_OK; |
|
225 } |
|
226 else if (canRead > 0) { |
|
227 uint32_t toRead = std::min(static_cast<uint32_t>(canRead), aCount); |
|
228 |
|
229 // We need to release the lock to avoid lock re-entering |
|
230 #ifdef DEBUG |
|
231 int64_t oldPos = mPos; |
|
232 #endif |
|
233 mInReadSegments = true; |
|
234 lock.Unlock(); |
|
235 rv = aWriter(this, aClosure, buf, 0, toRead, _retval); |
|
236 lock.Lock(); |
|
237 mInReadSegments = false; |
|
238 #ifdef DEBUG |
|
239 MOZ_ASSERT(oldPos == mPos); |
|
240 #endif |
|
241 |
|
242 if (NS_SUCCEEDED(rv)) { |
|
243 MOZ_ASSERT(*_retval <= toRead, |
|
244 "writer should not write more than we asked it to write"); |
|
245 mPos += *_retval; |
|
246 } |
|
247 |
|
248 EnsureCorrectChunk(!(canRead < aCount && mPos % kChunkSize == 0)); |
|
249 |
|
250 rv = NS_OK; |
|
251 } |
|
252 else { |
|
253 if (mFile->mOutput) |
|
254 rv = NS_BASE_STREAM_WOULD_BLOCK; |
|
255 else { |
|
256 *_retval = 0; |
|
257 rv = NS_OK; |
|
258 } |
|
259 } |
|
260 |
|
261 LOG(("CacheFileInputStream::ReadSegments() [this=%p, rv=0x%08x, retval=%d", |
|
262 this, rv, *_retval)); |
|
263 |
|
264 return rv; |
|
265 } |
|
266 |
|
267 NS_IMETHODIMP |
|
268 CacheFileInputStream::IsNonBlocking(bool *_retval) |
|
269 { |
|
270 *_retval = true; |
|
271 return NS_OK; |
|
272 } |
|
273 |
|
274 // nsIAsyncInputStream |
|
275 NS_IMETHODIMP |
|
276 CacheFileInputStream::CloseWithStatus(nsresult aStatus) |
|
277 { |
|
278 CacheFileAutoLock lock(mFile); |
|
279 MOZ_ASSERT(!mInReadSegments); |
|
280 |
|
281 LOG(("CacheFileInputStream::CloseWithStatus() [this=%p, aStatus=0x%08x]", |
|
282 this, aStatus)); |
|
283 |
|
284 if (mClosed) { |
|
285 MOZ_ASSERT(!mCallback); |
|
286 return NS_OK; |
|
287 } |
|
288 |
|
289 mClosed = true; |
|
290 mStatus = NS_FAILED(aStatus) ? aStatus : NS_BASE_STREAM_CLOSED; |
|
291 |
|
292 if (mChunk) |
|
293 ReleaseChunk(); |
|
294 |
|
295 // TODO propagate error from input stream to other streams ??? |
|
296 |
|
297 MaybeNotifyListener(); |
|
298 |
|
299 return NS_OK; |
|
300 } |
|
301 |
|
302 NS_IMETHODIMP |
|
303 CacheFileInputStream::AsyncWait(nsIInputStreamCallback *aCallback, |
|
304 uint32_t aFlags, |
|
305 uint32_t aRequestedCount, |
|
306 nsIEventTarget *aEventTarget) |
|
307 { |
|
308 CacheFileAutoLock lock(mFile); |
|
309 MOZ_ASSERT(!mInReadSegments); |
|
310 |
|
311 LOG(("CacheFileInputStream::AsyncWait() [this=%p, callback=%p, flags=%d, " |
|
312 "requestedCount=%d, eventTarget=%p]", this, aCallback, aFlags, |
|
313 aRequestedCount, aEventTarget)); |
|
314 |
|
315 mCallback = aCallback; |
|
316 mCallbackFlags = aFlags; |
|
317 |
|
318 if (!mCallback) { |
|
319 if (mWaitingForUpdate) { |
|
320 mChunk->CancelWait(this); |
|
321 mWaitingForUpdate = false; |
|
322 } |
|
323 return NS_OK; |
|
324 } |
|
325 |
|
326 if (mClosed) { |
|
327 NotifyListener(); |
|
328 return NS_OK; |
|
329 } |
|
330 |
|
331 EnsureCorrectChunk(false); |
|
332 |
|
333 MaybeNotifyListener(); |
|
334 |
|
335 return NS_OK; |
|
336 } |
|
337 |
|
338 // nsISeekableStream |
|
339 NS_IMETHODIMP |
|
340 CacheFileInputStream::Seek(int32_t whence, int64_t offset) |
|
341 { |
|
342 CacheFileAutoLock lock(mFile); |
|
343 MOZ_ASSERT(!mInReadSegments); |
|
344 |
|
345 LOG(("CacheFileInputStream::Seek() [this=%p, whence=%d, offset=%lld]", |
|
346 this, whence, offset)); |
|
347 |
|
348 if (mClosed) { |
|
349 LOG(("CacheFileInputStream::Seek() - Stream is closed. [this=%p]", this)); |
|
350 return NS_BASE_STREAM_CLOSED; |
|
351 } |
|
352 |
|
353 int64_t newPos = offset; |
|
354 switch (whence) { |
|
355 case NS_SEEK_SET: |
|
356 break; |
|
357 case NS_SEEK_CUR: |
|
358 newPos += mPos; |
|
359 break; |
|
360 case NS_SEEK_END: |
|
361 newPos += mFile->mDataSize; |
|
362 break; |
|
363 default: |
|
364 NS_ERROR("invalid whence"); |
|
365 return NS_ERROR_INVALID_ARG; |
|
366 } |
|
367 mPos = newPos; |
|
368 EnsureCorrectChunk(true); |
|
369 |
|
370 LOG(("CacheFileInputStream::Seek() [this=%p, pos=%lld]", this, mPos)); |
|
371 return NS_OK; |
|
372 } |
|
373 |
|
374 NS_IMETHODIMP |
|
375 CacheFileInputStream::Tell(int64_t *_retval) |
|
376 { |
|
377 CacheFileAutoLock lock(mFile); |
|
378 MOZ_ASSERT(!mInReadSegments); |
|
379 |
|
380 if (mClosed) { |
|
381 LOG(("CacheFileInputStream::Tell() - Stream is closed. [this=%p]", this)); |
|
382 return NS_BASE_STREAM_CLOSED; |
|
383 } |
|
384 |
|
385 *_retval = mPos; |
|
386 |
|
387 LOG(("CacheFileInputStream::Tell() [this=%p, retval=%lld]", this, *_retval)); |
|
388 return NS_OK; |
|
389 } |
|
390 |
|
391 NS_IMETHODIMP |
|
392 CacheFileInputStream::SetEOF() |
|
393 { |
|
394 MOZ_ASSERT(false, "Don't call SetEOF on cache input stream"); |
|
395 return NS_ERROR_NOT_IMPLEMENTED; |
|
396 } |
|
397 |
|
398 // CacheFileChunkListener |
|
399 nsresult |
|
400 CacheFileInputStream::OnChunkRead(nsresult aResult, CacheFileChunk *aChunk) |
|
401 { |
|
402 MOZ_CRASH("CacheFileInputStream::OnChunkRead should not be called!"); |
|
403 return NS_ERROR_UNEXPECTED; |
|
404 } |
|
405 |
|
406 nsresult |
|
407 CacheFileInputStream::OnChunkWritten(nsresult aResult, CacheFileChunk *aChunk) |
|
408 { |
|
409 MOZ_CRASH("CacheFileInputStream::OnChunkWritten should not be called!"); |
|
410 return NS_ERROR_UNEXPECTED; |
|
411 } |
|
412 |
|
413 nsresult |
|
414 CacheFileInputStream::OnChunkAvailable(nsresult aResult, uint32_t aChunkIdx, |
|
415 CacheFileChunk *aChunk) |
|
416 { |
|
417 CacheFileAutoLock lock(mFile); |
|
418 MOZ_ASSERT(!mInReadSegments); |
|
419 |
|
420 LOG(("CacheFileInputStream::OnChunkAvailable() [this=%p, result=0x%08x, " |
|
421 "idx=%d, chunk=%p]", this, aResult, aChunkIdx, aChunk)); |
|
422 |
|
423 MOZ_ASSERT(mListeningForChunk != -1); |
|
424 |
|
425 if (mListeningForChunk != static_cast<int64_t>(aChunkIdx)) { |
|
426 // This is not a chunk that we're waiting for |
|
427 LOG(("CacheFileInputStream::OnChunkAvailable() - Notification is for a " |
|
428 "different chunk. [this=%p, listeningForChunk=%lld]", |
|
429 this, mListeningForChunk)); |
|
430 |
|
431 return NS_OK; |
|
432 } |
|
433 |
|
434 MOZ_ASSERT(!mChunk); |
|
435 MOZ_ASSERT(!mWaitingForUpdate); |
|
436 mListeningForChunk = -1; |
|
437 |
|
438 if (mClosed) { |
|
439 MOZ_ASSERT(!mCallback); |
|
440 |
|
441 LOG(("CacheFileInputStream::OnChunkAvailable() - Stream is closed, " |
|
442 "ignoring notification. [this=%p]", this)); |
|
443 |
|
444 return NS_OK; |
|
445 } |
|
446 |
|
447 if (NS_SUCCEEDED(aResult)) { |
|
448 mChunk = aChunk; |
|
449 } else if (aResult != NS_ERROR_NOT_AVAILABLE) { |
|
450 // We store the error in mStatus, so we can propagate it later to consumer |
|
451 // in Read(), Available() etc. We need to handle NS_ERROR_NOT_AVAILABLE |
|
452 // differently since it is returned when the requested chunk is not |
|
453 // available and there is no writer that could create it, i.e. it means that |
|
454 // we've reached the end of the file. |
|
455 mStatus = aResult; |
|
456 } |
|
457 |
|
458 MaybeNotifyListener(); |
|
459 |
|
460 return NS_OK; |
|
461 } |
|
462 |
|
463 nsresult |
|
464 CacheFileInputStream::OnChunkUpdated(CacheFileChunk *aChunk) |
|
465 { |
|
466 CacheFileAutoLock lock(mFile); |
|
467 MOZ_ASSERT(!mInReadSegments); |
|
468 |
|
469 LOG(("CacheFileInputStream::OnChunkUpdated() [this=%p, idx=%d]", |
|
470 this, aChunk->Index())); |
|
471 |
|
472 if (!mWaitingForUpdate) { |
|
473 LOG(("CacheFileInputStream::OnChunkUpdated() - Ignoring notification since " |
|
474 "mWaitingforUpdate == false. [this=%p]", this)); |
|
475 |
|
476 return NS_OK; |
|
477 } |
|
478 else { |
|
479 mWaitingForUpdate = false; |
|
480 } |
|
481 |
|
482 MOZ_ASSERT(mChunk == aChunk); |
|
483 |
|
484 MaybeNotifyListener(); |
|
485 |
|
486 return NS_OK; |
|
487 } |
|
488 |
|
489 void |
|
490 CacheFileInputStream::ReleaseChunk() |
|
491 { |
|
492 mFile->AssertOwnsLock(); |
|
493 |
|
494 LOG(("CacheFileInputStream::ReleaseChunk() [this=%p, idx=%d]", |
|
495 this, mChunk->Index())); |
|
496 |
|
497 if (mWaitingForUpdate) { |
|
498 LOG(("CacheFileInputStream::ReleaseChunk() - Canceling waiting for update. " |
|
499 "[this=%p]", this)); |
|
500 |
|
501 mChunk->CancelWait(this); |
|
502 mWaitingForUpdate = false; |
|
503 } |
|
504 |
|
505 mFile->ReleaseOutsideLock(mChunk.forget().take()); |
|
506 } |
|
507 |
|
508 void |
|
509 CacheFileInputStream::EnsureCorrectChunk(bool aReleaseOnly) |
|
510 { |
|
511 mFile->AssertOwnsLock(); |
|
512 |
|
513 LOG(("CacheFileInputStream::EnsureCorrectChunk() [this=%p, releaseOnly=%d]", |
|
514 this, aReleaseOnly)); |
|
515 |
|
516 nsresult rv; |
|
517 |
|
518 uint32_t chunkIdx = mPos / kChunkSize; |
|
519 |
|
520 if (mChunk) { |
|
521 if (mChunk->Index() == chunkIdx) { |
|
522 // we have a correct chunk |
|
523 LOG(("CacheFileInputStream::EnsureCorrectChunk() - Have correct chunk " |
|
524 "[this=%p, idx=%d]", this, chunkIdx)); |
|
525 |
|
526 return; |
|
527 } |
|
528 else { |
|
529 ReleaseChunk(); |
|
530 } |
|
531 } |
|
532 |
|
533 MOZ_ASSERT(!mWaitingForUpdate); |
|
534 |
|
535 if (aReleaseOnly) |
|
536 return; |
|
537 |
|
538 if (mListeningForChunk == static_cast<int64_t>(chunkIdx)) { |
|
539 // We're already waiting for this chunk |
|
540 LOG(("CacheFileInputStream::EnsureCorrectChunk() - Already listening for " |
|
541 "chunk %lld [this=%p]", mListeningForChunk, this)); |
|
542 |
|
543 return; |
|
544 } |
|
545 |
|
546 rv = mFile->GetChunkLocked(chunkIdx, false, this, getter_AddRefs(mChunk)); |
|
547 if (NS_FAILED(rv)) { |
|
548 LOG(("CacheFileInputStream::EnsureCorrectChunk() - GetChunkLocked failed. " |
|
549 "[this=%p, idx=%d, rv=0x%08x]", this, chunkIdx, rv)); |
|
550 if (rv != NS_ERROR_NOT_AVAILABLE) { |
|
551 // We store the error in mStatus, so we can propagate it later to consumer |
|
552 // in Read(), Available() etc. We need to handle NS_ERROR_NOT_AVAILABLE |
|
553 // differently since it is returned when the requested chunk is not |
|
554 // available and there is no writer that could create it, i.e. it means |
|
555 // that we've reached the end of the file. |
|
556 mStatus = rv; |
|
557 } |
|
558 } |
|
559 else if (!mChunk) { |
|
560 mListeningForChunk = static_cast<int64_t>(chunkIdx); |
|
561 } |
|
562 |
|
563 MaybeNotifyListener(); |
|
564 } |
|
565 |
|
566 void |
|
567 CacheFileInputStream::CanRead(int64_t *aCanRead, const char **aBuf) |
|
568 { |
|
569 mFile->AssertOwnsLock(); |
|
570 |
|
571 MOZ_ASSERT(mChunk); |
|
572 MOZ_ASSERT(mPos / kChunkSize == mChunk->Index()); |
|
573 |
|
574 uint32_t chunkOffset = mPos - (mPos / kChunkSize) * kChunkSize; |
|
575 *aCanRead = mChunk->DataSize() - chunkOffset; |
|
576 *aBuf = mChunk->BufForReading() + chunkOffset; |
|
577 |
|
578 LOG(("CacheFileInputStream::CanRead() [this=%p, canRead=%lld]", |
|
579 this, *aCanRead)); |
|
580 } |
|
581 |
|
582 void |
|
583 CacheFileInputStream::NotifyListener() |
|
584 { |
|
585 mFile->AssertOwnsLock(); |
|
586 |
|
587 LOG(("CacheFileInputStream::NotifyListener() [this=%p]", this)); |
|
588 |
|
589 MOZ_ASSERT(mCallback); |
|
590 |
|
591 if (!mCallbackTarget) |
|
592 mCallbackTarget = NS_GetCurrentThread(); |
|
593 |
|
594 nsCOMPtr<nsIInputStreamCallback> asyncCallback = |
|
595 NS_NewInputStreamReadyEvent(mCallback, mCallbackTarget); |
|
596 |
|
597 mCallback = nullptr; |
|
598 mCallbackTarget = nullptr; |
|
599 |
|
600 asyncCallback->OnInputStreamReady(this); |
|
601 } |
|
602 |
|
603 void |
|
604 CacheFileInputStream::MaybeNotifyListener() |
|
605 { |
|
606 mFile->AssertOwnsLock(); |
|
607 |
|
608 LOG(("CacheFileInputStream::MaybeNotifyListener() [this=%p, mCallback=%p, " |
|
609 "mClosed=%d, mStatus=0x%08x, mChunk=%p, mListeningForChunk=%lld, " |
|
610 "mWaitingForUpdate=%d]", this, mCallback.get(), mClosed, mStatus, |
|
611 mChunk.get(), mListeningForChunk, mWaitingForUpdate)); |
|
612 |
|
613 if (!mCallback) |
|
614 return; |
|
615 |
|
616 if (mClosed || NS_FAILED(mStatus)) { |
|
617 NotifyListener(); |
|
618 return; |
|
619 } |
|
620 |
|
621 if (!mChunk) { |
|
622 if (mListeningForChunk == -1) { |
|
623 // EOF, should we notify even if mCallbackFlags == WAIT_CLOSURE_ONLY ?? |
|
624 NotifyListener(); |
|
625 } |
|
626 return; |
|
627 } |
|
628 |
|
629 MOZ_ASSERT(mPos / kChunkSize == mChunk->Index()); |
|
630 |
|
631 if (mWaitingForUpdate) |
|
632 return; |
|
633 |
|
634 int64_t canRead; |
|
635 const char *buf; |
|
636 CanRead(&canRead, &buf); |
|
637 |
|
638 if (canRead > 0) { |
|
639 if (!(mCallbackFlags & WAIT_CLOSURE_ONLY)) |
|
640 NotifyListener(); |
|
641 } |
|
642 else if (canRead == 0) { |
|
643 if (!mFile->mOutput) { |
|
644 // EOF |
|
645 NotifyListener(); |
|
646 } |
|
647 else { |
|
648 mChunk->WaitForUpdate(this); |
|
649 mWaitingForUpdate = true; |
|
650 } |
|
651 } |
|
652 else { |
|
653 // Output have set EOF before mPos? |
|
654 MOZ_ASSERT(false, "SetEOF is currenty not implemented?!"); |
|
655 NotifyListener(); |
|
656 } |
|
657 } |
|
658 |
|
659 // Memory reporting |
|
660 |
|
661 size_t |
|
662 CacheFileInputStream::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const |
|
663 { |
|
664 // Everything the stream keeps a reference to is already reported somewhere else. |
|
665 // mFile reports itself. |
|
666 // mChunk reported as part of CacheFile. |
|
667 // mCallback is usually CacheFile or a class that is reported elsewhere. |
|
668 return mallocSizeOf(this); |
|
669 } |
|
670 |
|
671 } // net |
|
672 } // mozilla |