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 1464 : 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 211781 : nsPipeEvents() { }
81 : ~nsPipeEvents();
82 :
83 28604 : inline void NotifyInputReady(nsIAsyncInputStream *stream,
84 : nsIInputStreamCallback *callback)
85 : {
86 28604 : NS_ASSERTION(!mInputCallback, "already have an input event");
87 28604 : mInputStream = stream;
88 28604 : mInputCallback = callback;
89 28604 : }
90 :
91 12854 : inline void NotifyOutputReady(nsIAsyncOutputStream *stream,
92 : nsIOutputStreamCallback *callback)
93 : {
94 12854 : NS_ASSERTION(!mOutputCallback, "already have an output event");
95 12854 : mOutputStream = stream;
96 12854 : mOutputCallback = callback;
97 12854 : }
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 18617 : {
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 18632 : nsPipeInputStream(nsPipe *pipe)
129 : : mPipe(pipe)
130 : , mReaderRefCnt(0)
131 : , mLogicalOffset(0)
132 : , mBlocking(true)
133 : , mBlocked(false)
134 : , mAvailable(0)
135 18632 : , mCallbackFlags(0)
136 18632 : { }
137 :
138 : nsresult Fill();
139 18631 : void SetNonBlocking(bool aNonBlocking) { mBlocking = !aNonBlocking; }
140 :
141 18471 : PRUint32 Available() { return mAvailable; }
142 22321 : 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 18617 : {
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 18632 : nsPipeOutputStream(nsPipe *pipe)
186 : : mPipe(pipe)
187 : , mWriterRefCnt(0)
188 : , mLogicalOffset(0)
189 : , mBlocking(true)
190 : , mBlocked(false)
191 : , mWritable(true)
192 18632 : , mCallbackFlags(0)
193 18632 : { }
194 :
195 18631 : void SetNonBlocking(bool aNonBlocking) { mBlocking = !aNonBlocking; }
196 105 : 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 18632 : 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 18632 : , mInited(false)
332 : {
333 18632 : }
334 :
335 18617 : nsPipe::~nsPipe()
336 : {
337 18617 : }
338 :
339 1131883 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsPipe, nsIPipe)
340 :
341 : NS_IMETHODIMP
342 18631 : nsPipe::Init(bool nonBlockingIn,
343 : bool nonBlockingOut,
344 : PRUint32 segmentSize,
345 : PRUint32 segmentCount,
346 : nsIMemory *segmentAlloc)
347 : {
348 18631 : mInited = true;
349 :
350 18631 : if (segmentSize == 0)
351 5852 : segmentSize = DEFAULT_SEGMENT_SIZE;
352 18631 : if (segmentCount == 0)
353 92 : segmentCount = DEFAULT_SEGMENT_COUNT;
354 :
355 : // protect against overflow
356 18631 : PRUint32 maxCount = PRUint32(-1) / segmentSize;
357 18631 : if (segmentCount > maxCount)
358 8728 : segmentCount = maxCount;
359 :
360 18631 : nsresult rv = mBuffer.Init(segmentSize, segmentSize * segmentCount, segmentAlloc);
361 18631 : if (NS_FAILED(rv))
362 0 : return rv;
363 :
364 18631 : mInput.SetNonBlocking(nonBlockingIn);
365 18631 : mOutput.SetNonBlocking(nonBlockingOut);
366 18631 : return NS_OK;
367 : }
368 :
369 : NS_IMETHODIMP
370 18643 : nsPipe::GetInputStream(nsIAsyncInputStream **aInputStream)
371 : {
372 18643 : NS_ADDREF(*aInputStream = &mInput);
373 18643 : return NS_OK;
374 : }
375 :
376 : NS_IMETHODIMP
377 21532 : nsPipe::GetOutputStream(nsIAsyncOutputStream **aOutputStream)
378 : {
379 21532 : NS_ENSURE_TRUE(mInited, NS_ERROR_NOT_INITIALIZED);
380 21531 : NS_ADDREF(*aOutputStream = &mOutput);
381 21531 : 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 41175 : nsPipe::GetReadSegment(const char *&segment, PRUint32 &segmentLen)
408 : {
409 82350 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
410 :
411 41175 : if (mReadCursor == mReadLimit)
412 18810 : return NS_FAILED(mStatus) ? mStatus : NS_BASE_STREAM_WOULD_BLOCK;
413 :
414 22365 : segment = mReadCursor;
415 22365 : segmentLen = mReadLimit - mReadCursor;
416 22365 : return NS_OK;
417 : }
418 :
419 : void
420 22321 : nsPipe::AdvanceReadCursor(PRUint32 bytesRead)
421 : {
422 22321 : NS_ASSERTION(bytesRead, "don't call if no bytes read");
423 :
424 44642 : nsPipeEvents events;
425 : {
426 44642 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
427 :
428 22321 : LOG(("III advancing read cursor by %u\n", bytesRead));
429 22321 : NS_ASSERTION(bytesRead <= mBuffer.GetSegmentSize(), "read too much");
430 :
431 22321 : mReadCursor += bytesRead;
432 22321 : NS_ASSERTION(mReadCursor <= mReadLimit, "read cursor exceeds limit");
433 :
434 22321 : mInput.ReduceAvailable(bytesRead);
435 :
436 22321 : 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 21282 : if (mWriteSegment == 0 && mWriteLimit > mWriteCursor) {
443 20170 : NS_ASSERTION(mReadLimit == mWriteCursor, "unexpected state");
444 : return;
445 : }
446 :
447 : // shift write segment index (-1 indicates an empty buffer).
448 1112 : --mWriteSegment;
449 :
450 : // done with this segment
451 1112 : mBuffer.DeleteFirstSegment();
452 1112 : LOG(("III deleting first segment\n"));
453 :
454 1112 : if (mWriteSegment == -1) {
455 : // buffer is completely empty
456 132 : mReadCursor = nsnull;
457 132 : mReadLimit = nsnull;
458 132 : mWriteCursor = nsnull;
459 132 : mWriteLimit = nsnull;
460 : }
461 : else {
462 : // advance read cursor and limit to next buffer segment
463 980 : mReadCursor = mBuffer.GetSegment(0);
464 980 : if (mWriteSegment == 0)
465 203 : mReadLimit = mWriteCursor;
466 : else
467 777 : 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 1112 : if (mOutput.OnOutputWritable(events))
473 0 : mon.Notify();
474 : }
475 : }
476 : }
477 :
478 : nsresult
479 80507 : nsPipe::GetWriteSegment(char *&segment, PRUint32 &segmentLen)
480 : {
481 161014 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
482 :
483 80507 : if (NS_FAILED(mStatus))
484 89 : return mStatus;
485 :
486 : // write cursor and limit may both be null indicating an empty buffer.
487 80418 : if (mWriteCursor == mWriteLimit) {
488 17045 : char *seg = mBuffer.AppendNewSegment();
489 : // pipe is full
490 17045 : if (seg == nsnull)
491 31 : return NS_BASE_STREAM_WOULD_BLOCK;
492 17014 : LOG(("OOO appended new segment\n"));
493 17014 : mWriteCursor = seg;
494 17014 : mWriteLimit = mWriteCursor + mBuffer.GetSegmentSize();
495 17014 : ++mWriteSegment;
496 : }
497 :
498 : // make sure read cursor is initialized
499 80387 : if (mReadCursor == nsnull) {
500 15998 : NS_ASSERTION(mWriteSegment == 0, "unexpected null read cursor");
501 15998 : 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 80387 : if (mReadCursor == mWriteCursor && mWriteSegment == 0) {
507 28687 : char *head = mBuffer.GetSegment(0);
508 28687 : LOG(("OOO rolling back write cursor %u bytes\n", mWriteCursor - head));
509 28687 : mWriteCursor = mReadCursor = mReadLimit = head;
510 : }
511 :
512 80387 : segment = mWriteCursor;
513 80387 : segmentLen = mWriteLimit - mWriteCursor;
514 80387 : return NS_OK;
515 : }
516 :
517 : void
518 72083 : nsPipe::AdvanceWriteCursor(PRUint32 bytesWritten)
519 : {
520 72083 : NS_ASSERTION(bytesWritten, "don't call if no bytes written");
521 :
522 144166 : nsPipeEvents events;
523 : {
524 144166 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
525 :
526 72083 : LOG(("OOO advancing write cursor by %u\n", bytesWritten));
527 :
528 72083 : char *newWriteCursor = mWriteCursor + bytesWritten;
529 72083 : NS_ASSERTION(newWriteCursor <= mWriteLimit, "write cursor exceeds limit");
530 :
531 : // update read limit if reading in the same segment
532 72083 : if (mWriteSegment == 0 && mReadLimit == mWriteCursor)
533 21875 : mReadLimit = newWriteCursor;
534 :
535 72083 : 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 72083 : 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 72083 : if (mWriteCursor == mWriteLimit) {
563 1148 : if (mBuffer.GetSize() >= mBuffer.GetMaxSize())
564 105 : mOutput.SetWritable(false);
565 : }
566 :
567 : // notify input stream that pipe now contains additional data
568 72083 : if (mInput.OnInputReadable(bytesWritten, events))
569 0 : mon.Notify();
570 : }
571 72083 : }
572 :
573 : void
574 66927 : nsPipe::OnPipeException(nsresult reason, bool outputOnly)
575 : {
576 66927 : LOG(("PPP nsPipe::OnPipeException [reason=%x output-only=%d]\n",
577 : reason, outputOnly));
578 :
579 133854 : nsPipeEvents events;
580 : {
581 133854 : ReentrantMonitorAutoEnter mon(mReentrantMonitor);
582 :
583 : // if we've already hit an exception, then ignore this one.
584 66927 : if (NS_FAILED(mStatus))
585 : return;
586 :
587 18617 : mStatus = reason;
588 :
589 : // an output-only exception applies to the input end if the pipe has
590 : // zero bytes available.
591 18617 : if (outputOnly && !mInput.Available())
592 9855 : outputOnly = false;
593 :
594 18617 : if (!outputOnly)
595 10001 : if (mInput.OnInputException(reason, events))
596 0 : mon.Notify();
597 :
598 18617 : if (mOutput.OnOutputException(reason, events))
599 0 : mon.Notify();
600 : }
601 : }
602 :
603 : //-----------------------------------------------------------------------------
604 : // nsPipeEvents methods:
605 : //-----------------------------------------------------------------------------
606 :
607 423562 : nsPipeEvents::~nsPipeEvents()
608 : {
609 : // dispatch any pending events
610 :
611 211781 : if (mInputCallback) {
612 28604 : mInputCallback->OnInputStreamReady(mInputStream);
613 28604 : mInputCallback = 0;
614 28604 : mInputStream = 0;
615 : }
616 211781 : if (mOutputCallback) {
617 12854 : mOutputCallback->OnOutputStreamReady(mOutputStream);
618 12854 : mOutputCallback = 0;
619 12854 : mOutputStream = 0;
620 : }
621 211781 : }
622 :
623 : //-----------------------------------------------------------------------------
624 : // nsPipeInputStream methods:
625 : //-----------------------------------------------------------------------------
626 :
627 317208 : NS_IMPL_QUERY_INTERFACE5(nsPipeInputStream,
628 : nsIInputStream,
629 : nsIAsyncInputStream,
630 : nsISeekableStream,
631 : nsISearchableInputStream,
632 : nsIClassInfo)
633 :
634 13029 : NS_IMPL_CI_INTERFACE_GETTER4(nsPipeInputStream,
635 : nsIInputStream,
636 : nsIAsyncInputStream,
637 : nsISeekableStream,
638 13029 : nsISearchableInputStream)
639 :
640 39139 : 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 72083 : nsPipeInputStream::OnInputReadable(PRUint32 bytesWritten, nsPipeEvents &events)
665 : {
666 72083 : bool result = false;
667 :
668 72083 : mAvailable += bytesWritten;
669 :
670 72083 : if (mCallback && !(mCallbackFlags & WAIT_CLOSURE_ONLY)) {
671 10634 : events.NotifyInputReady(this, mCallback);
672 10634 : mCallback = 0;
673 10634 : mCallbackFlags = 0;
674 : }
675 61449 : else if (mBlocked)
676 0 : result = true;
677 :
678 72083 : return result;
679 : }
680 :
681 : bool
682 10001 : nsPipeInputStream::OnInputException(nsresult reason, nsPipeEvents &events)
683 : {
684 10001 : LOG(("nsPipeInputStream::OnInputException [this=%x reason=%x]\n",
685 : this, reason));
686 :
687 10001 : bool result = false;
688 :
689 10001 : NS_ASSERTION(NS_FAILED(reason), "huh? successful exception");
690 :
691 : // force count of available bytes to zero.
692 10001 : mAvailable = 0;
693 :
694 10001 : if (mCallback) {
695 3475 : events.NotifyInputReady(this, mCallback);
696 3475 : mCallback = 0;
697 3475 : mCallbackFlags = 0;
698 : }
699 6526 : else if (mBlocked)
700 0 : result = true;
701 :
702 10001 : return result;
703 : }
704 :
705 : NS_IMETHODIMP_(nsrefcnt)
706 308164 : nsPipeInputStream::AddRef(void)
707 : {
708 308164 : NS_AtomicIncrementRefcnt(mReaderRefCnt);
709 308164 : return mPipe->AddRef();
710 : }
711 :
712 : NS_IMETHODIMP_(nsrefcnt)
713 308134 : nsPipeInputStream::Release(void)
714 : {
715 308134 : if (NS_AtomicDecrementRefcnt(mReaderRefCnt) == 0)
716 18616 : Close();
717 308134 : return mPipe->Release();
718 : }
719 :
720 : NS_IMETHODIMP
721 31039 : nsPipeInputStream::CloseWithStatus(nsresult reason)
722 : {
723 31039 : LOG(("III CloseWithStatus [this=%x reason=%x]\n", this, reason));
724 :
725 31039 : if (NS_SUCCEEDED(reason))
726 8259 : reason = NS_BASE_STREAM_CLOSED;
727 :
728 31039 : mPipe->OnPipeException(reason);
729 31039 : return NS_OK;
730 : }
731 :
732 : NS_IMETHODIMP
733 22235 : nsPipeInputStream::Close()
734 : {
735 22235 : return CloseWithStatus(NS_BASE_STREAM_CLOSED);
736 : }
737 :
738 : NS_IMETHODIMP
739 31486 : nsPipeInputStream::Available(PRUint32 *result)
740 : {
741 62972 : ReentrantMonitorAutoEnter mon(mPipe->mReentrantMonitor);
742 :
743 : // return error if pipe closed
744 31486 : if (!mAvailable && NS_FAILED(mPipe->mStatus))
745 9024 : return mPipe->mStatus;
746 :
747 22462 : *result = mAvailable;
748 22462 : return NS_OK;
749 : }
750 :
751 : NS_IMETHODIMP
752 34372 : nsPipeInputStream::ReadSegments(nsWriteSegmentFun writer,
753 : void *closure,
754 : PRUint32 count,
755 : PRUint32 *readCount)
756 : {
757 34372 : LOG(("III ReadSegments [this=%x count=%u]\n", this, count));
758 :
759 34372 : nsresult rv = NS_OK;
760 :
761 : const char *segment;
762 : PRUint32 segmentLen;
763 :
764 34372 : *readCount = 0;
765 91109 : while (count) {
766 41175 : rv = mPipe->GetReadSegment(segment, segmentLen);
767 41175 : if (NS_FAILED(rv)) {
768 : // ignore this error if we've already read something.
769 18810 : if (*readCount > 0) {
770 6460 : rv = NS_OK;
771 6460 : break;
772 : }
773 12350 : if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
774 : // pipe is empty
775 9261 : if (!mBlocking)
776 9261 : 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 3089 : if (rv == NS_BASE_STREAM_CLOSED) {
784 3089 : rv = NS_OK;
785 3089 : break;
786 : }
787 0 : mPipe->OnPipeException(rv);
788 0 : break;
789 : }
790 :
791 : // read no more than count
792 22365 : if (segmentLen > count)
793 1038 : segmentLen = count;
794 :
795 22365 : PRUint32 writeCount, originalLen = segmentLen;
796 67051 : while (segmentLen) {
797 22370 : writeCount = 0;
798 :
799 22370 : rv = writer(this, closure, segment, *readCount, segmentLen, &writeCount);
800 :
801 22370 : if (NS_FAILED(rv) || writeCount == 0) {
802 49 : count = 0;
803 : // any errors returned from the writer end here: do not
804 : // propagate to the caller of ReadSegments.
805 49 : rv = NS_OK;
806 49 : break;
807 : }
808 :
809 22321 : NS_ASSERTION(writeCount <= segmentLen, "wrote more than expected");
810 22321 : segment += writeCount;
811 22321 : segmentLen -= writeCount;
812 22321 : count -= writeCount;
813 22321 : *readCount += writeCount;
814 22321 : mLogicalOffset += writeCount;
815 : }
816 :
817 22365 : if (segmentLen < originalLen)
818 22321 : mPipe->AdvanceReadCursor(originalLen - segmentLen);
819 : }
820 :
821 34372 : return rv;
822 : }
823 :
824 : NS_IMETHODIMP
825 15057 : nsPipeInputStream::Read(char* toBuf, PRUint32 bufLen, PRUint32 *readCount)
826 : {
827 15057 : return ReadSegments(NS_CopySegmentToBuffer, toBuf, bufLen, readCount);
828 : }
829 :
830 : NS_IMETHODIMP
831 3204 : nsPipeInputStream::IsNonBlocking(bool *aNonBlocking)
832 : {
833 3204 : *aNonBlocking = !mBlocking;
834 3204 : return NS_OK;
835 : }
836 :
837 : NS_IMETHODIMP
838 28640 : nsPipeInputStream::AsyncWait(nsIInputStreamCallback *callback,
839 : PRUint32 flags,
840 : PRUint32 requestedCount,
841 : nsIEventTarget *target)
842 : {
843 28640 : LOG(("III AsyncWait [this=%x]\n", this));
844 :
845 57280 : nsPipeEvents pipeEvents;
846 : {
847 57280 : ReentrantMonitorAutoEnter mon(mPipe->mReentrantMonitor);
848 :
849 : // replace a pending callback
850 28640 : mCallback = 0;
851 28640 : mCallbackFlags = 0;
852 :
853 28640 : if (!callback)
854 0 : return NS_OK;
855 :
856 57280 : nsCOMPtr<nsIInputStreamCallback> proxy;
857 28640 : if (target) {
858 19365 : nsresult rv = NS_NewInputStreamReadyEvent(getter_AddRefs(proxy),
859 19365 : callback, target);
860 19365 : if (NS_FAILED(rv)) return rv;
861 19365 : callback = proxy;
862 : }
863 :
864 34326 : if (NS_FAILED(mPipe->mStatus) ||
865 5686 : (mAvailable && !(flags & WAIT_CLOSURE_ONLY))) {
866 : // stream is already closed or readable; post event.
867 14495 : pipeEvents.NotifyInputReady(this, callback);
868 : }
869 : else {
870 : // queue up callback object to be notified when data becomes available
871 14145 : mCallback = callback;
872 14145 : mCallbackFlags = flags;
873 : }
874 : }
875 28640 : 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 7826 : nsPipeInputStream::Tell(PRInt64 *offset)
887 : {
888 15652 : ReentrantMonitorAutoEnter mon(mPipe->mReentrantMonitor);
889 :
890 : // return error if pipe closed
891 7826 : if (!mAvailable && NS_FAILED(mPipe->mStatus))
892 2790 : return mPipe->mStatus;
893 :
894 5036 : *offset = mLogicalOffset;
895 5036 : 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 210609 : NS_IMPL_QUERY_INTERFACE3(nsPipeOutputStream,
991 : nsIOutputStream,
992 : nsIAsyncOutputStream,
993 : nsIClassInfo)
994 :
995 11321 : NS_IMPL_CI_INTERFACE_GETTER2(nsPipeOutputStream,
996 : nsIOutputStream,
997 11321 : nsIAsyncOutputStream)
998 :
999 34098 : 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 1112 : nsPipeOutputStream::OnOutputWritable(nsPipeEvents &events)
1022 : {
1023 1112 : bool result = false;
1024 :
1025 1112 : mWritable = true;
1026 :
1027 1112 : if (mCallback && !(mCallbackFlags & WAIT_CLOSURE_ONLY)) {
1028 28 : events.NotifyOutputReady(this, mCallback);
1029 28 : mCallback = 0;
1030 28 : mCallbackFlags = 0;
1031 : }
1032 1084 : else if (mBlocked)
1033 0 : result = true;
1034 :
1035 1112 : return result;
1036 : }
1037 :
1038 : bool
1039 18617 : nsPipeOutputStream::OnOutputException(nsresult reason, nsPipeEvents &events)
1040 : {
1041 18617 : LOG(("nsPipeOutputStream::OnOutputException [this=%x reason=%x]\n",
1042 : this, reason));
1043 :
1044 18617 : bool result = false;
1045 :
1046 18617 : NS_ASSERTION(NS_FAILED(reason), "huh? successful exception");
1047 18617 : mWritable = false;
1048 :
1049 18617 : if (mCallback) {
1050 5770 : events.NotifyOutputReady(this, mCallback);
1051 5770 : mCallback = 0;
1052 5770 : mCallbackFlags = 0;
1053 : }
1054 12847 : else if (mBlocked)
1055 0 : result = true;
1056 :
1057 18617 : return result;
1058 : }
1059 :
1060 :
1061 : NS_IMETHODIMP_(nsrefcnt)
1062 176952 : nsPipeOutputStream::AddRef()
1063 : {
1064 176952 : NS_AtomicIncrementRefcnt(mWriterRefCnt);
1065 176952 : return mPipe->AddRef();
1066 : }
1067 :
1068 : NS_IMETHODIMP_(nsrefcnt)
1069 176936 : nsPipeOutputStream::Release()
1070 : {
1071 176936 : if (NS_AtomicDecrementRefcnt(mWriterRefCnt) == 0)
1072 18618 : Close();
1073 176936 : return mPipe->Release();
1074 : }
1075 :
1076 : NS_IMETHODIMP
1077 35799 : nsPipeOutputStream::CloseWithStatus(nsresult reason)
1078 : {
1079 35799 : LOG(("OOO CloseWithStatus [this=%x reason=%x]\n", this, reason));
1080 :
1081 35799 : if (NS_SUCCEEDED(reason))
1082 2881 : reason = NS_BASE_STREAM_CLOSED;
1083 :
1084 : // input stream may remain open
1085 35799 : mPipe->OnPipeException(reason, true);
1086 35799 : return NS_OK;
1087 : }
1088 :
1089 : NS_IMETHODIMP
1090 29624 : nsPipeOutputStream::Close()
1091 : {
1092 29624 : return CloseWithStatus(NS_BASE_STREAM_CLOSED);
1093 : }
1094 :
1095 : NS_IMETHODIMP
1096 79795 : nsPipeOutputStream::WriteSegments(nsReadSegmentFun reader,
1097 : void* closure,
1098 : PRUint32 count,
1099 : PRUint32 *writeCount)
1100 : {
1101 79795 : LOG(("OOO WriteSegments [this=%x count=%u]\n", this, count));
1102 :
1103 79795 : nsresult rv = NS_OK;
1104 :
1105 : char *segment;
1106 : PRUint32 segmentLen;
1107 :
1108 79795 : *writeCount = 0;
1109 239977 : while (count) {
1110 80507 : rv = mPipe->GetWriteSegment(segment, segmentLen);
1111 80507 : if (NS_FAILED(rv)) {
1112 120 : if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
1113 : // pipe is full
1114 31 : if (!mBlocking) {
1115 : // ignore this error if we've already written something
1116 31 : if (*writeCount > 0)
1117 5 : rv = NS_OK;
1118 31 : 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 89 : mPipe->OnPipeException(rv);
1126 89 : break;
1127 : }
1128 :
1129 : // write no more than count
1130 80387 : if (segmentLen > count)
1131 64423 : segmentLen = count;
1132 :
1133 80387 : PRUint32 readCount, originalLen = segmentLen;
1134 232857 : while (segmentLen) {
1135 86900 : readCount = 0;
1136 :
1137 86900 : rv = reader(this, closure, segment, *writeCount, segmentLen, &readCount);
1138 :
1139 86900 : if (NS_FAILED(rv) || readCount == 0) {
1140 14817 : count = 0;
1141 : // any errors returned from the reader end here: do not
1142 : // propagate to the caller of WriteSegments.
1143 14817 : rv = NS_OK;
1144 14817 : break;
1145 : }
1146 :
1147 72083 : NS_ASSERTION(readCount <= segmentLen, "read more than expected");
1148 72083 : segment += readCount;
1149 72083 : segmentLen -= readCount;
1150 72083 : count -= readCount;
1151 72083 : *writeCount += readCount;
1152 72083 : mLogicalOffset += readCount;
1153 : }
1154 :
1155 80387 : if (segmentLen < originalLen)
1156 72083 : mPipe->AdvanceWriteCursor(originalLen - segmentLen);
1157 : }
1158 :
1159 79795 : return rv;
1160 : }
1161 :
1162 : static NS_METHOD
1163 65225 : nsReadFromRawBuffer(nsIOutputStream* outStr,
1164 : void* closure,
1165 : char* toRawSegment,
1166 : PRUint32 offset,
1167 : PRUint32 count,
1168 : PRUint32 *readCount)
1169 : {
1170 65225 : const char* fromBuf = (const char*)closure;
1171 65225 : memcpy(toRawSegment, &fromBuf[offset], count);
1172 65225 : *readCount = count;
1173 65225 : return NS_OK;
1174 : }
1175 :
1176 : NS_IMETHODIMP
1177 64591 : nsPipeOutputStream::Write(const char* fromBuf,
1178 : PRUint32 bufLen,
1179 : PRUint32 *writeCount)
1180 : {
1181 64591 : 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 21810 : nsPipeOutputStream::AsyncWait(nsIOutputStreamCallback *callback,
1220 : PRUint32 flags,
1221 : PRUint32 requestedCount,
1222 : nsIEventTarget *target)
1223 : {
1224 21810 : LOG(("OOO AsyncWait [this=%x]\n", this));
1225 :
1226 43620 : nsPipeEvents pipeEvents;
1227 : {
1228 43620 : ReentrantMonitorAutoEnter mon(mPipe->mReentrantMonitor);
1229 :
1230 : // replace a pending callback
1231 21809 : mCallback = 0;
1232 21810 : mCallbackFlags = 0;
1233 :
1234 21810 : if (!callback)
1235 0 : return NS_OK;
1236 :
1237 43620 : nsCOMPtr<nsIOutputStreamCallback> proxy;
1238 21810 : if (target) {
1239 18277 : nsresult rv = NS_NewOutputStreamReadyEvent(getter_AddRefs(proxy),
1240 18277 : callback, target);
1241 18277 : if (NS_FAILED(rv)) return rv;
1242 18277 : callback = proxy;
1243 : }
1244 :
1245 43571 : if (NS_FAILED(mPipe->mStatus) ||
1246 21761 : (mWritable && !(flags & WAIT_CLOSURE_ONLY))) {
1247 : // stream is already closed or writable; post event.
1248 7056 : pipeEvents.NotifyOutputReady(this, callback);
1249 : }
1250 : else {
1251 : // queue up callback object to be notified when data becomes available
1252 14754 : mCallback = callback;
1253 14754 : mCallbackFlags = flags;
1254 : }
1255 : }
1256 21810 : return NS_OK;
1257 : }
1258 :
1259 : ////////////////////////////////////////////////////////////////////////////////
1260 :
1261 : nsresult
1262 1132 : NS_NewPipe(nsIInputStream **pipeIn,
1263 : nsIOutputStream **pipeOut,
1264 : PRUint32 segmentSize,
1265 : PRUint32 maxSize,
1266 : bool nonBlockingInput,
1267 : bool nonBlockingOutput,
1268 : nsIMemory *segmentAlloc)
1269 : {
1270 1132 : 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 1132 : if (maxSize == PR_UINT32_MAX)
1276 418 : 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 1132 : segmentSize, segmentCount, segmentAlloc);
1284 1132 : if (NS_FAILED(rv)) return rv;
1285 :
1286 1132 : *pipeIn = in;
1287 1132 : *pipeOut = out;
1288 1132 : return NS_OK;
1289 : }
1290 :
1291 : nsresult
1292 10215 : 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 10215 : nsPipe *pipe = new nsPipe();
1303 10215 : if (!pipe)
1304 0 : return NS_ERROR_OUT_OF_MEMORY;
1305 :
1306 : rv = pipe->Init(nonBlockingInput,
1307 : nonBlockingOutput,
1308 : segmentSize,
1309 : segmentCount,
1310 10215 : segmentAlloc);
1311 10215 : if (NS_FAILED(rv)) {
1312 0 : NS_ADDREF(pipe);
1313 0 : NS_RELEASE(pipe);
1314 0 : return rv;
1315 : }
1316 :
1317 10215 : pipe->GetInputStream(pipeIn);
1318 10215 : pipe->GetOutputStream(pipeOut);
1319 10215 : return NS_OK;
1320 : }
1321 :
1322 : nsresult
1323 8417 : nsPipeConstructor(nsISupports *outer, REFNSIID iid, void **result)
1324 : {
1325 8417 : if (outer)
1326 0 : return NS_ERROR_NO_AGGREGATION;
1327 8417 : nsPipe *pipe = new nsPipe();
1328 8417 : if (!pipe)
1329 0 : return NS_ERROR_OUT_OF_MEMORY;
1330 8417 : NS_ADDREF(pipe);
1331 8417 : nsresult rv = pipe->QueryInterface(iid, result);
1332 8417 : NS_RELEASE(pipe);
1333 8417 : return rv;
1334 4392 : }
1335 :
1336 : ////////////////////////////////////////////////////////////////////////////////
|