1 : /* ***** BEGIN LICENSE BLOCK *****
2 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 : *
4 : * The contents of this file are subject to the Mozilla Public License Version
5 : * 1.1 (the "License"); you may not use this file except in compliance with
6 : * the License. You may obtain a copy of the License at
7 : * http://www.mozilla.org/MPL/
8 : *
9 : * Software distributed under the License is distributed on an "AS IS" basis,
10 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 : * for the specific language governing rights and limitations under the
12 : * License.
13 : *
14 : * The Original Code is Mozilla.
15 : *
16 : * The Initial Developer of the Original Code is
17 : * Netscape Communications Corporation.
18 : * Portions created by the Initial Developer are Copyright (C) 2002
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Darin Fisher <darin@netscape.com>
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "mozilla/ReentrantMonitor.h"
39 : #include "nsIPipe.h"
40 : #include "nsIEventTarget.h"
41 : #include "nsISeekableStream.h"
42 : #include "nsIProgrammingLanguage.h"
43 : #include "nsSegmentedBuffer.h"
44 : #include "nsStreamUtils.h"
45 : #include "nsCOMPtr.h"
46 : #include "nsCRT.h"
47 : #include "prlog.h"
48 : #include "nsIClassInfoImpl.h"
49 : #include "nsAtomicRefcnt.h"
50 : #include "nsAlgorithm.h"
51 :
52 : using namespace mozilla;
53 :
54 : #if defined(PR_LOGGING)
55 : //
56 : // set NSPR_LOG_MODULES=nsPipe:5
57 : //
58 1396 : static PRLogModuleInfo *gPipeLog = PR_NewLogModule("nsPipe");
59 : #define LOG(args) PR_LOG(gPipeLog, PR_LOG_DEBUG, args)
60 : #else
61 : #define LOG(args)
62 : #endif
63 :
64 : #define DEFAULT_SEGMENT_SIZE 4096
65 : #define DEFAULT_SEGMENT_COUNT 16
66 :
67 : class nsPipe;
68 : class nsPipeEvents;
69 : class nsPipeInputStream;
70 : class nsPipeOutputStream;
71 :
72 : //-----------------------------------------------------------------------------
73 :
74 : // this class is used to delay notifications until the end of a particular
75 : // scope. it helps avoid the complexity of issuing callbacks while inside
76 : // a critical section.
77 : class nsPipeEvents
78 : {
79 : public:
80 212259 : nsPipeEvents() { }
81 : ~nsPipeEvents();
82 :
83 28725 : inline void NotifyInputReady(nsIAsyncInputStream *stream,
84 : nsIInputStreamCallback *callback)
85 : {
86 28725 : NS_ASSERTION(!mInputCallback, "already have an input event");
87 28725 : mInputStream = stream;
88 28725 : mInputCallback = callback;
89 28725 : }
90 :
91 12975 : inline void NotifyOutputReady(nsIAsyncOutputStream *stream,
92 : nsIOutputStreamCallback *callback)
93 : {
94 12975 : NS_ASSERTION(!mOutputCallback, "already have an output event");
95 12975 : mOutputStream = stream;
96 12975 : mOutputCallback = callback;
97 12975 : }
98 :
99 : private:
100 : nsCOMPtr<nsIAsyncInputStream> mInputStream;
101 : nsCOMPtr<nsIInputStreamCallback> mInputCallback;
102 : nsCOMPtr<nsIAsyncOutputStream> mOutputStream;
103 : nsCOMPtr<nsIOutputStreamCallback> mOutputCallback;
104 : };
105 :
106 : //-----------------------------------------------------------------------------
107 :
108 : // the input end of a pipe (allocated as a member of the pipe).
109 : class nsPipeInputStream : public nsIAsyncInputStream
110 : , public nsISeekableStream
111 : , public nsISearchableInputStream
112 : , public nsIClassInfo
113 18670 : {
114 : public:
115 : // since this class will be allocated as a member of the pipe, we do not
116 : // need our own ref count. instead, we share the lifetime (the ref count)
117 : // of the entire pipe. this macro is just convenience since it does not
118 : // declare a mRefCount variable; however, don't let the name fool you...
119 : // we are not inheriting from nsPipe ;-)
120 : NS_DECL_ISUPPORTS_INHERITED
121 :
122 : NS_DECL_NSIINPUTSTREAM
123 : NS_DECL_NSIASYNCINPUTSTREAM
124 : NS_DECL_NSISEEKABLESTREAM
125 : NS_DECL_NSISEARCHABLEINPUTSTREAM
126 : NS_DECL_NSICLASSINFO
127 :
128 18685 : nsPipeInputStream(nsPipe *pipe)
129 : : mPipe(pipe)
130 : , mReaderRefCnt(0)
131 : , mLogicalOffset(0)
132 : , mBlocking(true)
133 : , mBlocked(false)
134 : , mAvailable(0)
135 18685 : , mCallbackFlags(0)
136 18685 : { }
137 :
138 : nsresult Fill();
139 18684 : void SetNonBlocking(bool aNonBlocking) { mBlocking = !aNonBlocking; }
140 :
141 18533 : PRUint32 Available() { return mAvailable; }
142 22353 : void ReduceAvailable(PRUint32 avail) { mAvailable -= avail; }
143 :
144 : // synchronously wait for the pipe to become readable.
145 : nsresult Wait();
146 :
147 : // these functions return true to indicate that the pipe's monitor should
148 : // be notified, to wake up a blocked reader if any.
149 : bool OnInputReadable(PRUint32 bytesWritten, nsPipeEvents &);
150 : bool OnInputException(nsresult, nsPipeEvents &);
151 :
152 : private:
153 : nsPipe *mPipe;
154 :
155 : // separate refcnt so that we know when to close the consumer
156 : nsrefcnt mReaderRefCnt;
157 : PRInt64 mLogicalOffset;
158 : bool mBlocking;
159 :
160 : // these variables can only be accessed while inside the pipe's monitor
161 : bool mBlocked;
162 : PRUint32 mAvailable;
163 : nsCOMPtr<nsIInputStreamCallback> mCallback;
164 : PRUint32 mCallbackFlags;
165 : };
166 :
167 : //-----------------------------------------------------------------------------
168 :
169 : // the output end of a pipe (allocated as a member of the pipe).
170 : class nsPipeOutputStream : public nsIAsyncOutputStream
171 : , public nsIClassInfo
172 18670 : {
173 : public:
174 : // since this class will be allocated as a member of the pipe, we do not
175 : // need our own ref count. instead, we share the lifetime (the ref count)
176 : // of the entire pipe. this macro is just convenience since it does not
177 : // declare a mRefCount variable; however, don't let the name fool you...
178 : // we are not inheriting from nsPipe ;-)
179 : NS_DECL_ISUPPORTS_INHERITED
180 :
181 : NS_DECL_NSIOUTPUTSTREAM
182 : NS_DECL_NSIASYNCOUTPUTSTREAM
183 : NS_DECL_NSICLASSINFO
184 :
185 18685 : nsPipeOutputStream(nsPipe *pipe)
186 : : mPipe(pipe)
187 : , mWriterRefCnt(0)
188 : , mLogicalOffset(0)
189 : , mBlocking(true)
190 : , mBlocked(false)
191 : , mWritable(true)
192 18685 : , mCallbackFlags(0)
193 18685 : { }
194 :
195 18684 : void SetNonBlocking(bool aNonBlocking) { mBlocking = !aNonBlocking; }
196 193 : void SetWritable(bool writable) { mWritable = writable; }
197 :
198 : // synchronously wait for the pipe to become writable.
199 : nsresult Wait();
200 :
201 : // these functions return true to indicate that the pipe's monitor should
202 : // be notified, to wake up a blocked writer if any.
203 : bool OnOutputWritable(nsPipeEvents &);
204 : bool OnOutputException(nsresult, nsPipeEvents &);
205 :
206 : private:
207 : nsPipe *mPipe;
208 :
209 : // separate refcnt so that we know when to close the producer
210 : nsrefcnt mWriterRefCnt;
211 : PRInt64 mLogicalOffset;
212 : bool mBlocking;
213 :
214 : // these variables can only be accessed while inside the pipe's monitor
215 : bool mBlocked;
216 : bool mWritable;
217 : nsCOMPtr<nsIOutputStreamCallback> mCallback;
218 : PRUint32 mCallbackFlags;
219 : };
220 :
221 : //-----------------------------------------------------------------------------
222 :
223 : class nsPipe : public nsIPipe
224 : {
225 : public:
226 : friend class nsPipeInputStream;
227 : friend class nsPipeOutputStream;
228 :
229 : NS_DECL_ISUPPORTS
230 : NS_DECL_NSIPIPE
231 :
232 : // nsPipe methods:
233 : nsPipe();
234 :
235 : private:
236 : ~nsPipe();
237 :
238 : public:
239 : //
240 : // methods below may only be called while inside the pipe's monitor
241 : //
242 :
243 : void PeekSegment(PRUint32 n, char *&cursor, char *&limit);
244 :
245 : //
246 : // methods below may be called while outside the pipe's monitor
247 : //
248 :
249 : nsresult GetReadSegment(const char *&segment, PRUint32 &segmentLen);
250 : void AdvanceReadCursor(PRUint32 count);
251 :
252 : nsresult GetWriteSegment(char *&segment, PRUint32 &segmentLen);
253 : void AdvanceWriteCursor(PRUint32 count);
254 :
255 : void OnPipeException(nsresult reason, bool outputOnly = false);
256 :
257 : protected:
258 : // We can't inherit from both nsIInputStream and nsIOutputStream
259 : // because they collide on their Close method. Consequently we nest their
260 : // implementations to avoid the extra object allocation.
261 : nsPipeInputStream mInput;
262 : nsPipeOutputStream mOutput;
263 :
264 : ReentrantMonitor mReentrantMonitor;
265 : nsSegmentedBuffer mBuffer;
266 :
267 : char* mReadCursor;
268 : char* mReadLimit;
269 :
270 : PRInt32 mWriteSegment;
271 : char* mWriteCursor;
272 : char* mWriteLimit;
273 :
274 : nsresult mStatus;
275 : bool mInited;
276 : };
277 :
278 : //
279 : // NOTES on buffer architecture:
280 : //
281 : // +-----------------+ - - mBuffer.GetSegment(0)
282 : // | |
283 : // + - - - - - - - - + - - mReadCursor
284 : // |/////////////////|
285 : // |/////////////////|
286 : // |/////////////////|
287 : // |/////////////////|
288 : // +-----------------+ - - mReadLimit
289 : // |
290 : // +-----------------+
291 : // |/////////////////|
292 : // |/////////////////|
293 : // |/////////////////|
294 : // |/////////////////|
295 : // |/////////////////|
296 : // |/////////////////|
297 : // +-----------------+
298 : // |
299 : // +-----------------+ - - mBuffer.GetSegment(mWriteSegment)
300 : // |/////////////////|
301 : // |/////////////////|
302 : // |/////////////////|
303 : // + - - - - - - - - + - - mWriteCursor
304 : // | |
305 : // | |
306 : // +-----------------+ - - mWriteLimit
307 : //
308 : // (shaded region contains data)
309 : //
310 : // NOTE: on some systems (notably OS/2), the heap allocator uses an arena for
311 : // small allocations (e.g., 64 byte allocations). this means that buffers may
312 : // be allocated back-to-back. in the diagram above, for example, mReadLimit
313 : // would actually be pointing at the beginning of the next segment. when
314 : // making changes to this file, please keep this fact in mind.
315 : //
316 :
317 : //-----------------------------------------------------------------------------
318 : // nsPipe methods:
319 : //-----------------------------------------------------------------------------
320 :
321 18685 : nsPipe::nsPipe()
322 : : mInput(this)
323 : , mOutput(this)
324 : , mReentrantMonitor("nsPipe.mReentrantMonitor")
325 : , mReadCursor(nsnull)
326 : , mReadLimit(nsnull)
327 : , mWriteSegment(-1)
328 : , mWriteCursor(nsnull)
329 : , mWriteLimit(nsnull)
330 : , mStatus(NS_OK)
331 18685 : , mInited(false)
332 : {
333 18685 : }
334 :
335 18670 : nsPipe::~nsPipe()
336 : {
337 18670 : }
338 :
339 1136435 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsPipe, nsIPipe)
340 :
341 : NS_IMETHODIMP
342 18684 : nsPipe::Init(bool nonBlockingIn,
343 : bool nonBlockingOut,
344 : PRUint32 segmentSize,
345 : PRUint32 segmentCount,
346 : nsIMemory *segmentAlloc)
347 : {
348 18684 : mInited = true;
349 :
350 18684 : if (segmentSize == 0)
351 5880 : segmentSize = DEFAULT_SEGMENT_SIZE;
352 18684 : if (segmentCount == 0)
353 92 : segmentCount = DEFAULT_SEGMENT_COUNT;
354 :
355 : // protect against overflow
356 18684 : PRUint32 maxCount = PRUint32(-1) / segmentSize;
357 18684 : if (segmentCount > maxCount)
358 8743 : segmentCount = maxCount;
359 :
360 18684 : nsresult rv = mBuffer.Init(segmentSize, segmentSize * segmentCount, segmentAlloc);
361 18684 : if (NS_FAILED(rv))
362 0 : return rv;
363 :
364 18684 : mInput.SetNonBlocking(nonBlockingIn);
365 18684 : mOutput.SetNonBlocking(nonBlockingOut);
366 18684 : return NS_OK;
367 : }
368 :
369 : NS_IMETHODIMP
370 18696 : nsPipe::GetInputStream(nsIAsyncInputStream **aInputStream)
371 : {
372 18696 : NS_ADDREF(*aInputStream = &mInput);
373 18696 : return NS_OK;
374 : }
375 :
376 : NS_IMETHODIMP
377 21599 : nsPipe::GetOutputStream(nsIAsyncOutputStream **aOutputStream)
378 : {
379 21599 : NS_ENSURE_TRUE(mInited, NS_ERROR_NOT_INITIALIZED);
380 21598 : NS_ADDREF(*aOutputStream = &mOutput);
381 21598 : return NS_OK;
382 : }
383 :
384 : void
385 0 : nsPipe::PeekSegment(PRUint32 index, char *&cursor, char *&limit)
386 : {
387 0 : if (index == 0) {
388 0 : NS_ASSERTION(!mReadCursor || mBuffer.GetSegmentCount(), "unexpected state");
389 0 : cursor = mReadCursor;
390 0 : limit = mReadLimit;
391 : }
392 : else {
393 0 : PRUint32 numSegments = mBuffer.GetSegmentCount();
394 0 : if (index >= numSegments)
395 0 : cursor = limit = nsnull;
396 : else {
397 0 : cursor = mBuffer.GetSegment(index);
398 0 : if (mWriteSegment == (PRInt32) index)
399 0 : limit = mWriteCursor;
400 : else
401 0 : limit = cursor + mBuffer.GetSegmentSize();
402 : }
403 : }
404 0 : }
405 :
406 : nsresult
407 41273 : nsPipe::GetReadSegment(const char *&segment, PRUint32 &segmentLen)
408 : {
409 82546 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
410 :
411 41273 : if (mReadCursor == mReadLimit)
412 18865 : return NS_FAILED(mStatus) ? mStatus : NS_BASE_STREAM_WOULD_BLOCK;
413 :
414 22408 : segment = mReadCursor;
415 22408 : segmentLen = mReadLimit - mReadCursor;
416 22408 : return NS_OK;
417 : }
418 :
419 : void
420 22353 : nsPipe::AdvanceReadCursor(PRUint32 bytesRead)
421 : {
422 22353 : NS_ASSERTION(bytesRead, "don't call if no bytes read");
423 :
424 44706 : nsPipeEvents events;
425 : {
426 44706 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
427 :
428 22353 : LOG(("III advancing read cursor by %u\n", bytesRead));
429 22353 : NS_ASSERTION(bytesRead <= mBuffer.GetSegmentSize(), "read too much");
430 :
431 22353 : mReadCursor += bytesRead;
432 22353 : NS_ASSERTION(mReadCursor <= mReadLimit, "read cursor exceeds limit");
433 :
434 22353 : mInput.ReduceAvailable(bytesRead);
435 :
436 22353 : if (mReadCursor == mReadLimit) {
437 : // we've reached the limit of how much we can read from this segment.
438 : // if at the end of this segment, then we must discard this segment.
439 :
440 : // if still writing in this segment then bail because we're not done
441 : // with the segment and have to wait for now...
442 21346 : if (mWriteSegment == 0 && mWriteLimit > mWriteCursor) {
443 20243 : NS_ASSERTION(mReadLimit == mWriteCursor, "unexpected state");
444 : return;
445 : }
446 :
447 : // shift write segment index (-1 indicates an empty buffer).
448 1103 : --mWriteSegment;
449 :
450 : // done with this segment
451 1103 : mBuffer.DeleteFirstSegment();
452 1103 : LOG(("III deleting first segment\n"));
453 :
454 1103 : if (mWriteSegment == -1) {
455 : // buffer is completely empty
456 148 : mReadCursor = nsnull;
457 148 : mReadLimit = nsnull;
458 148 : mWriteCursor = nsnull;
459 148 : mWriteLimit = nsnull;
460 : }
461 : else {
462 : // advance read cursor and limit to next buffer segment
463 955 : mReadCursor = mBuffer.GetSegment(0);
464 955 : if (mWriteSegment == 0)
465 204 : mReadLimit = mWriteCursor;
466 : else
467 751 : mReadLimit = mReadCursor + mBuffer.GetSegmentSize();
468 : }
469 :
470 : // we've free'd up a segment, so notify output stream that pipe has
471 : // room for a new segment.
472 1103 : if (mOutput.OnOutputWritable(events))
473 0 : mon.Notify();
474 : }
475 : }
476 : }
477 :
478 : nsresult
479 80617 : nsPipe::GetWriteSegment(char *&segment, PRUint32 &segmentLen)
480 : {
481 161234 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
482 :
483 80617 : if (NS_FAILED(mStatus))
484 88 : return mStatus;
485 :
486 : // write cursor and limit may both be null indicating an empty buffer.
487 80529 : if (mWriteCursor == mWriteLimit) {
488 17161 : char *seg = mBuffer.AppendNewSegment();
489 : // pipe is full
490 17161 : if (seg == nsnull)
491 116 : return NS_BASE_STREAM_WOULD_BLOCK;
492 17045 : LOG(("OOO appended new segment\n"));
493 17045 : mWriteCursor = seg;
494 17045 : mWriteLimit = mWriteCursor + mBuffer.GetSegmentSize();
495 17045 : ++mWriteSegment;
496 : }
497 :
498 : // make sure read cursor is initialized
499 80413 : if (mReadCursor == nsnull) {
500 16054 : NS_ASSERTION(mWriteSegment == 0, "unexpected null read cursor");
501 16054 : mReadCursor = mReadLimit = mWriteCursor;
502 : }
503 :
504 : // check to see if we can roll-back our read and write cursors to the
505 : // beginning of the current/first segment. this is purely an optimization.
506 80413 : if (mReadCursor == mWriteCursor && mWriteSegment == 0) {
507 28815 : char *head = mBuffer.GetSegment(0);
508 28815 : LOG(("OOO rolling back write cursor %u bytes\n", mWriteCursor - head));
509 28815 : mWriteCursor = mReadCursor = mReadLimit = head;
510 : }
511 :
512 80413 : segment = mWriteCursor;
513 80413 : segmentLen = mWriteLimit - mWriteCursor;
514 80413 : return NS_OK;
515 : }
516 :
517 : void
518 72079 : nsPipe::AdvanceWriteCursor(PRUint32 bytesWritten)
519 : {
520 72079 : NS_ASSERTION(bytesWritten, "don't call if no bytes written");
521 :
522 144158 : nsPipeEvents events;
523 : {
524 144158 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
525 :
526 72079 : LOG(("OOO advancing write cursor by %u\n", bytesWritten));
527 :
528 72079 : char *newWriteCursor = mWriteCursor + bytesWritten;
529 72079 : NS_ASSERTION(newWriteCursor <= mWriteLimit, "write cursor exceeds limit");
530 :
531 : // update read limit if reading in the same segment
532 72079 : if (mWriteSegment == 0 && mReadLimit == mWriteCursor)
533 21947 : mReadLimit = newWriteCursor;
534 :
535 72079 : mWriteCursor = newWriteCursor;
536 :
537 : // The only way mReadCursor == mWriteCursor is if:
538 : //
539 : // - mReadCursor is at the start of a segment (which, based on how
540 : // nsSegmentedBuffer works, means that this segment is the "first"
541 : // segment)
542 : // - mWriteCursor points at the location past the end of the current
543 : // write segment (so the current write filled the current write
544 : // segment, so we've incremented mWriteCursor to point past the end
545 : // of it)
546 : // - the segment to which data has just been written is located
547 : // exactly one segment's worth of bytes before the first segment
548 : // where mReadCursor is located
549 : //
550 : // Consequently, the byte immediately after the end of the current
551 : // write segment is the first byte of the first segment, so
552 : // mReadCursor == mWriteCursor. (Another way to think about this is
553 : // to consider the buffer architecture diagram above, but consider it
554 : // with an arena allocator which allocates from the *end* of the
555 : // arena to the *beginning* of the arena.)
556 72079 : NS_ASSERTION(mReadCursor != mWriteCursor ||
557 : (mBuffer.GetSegment(0) == mReadCursor &&
558 : mWriteCursor == mWriteLimit),
559 : "read cursor is bad");
560 :
561 : // update the writable flag on the output stream
562 72079 : if (mWriteCursor == mWriteLimit) {
563 1139 : if (mBuffer.GetSize() >= mBuffer.GetMaxSize())
564 193 : mOutput.SetWritable(false);
565 : }
566 :
567 : // notify input stream that pipe now contains additional data
568 72079 : if (mInput.OnInputReadable(bytesWritten, events))
569 0 : mon.Notify();
570 : }
571 72079 : }
572 :
573 : void
574 67115 : nsPipe::OnPipeException(nsresult reason, bool outputOnly)
575 : {
576 67115 : LOG(("PPP nsPipe::OnPipeException [reason=%x output-only=%d]\n",
577 : reason, outputOnly));
578 :
579 134230 : nsPipeEvents events;
580 : {
581 134230 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
582 :
583 : // if we've already hit an exception, then ignore this one.
584 67115 : if (NS_FAILED(mStatus))
585 : return;
586 :
587 18670 : mStatus = reason;
588 :
589 : // an output-only exception applies to the input end if the pipe has
590 : // zero bytes available.
591 18670 : if (outputOnly && !mInput.Available())
592 9906 : outputOnly = false;
593 :
594 18670 : if (!outputOnly)
595 10043 : if (mInput.OnInputException(reason, events))
596 0 : mon.Notify();
597 :
598 18670 : if (mOutput.OnOutputException(reason, events))
599 0 : mon.Notify();
600 : }
601 : }
602 :
603 : //-----------------------------------------------------------------------------
604 : // nsPipeEvents methods:
605 : //-----------------------------------------------------------------------------
606 :
607 424518 : nsPipeEvents::~nsPipeEvents()
608 : {
609 : // dispatch any pending events
610 :
611 212259 : if (mInputCallback) {
612 28725 : mInputCallback->OnInputStreamReady(mInputStream);
613 28725 : mInputCallback = 0;
614 28725 : mInputStream = 0;
615 : }
616 212259 : if (mOutputCallback) {
617 12975 : mOutputCallback->OnOutputStreamReady(mOutputStream);
618 12975 : mOutputCallback = 0;
619 12975 : mOutputStream = 0;
620 : }
621 212259 : }
622 :
623 : //-----------------------------------------------------------------------------
624 : // nsPipeInputStream methods:
625 : //-----------------------------------------------------------------------------
626 :
627 318521 : NS_IMPL_QUERY_INTERFACE5(nsPipeInputStream,
628 : nsIInputStream,
629 : nsIAsyncInputStream,
630 : nsISeekableStream,
631 : nsISearchableInputStream,
632 : nsIClassInfo)
633 :
634 13072 : NS_IMPL_CI_INTERFACE_GETTER4(nsPipeInputStream,
635 : nsIInputStream,
636 : nsIAsyncInputStream,
637 : nsISeekableStream,
638 13072 : nsISearchableInputStream)
639 :
640 39268 : NS_IMPL_THREADSAFE_CI(nsPipeInputStream)
641 :
642 : nsresult
643 0 : nsPipeInputStream::Wait()
644 : {
645 0 : NS_ASSERTION(mBlocking, "wait on non-blocking pipe input stream");
646 :
647 0 : ReentrantMonitorAutoEnter mon(mPipe->mReentrantMonitor);
648 :
649 0 : while (NS_SUCCEEDED(mPipe->mStatus) && (mAvailable == 0)) {
650 0 : LOG(("III pipe input: waiting for data\n"));
651 :
652 0 : mBlocked = true;
653 0 : mon.Wait();
654 0 : mBlocked = false;
655 :
656 0 : LOG(("III pipe input: woke up [pipe-status=%x available=%u]\n",
657 : mPipe->mStatus, mAvailable));
658 : }
659 :
660 0 : return mPipe->mStatus == NS_BASE_STREAM_CLOSED ? NS_OK : mPipe->mStatus;
661 : }
662 :
663 : bool
664 72079 : nsPipeInputStream::OnInputReadable(PRUint32 bytesWritten, nsPipeEvents &events)
665 : {
666 72079 : bool result = false;
667 :
668 72079 : mAvailable += bytesWritten;
669 :
670 72079 : if (mCallback && !(mCallbackFlags & WAIT_CLOSURE_ONLY)) {
671 10622 : events.NotifyInputReady(this, mCallback);
672 10622 : mCallback = 0;
673 10622 : mCallbackFlags = 0;
674 : }
675 61457 : else if (mBlocked)
676 0 : result = true;
677 :
678 72079 : return result;
679 : }
680 :
681 : bool
682 10043 : nsPipeInputStream::OnInputException(nsresult reason, nsPipeEvents &events)
683 : {
684 10043 : LOG(("nsPipeInputStream::OnInputException [this=%x reason=%x]\n",
685 : this, reason));
686 :
687 10043 : bool result = false;
688 :
689 10043 : NS_ASSERTION(NS_FAILED(reason), "huh? successful exception");
690 :
691 : // force count of available bytes to zero.
692 10043 : mAvailable = 0;
693 :
694 10043 : if (mCallback) {
695 3425 : events.NotifyInputReady(this, mCallback);
696 3425 : mCallback = 0;
697 3425 : mCallbackFlags = 0;
698 : }
699 6618 : else if (mBlocked)
700 0 : result = true;
701 :
702 10043 : return result;
703 : }
704 :
705 : NS_IMETHODIMP_(nsrefcnt)
706 309379 : nsPipeInputStream::AddRef(void)
707 : {
708 309379 : NS_AtomicIncrementRefcnt(mReaderRefCnt);
709 309379 : return mPipe->AddRef();
710 : }
711 :
712 : NS_IMETHODIMP_(nsrefcnt)
713 309349 : nsPipeInputStream::Release(void)
714 : {
715 309349 : if (NS_AtomicDecrementRefcnt(mReaderRefCnt) == 0)
716 18669 : Close();
717 309349 : return mPipe->Release();
718 : }
719 :
720 : NS_IMETHODIMP
721 31120 : nsPipeInputStream::CloseWithStatus(nsresult reason)
722 : {
723 31120 : LOG(("III CloseWithStatus [this=%x reason=%x]\n", this, reason));
724 :
725 31120 : if (NS_SUCCEEDED(reason))
726 8285 : reason = NS_BASE_STREAM_CLOSED;
727 :
728 31120 : mPipe->OnPipeException(reason);
729 31120 : return NS_OK;
730 : }
731 :
732 : NS_IMETHODIMP
733 22287 : nsPipeInputStream::Close()
734 : {
735 22287 : return CloseWithStatus(NS_BASE_STREAM_CLOSED);
736 : }
737 :
738 : NS_IMETHODIMP
739 31560 : nsPipeInputStream::Available(PRUint32 *result)
740 : {
741 63120 : ReentrantMonitorAutoEnter mon(mPipe->mReentrantMonitor);
742 :
743 : // return error if pipe closed
744 31560 : if (!mAvailable && NS_FAILED(mPipe->mStatus))
745 9048 : return mPipe->mStatus;
746 :
747 22512 : *result = mAvailable;
748 22512 : return NS_OK;
749 : }
750 :
751 : NS_IMETHODIMP
752 34503 : nsPipeInputStream::ReadSegments(nsWriteSegmentFun writer,
753 : void *closure,
754 : PRUint32 count,
755 : PRUint32 *readCount)
756 : {
757 34503 : LOG(("III ReadSegments [this=%x count=%u]\n", this, count));
758 :
759 34503 : nsresult rv = NS_OK;
760 :
761 : const char *segment;
762 : PRUint32 segmentLen;
763 :
764 34503 : *readCount = 0;
765 91414 : while (count) {
766 41273 : rv = mPipe->GetReadSegment(segment, segmentLen);
767 41273 : if (NS_FAILED(rv)) {
768 : // ignore this error if we've already read something.
769 18865 : if (*readCount > 0) {
770 6472 : rv = NS_OK;
771 6472 : break;
772 : }
773 12393 : if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
774 : // pipe is empty
775 9292 : if (!mBlocking)
776 9292 : break;
777 : // wait for some data to be written to the pipe
778 0 : rv = Wait();
779 0 : if (NS_SUCCEEDED(rv))
780 0 : continue;
781 : }
782 : // ignore this error, just return.
783 3101 : if (rv == NS_BASE_STREAM_CLOSED) {
784 3101 : rv = NS_OK;
785 3101 : break;
786 : }
787 0 : mPipe->OnPipeException(rv);
788 0 : break;
789 : }
790 :
791 : // read no more than count
792 22408 : if (segmentLen > count)
793 1007 : segmentLen = count;
794 :
795 22408 : PRUint32 writeCount, originalLen = segmentLen;
796 67169 : while (segmentLen) {
797 22415 : writeCount = 0;
798 :
799 22415 : rv = writer(this, closure, segment, *readCount, segmentLen, &writeCount);
800 :
801 22415 : if (NS_FAILED(rv) || writeCount == 0) {
802 62 : count = 0;
803 : // any errors returned from the writer end here: do not
804 : // propagate to the caller of ReadSegments.
805 62 : rv = NS_OK;
806 62 : break;
807 : }
808 :
809 22353 : NS_ASSERTION(writeCount <= segmentLen, "wrote more than expected");
810 22353 : segment += writeCount;
811 22353 : segmentLen -= writeCount;
812 22353 : count -= writeCount;
813 22353 : *readCount += writeCount;
814 22353 : mLogicalOffset += writeCount;
815 : }
816 :
817 22408 : if (segmentLen < originalLen)
818 22353 : mPipe->AdvanceReadCursor(originalLen - segmentLen);
819 : }
820 :
821 34503 : return rv;
822 : }
823 :
824 : NS_IMETHODIMP
825 15123 : nsPipeInputStream::Read(char* toBuf, PRUint32 bufLen, PRUint32 *readCount)
826 : {
827 15123 : return ReadSegments(NS_CopySegmentToBuffer, toBuf, bufLen, readCount);
828 : }
829 :
830 : NS_IMETHODIMP
831 3203 : nsPipeInputStream::IsNonBlocking(bool *aNonBlocking)
832 : {
833 3203 : *aNonBlocking = !mBlocking;
834 3203 : return NS_OK;
835 : }
836 :
837 : NS_IMETHODIMP
838 28770 : nsPipeInputStream::AsyncWait(nsIInputStreamCallback *callback,
839 : PRUint32 flags,
840 : PRUint32 requestedCount,
841 : nsIEventTarget *target)
842 : {
843 28770 : LOG(("III AsyncWait [this=%x]\n", this));
844 :
845 57540 : nsPipeEvents pipeEvents;
846 : {
847 57540 : ReentrantMonitorAutoEnter mon(mPipe->mReentrantMonitor);
848 :
849 : // replace a pending callback
850 28770 : mCallback = 0;
851 28770 : mCallbackFlags = 0;
852 :
853 28770 : if (!callback)
854 0 : return NS_OK;
855 :
856 57540 : nsCOMPtr<nsIInputStreamCallback> proxy;
857 28770 : if (target) {
858 19452 : nsresult rv = NS_NewInputStreamReadyEvent(getter_AddRefs(proxy),
859 19452 : callback, target);
860 19452 : if (NS_FAILED(rv)) return rv;
861 19452 : callback = proxy;
862 : }
863 :
864 34492 : if (NS_FAILED(mPipe->mStatus) ||
865 5722 : (mAvailable && !(flags & WAIT_CLOSURE_ONLY))) {
866 : // stream is already closed or readable; post event.
867 14678 : pipeEvents.NotifyInputReady(this, callback);
868 : }
869 : else {
870 : // queue up callback object to be notified when data becomes available
871 14092 : mCallback = callback;
872 14092 : mCallbackFlags = flags;
873 : }
874 : }
875 28770 : return NS_OK;
876 : }
877 :
878 : NS_IMETHODIMP
879 0 : nsPipeInputStream::Seek(PRInt32 whence, PRInt64 offset)
880 : {
881 0 : NS_NOTREACHED("nsPipeInputStream::Seek");
882 0 : return NS_ERROR_NOT_IMPLEMENTED;
883 : }
884 :
885 : NS_IMETHODIMP
886 7834 : nsPipeInputStream::Tell(PRInt64 *offset)
887 : {
888 15668 : ReentrantMonitorAutoEnter mon(mPipe->mReentrantMonitor);
889 :
890 : // return error if pipe closed
891 7834 : if (!mAvailable && NS_FAILED(mPipe->mStatus))
892 2778 : return mPipe->mStatus;
893 :
894 5056 : *offset = mLogicalOffset;
895 5056 : return NS_OK;
896 : }
897 :
898 : NS_IMETHODIMP
899 0 : nsPipeInputStream::SetEOF()
900 : {
901 0 : NS_NOTREACHED("nsPipeInputStream::SetEOF");
902 0 : return NS_ERROR_NOT_IMPLEMENTED;
903 : }
904 :
905 : #define COMPARE(s1, s2, i) \
906 : (ignoreCase \
907 : ? nsCRT::strncasecmp((const char *)s1, (const char *)s2, (PRUint32)i) \
908 : : nsCRT::strncmp((const char *)s1, (const char *)s2, (PRUint32)i))
909 :
910 : NS_IMETHODIMP
911 0 : nsPipeInputStream::Search(const char *forString,
912 : bool ignoreCase,
913 : bool *found,
914 : PRUint32 *offsetSearchedTo)
915 : {
916 0 : LOG(("III Search [for=%s ic=%u]\n", forString, ignoreCase));
917 :
918 0 : ReentrantMonitorAutoEnter mon(mPipe->mReentrantMonitor);
919 :
920 : char *cursor1, *limit1;
921 0 : PRUint32 index = 0, offset = 0;
922 0 : PRUint32 strLen = strlen(forString);
923 :
924 0 : mPipe->PeekSegment(0, cursor1, limit1);
925 0 : if (cursor1 == limit1) {
926 0 : *found = false;
927 0 : *offsetSearchedTo = 0;
928 0 : LOG((" result [found=%u offset=%u]\n", *found, *offsetSearchedTo));
929 0 : return NS_OK;
930 : }
931 :
932 0 : while (true) {
933 0 : PRUint32 i, len1 = limit1 - cursor1;
934 :
935 : // check if the string is in the buffer segment
936 0 : for (i = 0; i < len1 - strLen + 1; i++) {
937 0 : if (COMPARE(&cursor1[i], forString, strLen) == 0) {
938 0 : *found = true;
939 0 : *offsetSearchedTo = offset + i;
940 0 : LOG((" result [found=%u offset=%u]\n", *found, *offsetSearchedTo));
941 0 : return NS_OK;
942 : }
943 : }
944 :
945 : // get the next segment
946 : char *cursor2, *limit2;
947 : PRUint32 len2;
948 :
949 0 : index++;
950 0 : offset += len1;
951 :
952 0 : mPipe->PeekSegment(index, cursor2, limit2);
953 0 : if (cursor2 == limit2) {
954 0 : *found = false;
955 0 : *offsetSearchedTo = offset - strLen + 1;
956 0 : LOG((" result [found=%u offset=%u]\n", *found, *offsetSearchedTo));
957 0 : return NS_OK;
958 : }
959 0 : len2 = limit2 - cursor2;
960 :
961 : // check if the string is straddling the next buffer segment
962 0 : PRUint32 lim = NS_MIN(strLen, len2 + 1);
963 0 : for (i = 0; i < lim; ++i) {
964 0 : PRUint32 strPart1Len = strLen - i - 1;
965 0 : PRUint32 strPart2Len = strLen - strPart1Len;
966 0 : const char* strPart2 = &forString[strLen - strPart2Len];
967 0 : PRUint32 bufSeg1Offset = len1 - strPart1Len;
968 0 : if (COMPARE(&cursor1[bufSeg1Offset], forString, strPart1Len) == 0 &&
969 0 : COMPARE(cursor2, strPart2, strPart2Len) == 0) {
970 0 : *found = true;
971 0 : *offsetSearchedTo = offset - strPart1Len;
972 0 : LOG((" result [found=%u offset=%u]\n", *found, *offsetSearchedTo));
973 0 : return NS_OK;
974 : }
975 : }
976 :
977 : // finally continue with the next buffer
978 0 : cursor1 = cursor2;
979 0 : limit1 = limit2;
980 : }
981 :
982 : NS_NOTREACHED("can't get here");
983 : return NS_ERROR_UNEXPECTED; // keep compiler happy
984 : }
985 :
986 : //-----------------------------------------------------------------------------
987 : // nsPipeOutputStream methods:
988 : //-----------------------------------------------------------------------------
989 :
990 211515 : NS_IMPL_QUERY_INTERFACE3(nsPipeOutputStream,
991 : nsIOutputStream,
992 : nsIAsyncOutputStream,
993 : nsIClassInfo)
994 :
995 11363 : NS_IMPL_CI_INTERFACE_GETTER2(nsPipeOutputStream,
996 : nsIOutputStream,
997 11363 : nsIAsyncOutputStream)
998 :
999 34224 : NS_IMPL_THREADSAFE_CI(nsPipeOutputStream)
1000 :
1001 : nsresult
1002 0 : nsPipeOutputStream::Wait()
1003 : {
1004 0 : NS_ASSERTION(mBlocking, "wait on non-blocking pipe output stream");
1005 :
1006 0 : ReentrantMonitorAutoEnter mon(mPipe->mReentrantMonitor);
1007 :
1008 0 : if (NS_SUCCEEDED(mPipe->mStatus) && !mWritable) {
1009 0 : LOG(("OOO pipe output: waiting for space\n"));
1010 0 : mBlocked = true;
1011 0 : mon.Wait();
1012 0 : mBlocked = false;
1013 0 : LOG(("OOO pipe output: woke up [pipe-status=%x writable=%u]\n",
1014 : mPipe->mStatus, mWritable));
1015 : }
1016 :
1017 0 : return mPipe->mStatus == NS_BASE_STREAM_CLOSED ? NS_OK : mPipe->mStatus;
1018 : }
1019 :
1020 : bool
1021 1103 : nsPipeOutputStream::OnOutputWritable(nsPipeEvents &events)
1022 : {
1023 1103 : bool result = false;
1024 :
1025 1103 : mWritable = true;
1026 :
1027 1103 : if (mCallback && !(mCallbackFlags & WAIT_CLOSURE_ONLY)) {
1028 116 : events.NotifyOutputReady(this, mCallback);
1029 116 : mCallback = 0;
1030 116 : mCallbackFlags = 0;
1031 : }
1032 987 : else if (mBlocked)
1033 0 : result = true;
1034 :
1035 1103 : return result;
1036 : }
1037 :
1038 : bool
1039 18670 : nsPipeOutputStream::OnOutputException(nsresult reason, nsPipeEvents &events)
1040 : {
1041 18670 : LOG(("nsPipeOutputStream::OnOutputException [this=%x reason=%x]\n",
1042 : this, reason));
1043 :
1044 18670 : bool result = false;
1045 :
1046 18670 : NS_ASSERTION(NS_FAILED(reason), "huh? successful exception");
1047 18670 : mWritable = false;
1048 :
1049 18670 : if (mCallback) {
1050 5791 : events.NotifyOutputReady(this, mCallback);
1051 5791 : mCallback = 0;
1052 5791 : mCallbackFlags = 0;
1053 : }
1054 12879 : else if (mBlocked)
1055 0 : result = true;
1056 :
1057 18670 : return result;
1058 : }
1059 :
1060 :
1061 : NS_IMETHODIMP_(nsrefcnt)
1062 177744 : nsPipeOutputStream::AddRef()
1063 : {
1064 177744 : NS_AtomicIncrementRefcnt(mWriterRefCnt);
1065 177744 : return mPipe->AddRef();
1066 : }
1067 :
1068 : NS_IMETHODIMP_(nsrefcnt)
1069 177728 : nsPipeOutputStream::Release()
1070 : {
1071 177728 : if (NS_AtomicDecrementRefcnt(mWriterRefCnt) == 0)
1072 18670 : Close();
1073 177728 : return mPipe->Release();
1074 : }
1075 :
1076 : NS_IMETHODIMP
1077 35907 : nsPipeOutputStream::CloseWithStatus(nsresult reason)
1078 : {
1079 35907 : LOG(("OOO CloseWithStatus [this=%x reason=%x]\n", this, reason));
1080 :
1081 35907 : if (NS_SUCCEEDED(reason))
1082 2892 : reason = NS_BASE_STREAM_CLOSED;
1083 :
1084 : // input stream may remain open
1085 35907 : mPipe->OnPipeException(reason, true);
1086 35907 : return NS_OK;
1087 : }
1088 :
1089 : NS_IMETHODIMP
1090 29706 : nsPipeOutputStream::Close()
1091 : {
1092 29706 : return CloseWithStatus(NS_BASE_STREAM_CLOSED);
1093 : }
1094 :
1095 : NS_IMETHODIMP
1096 79962 : nsPipeOutputStream::WriteSegments(nsReadSegmentFun reader,
1097 : void* closure,
1098 : PRUint32 count,
1099 : PRUint32 *writeCount)
1100 : {
1101 79962 : LOG(("OOO WriteSegments [this=%x count=%u]\n", this, count));
1102 :
1103 79962 : nsresult rv = NS_OK;
1104 :
1105 : char *segment;
1106 : PRUint32 segmentLen;
1107 :
1108 79962 : *writeCount = 0;
1109 240337 : while (count) {
1110 80617 : rv = mPipe->GetWriteSegment(segment, segmentLen);
1111 80617 : if (NS_FAILED(rv)) {
1112 204 : if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
1113 : // pipe is full
1114 116 : if (!mBlocking) {
1115 : // ignore this error if we've already written something
1116 116 : if (*writeCount > 0)
1117 2 : rv = NS_OK;
1118 116 : break;
1119 : }
1120 : // wait for the pipe to have an empty segment.
1121 0 : rv = Wait();
1122 0 : if (NS_SUCCEEDED(rv))
1123 0 : continue;
1124 : }
1125 88 : mPipe->OnPipeException(rv);
1126 88 : break;
1127 : }
1128 :
1129 : // write no more than count
1130 80413 : if (segmentLen > count)
1131 64392 : segmentLen = count;
1132 :
1133 80413 : PRUint32 readCount, originalLen = segmentLen;
1134 232905 : while (segmentLen) {
1135 86962 : readCount = 0;
1136 :
1137 86962 : rv = reader(this, closure, segment, *writeCount, segmentLen, &readCount);
1138 :
1139 86962 : if (NS_FAILED(rv) || readCount == 0) {
1140 14883 : count = 0;
1141 : // any errors returned from the reader end here: do not
1142 : // propagate to the caller of WriteSegments.
1143 14883 : rv = NS_OK;
1144 14883 : break;
1145 : }
1146 :
1147 72079 : NS_ASSERTION(readCount <= segmentLen, "read more than expected");
1148 72079 : segment += readCount;
1149 72079 : segmentLen -= readCount;
1150 72079 : count -= readCount;
1151 72079 : *writeCount += readCount;
1152 72079 : mLogicalOffset += readCount;
1153 : }
1154 :
1155 80413 : if (segmentLen < originalLen)
1156 72079 : mPipe->AdvanceWriteCursor(originalLen - segmentLen);
1157 : }
1158 :
1159 79962 : return rv;
1160 : }
1161 :
1162 : static NS_METHOD
1163 65230 : nsReadFromRawBuffer(nsIOutputStream* outStr,
1164 : void* closure,
1165 : char* toRawSegment,
1166 : PRUint32 offset,
1167 : PRUint32 count,
1168 : PRUint32 *readCount)
1169 : {
1170 65230 : const char* fromBuf = (const char*)closure;
1171 65230 : memcpy(toRawSegment, &fromBuf[offset], count);
1172 65230 : *readCount = count;
1173 65230 : return NS_OK;
1174 : }
1175 :
1176 : NS_IMETHODIMP
1177 64606 : nsPipeOutputStream::Write(const char* fromBuf,
1178 : PRUint32 bufLen,
1179 : PRUint32 *writeCount)
1180 : {
1181 64606 : return WriteSegments(nsReadFromRawBuffer, (void*)fromBuf, bufLen, writeCount);
1182 : }
1183 :
1184 : NS_IMETHODIMP
1185 8 : nsPipeOutputStream::Flush(void)
1186 : {
1187 : // nothing to do
1188 8 : return NS_OK;
1189 : }
1190 :
1191 : static NS_METHOD
1192 40 : nsReadFromInputStream(nsIOutputStream* outStr,
1193 : void* closure,
1194 : char* toRawSegment,
1195 : PRUint32 offset,
1196 : PRUint32 count,
1197 : PRUint32 *readCount)
1198 : {
1199 40 : nsIInputStream* fromStream = (nsIInputStream*)closure;
1200 40 : return fromStream->Read(toRawSegment, count, readCount);
1201 : }
1202 :
1203 : NS_IMETHODIMP
1204 40 : nsPipeOutputStream::WriteFrom(nsIInputStream* fromStream,
1205 : PRUint32 count,
1206 : PRUint32 *writeCount)
1207 : {
1208 40 : return WriteSegments(nsReadFromInputStream, fromStream, count, writeCount);
1209 : }
1210 :
1211 : NS_IMETHODIMP
1212 1 : nsPipeOutputStream::IsNonBlocking(bool *aNonBlocking)
1213 : {
1214 1 : *aNonBlocking = !mBlocking;
1215 1 : return NS_OK;
1216 : }
1217 :
1218 : NS_IMETHODIMP
1219 21942 : nsPipeOutputStream::AsyncWait(nsIOutputStreamCallback *callback,
1220 : PRUint32 flags,
1221 : PRUint32 requestedCount,
1222 : nsIEventTarget *target)
1223 : {
1224 21942 : LOG(("OOO AsyncWait [this=%x]\n", this));
1225 :
1226 43884 : nsPipeEvents pipeEvents;
1227 : {
1228 43884 : ReentrantMonitorAutoEnter mon(mPipe->mReentrantMonitor);
1229 :
1230 : // replace a pending callback
1231 21942 : mCallback = 0;
1232 21942 : mCallbackFlags = 0;
1233 :
1234 21942 : if (!callback)
1235 0 : return NS_OK;
1236 :
1237 43884 : nsCOMPtr<nsIOutputStreamCallback> proxy;
1238 21942 : if (target) {
1239 18321 : nsresult rv = NS_NewOutputStreamReadyEvent(getter_AddRefs(proxy),
1240 18321 : callback, target);
1241 18321 : if (NS_FAILED(rv)) return rv;
1242 18321 : callback = proxy;
1243 : }
1244 :
1245 43749 : if (NS_FAILED(mPipe->mStatus) ||
1246 21807 : (mWritable && !(flags & WAIT_CLOSURE_ONLY))) {
1247 : // stream is already closed or writable; post event.
1248 7068 : pipeEvents.NotifyOutputReady(this, callback);
1249 : }
1250 : else {
1251 : // queue up callback object to be notified when data becomes available
1252 14874 : mCallback = callback;
1253 14874 : mCallbackFlags = flags;
1254 : }
1255 : }
1256 21942 : return NS_OK;
1257 : }
1258 :
1259 : ////////////////////////////////////////////////////////////////////////////////
1260 :
1261 : nsresult
1262 1118 : NS_NewPipe(nsIInputStream **pipeIn,
1263 : nsIOutputStream **pipeOut,
1264 : PRUint32 segmentSize,
1265 : PRUint32 maxSize,
1266 : bool nonBlockingInput,
1267 : bool nonBlockingOutput,
1268 : nsIMemory *segmentAlloc)
1269 : {
1270 1118 : if (segmentSize == 0)
1271 0 : segmentSize = DEFAULT_SEGMENT_SIZE;
1272 :
1273 : // Handle maxSize of PR_UINT32_MAX as a special case
1274 : PRUint32 segmentCount;
1275 1118 : if (maxSize == PR_UINT32_MAX)
1276 404 : segmentCount = PR_UINT32_MAX;
1277 : else
1278 714 : segmentCount = maxSize / segmentSize;
1279 :
1280 : nsIAsyncInputStream *in;
1281 : nsIAsyncOutputStream *out;
1282 : nsresult rv = NS_NewPipe2(&in, &out, nonBlockingInput, nonBlockingOutput,
1283 1118 : segmentSize, segmentCount, segmentAlloc);
1284 1118 : if (NS_FAILED(rv)) return rv;
1285 :
1286 1118 : *pipeIn = in;
1287 1118 : *pipeOut = out;
1288 1118 : return NS_OK;
1289 : }
1290 :
1291 : nsresult
1292 10240 : NS_NewPipe2(nsIAsyncInputStream **pipeIn,
1293 : nsIAsyncOutputStream **pipeOut,
1294 : bool nonBlockingInput,
1295 : bool nonBlockingOutput,
1296 : PRUint32 segmentSize,
1297 : PRUint32 segmentCount,
1298 : nsIMemory *segmentAlloc)
1299 : {
1300 : nsresult rv;
1301 :
1302 10240 : nsPipe *pipe = new nsPipe();
1303 10240 : if (!pipe)
1304 0 : return NS_ERROR_OUT_OF_MEMORY;
1305 :
1306 : rv = pipe->Init(nonBlockingInput,
1307 : nonBlockingOutput,
1308 : segmentSize,
1309 : segmentCount,
1310 10240 : segmentAlloc);
1311 10240 : if (NS_FAILED(rv)) {
1312 0 : NS_ADDREF(pipe);
1313 0 : NS_RELEASE(pipe);
1314 0 : return rv;
1315 : }
1316 :
1317 10240 : pipe->GetInputStream(pipeIn);
1318 10240 : pipe->GetOutputStream(pipeOut);
1319 10240 : return NS_OK;
1320 : }
1321 :
1322 : nsresult
1323 8445 : nsPipeConstructor(nsISupports *outer, REFNSIID iid, void **result)
1324 : {
1325 8445 : if (outer)
1326 0 : return NS_ERROR_NO_AGGREGATION;
1327 8445 : nsPipe *pipe = new nsPipe();
1328 8445 : if (!pipe)
1329 0 : return NS_ERROR_OUT_OF_MEMORY;
1330 8445 : NS_ADDREF(pipe);
1331 8445 : nsresult rv = pipe->QueryInterface(iid, result);
1332 8445 : NS_RELEASE(pipe);
1333 8445 : return rv;
1334 4188 : }
1335 :
1336 : ////////////////////////////////////////////////////////////////////////////////
|