1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Jeff Walden <jwalden+code@mit.edu>.
19 : * Portions created by the Initial Developer are Copyright (C) 2007
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or 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 "TestHarness.h"
39 :
40 : #include "nsIPipe.h"
41 : #include "nsIMemory.h"
42 :
43 : /** NS_NewPipe2 reimplemented, because it's not exported by XPCOM */
44 1 : nsresult TP_NewPipe2(nsIAsyncInputStream** input,
45 : nsIAsyncOutputStream** output,
46 : bool nonBlockingInput,
47 : bool nonBlockingOutput,
48 : PRUint32 segmentSize,
49 : PRUint32 segmentCount,
50 : nsIMemory* segmentAlloc)
51 : {
52 2 : nsCOMPtr<nsIPipe> pipe = do_CreateInstance("@mozilla.org/pipe;1");
53 1 : if (!pipe)
54 0 : return NS_ERROR_OUT_OF_MEMORY;
55 :
56 1 : nsresult rv = pipe->Init(nonBlockingInput,
57 : nonBlockingOutput,
58 : segmentSize,
59 : segmentCount,
60 1 : segmentAlloc);
61 :
62 1 : if (NS_FAILED(rv))
63 0 : return rv;
64 :
65 1 : pipe->GetInputStream(input);
66 1 : pipe->GetOutputStream(output);
67 1 : return NS_OK;
68 : }
69 :
70 : /**
71 : * Allocator can allocate exactly count * size bytes, stored at mMemory;
72 : * immediately after the end of this is a byte-map of 0/1 values indicating
73 : * which <size>-byte locations in mMemory are empty and which are filled.
74 : * Pretty stupid, but enough to test bug 394692.
75 : */
76 : class BackwardsAllocator : public nsIMemory
77 : {
78 : public:
79 1 : BackwardsAllocator()
80 : : mMemory(0),
81 : mIndex(0xFFFFFFFF),
82 : mCount(0xFFFFFFFF),
83 1 : mSize(0)
84 1 : { }
85 1 : ~BackwardsAllocator()
86 1 : {
87 1 : delete [] mMemory;
88 1 : }
89 :
90 : nsresult Init(PRUint32 count, size_t size);
91 :
92 : NS_DECL_ISUPPORTS
93 : NS_DECL_NSIMEMORY
94 :
95 : private:
96 10 : PRUint32 previous(PRUint32 i)
97 : {
98 10 : if (i == 0)
99 1 : return mCount - 1;
100 9 : return i - 1;
101 : }
102 :
103 : private:
104 : PRUint8* mMemory;
105 : PRUint32 mIndex;
106 : PRUint32 mCount;
107 : size_t mSize;
108 : };
109 :
110 5 : NS_IMPL_ISUPPORTS1(BackwardsAllocator, nsIMemory)
111 :
112 1 : nsresult BackwardsAllocator::Init(PRUint32 count, size_t size)
113 : {
114 1 : if (mMemory)
115 : {
116 0 : fail("allocator already initialized!");
117 0 : return NS_ERROR_ALREADY_INITIALIZED;
118 : }
119 :
120 2 : mMemory = new PRUint8[count * size + count];
121 1 : if (!mMemory)
122 : {
123 0 : fail("failed to allocate mMemory!");
124 0 : return NS_ERROR_OUT_OF_MEMORY;
125 : }
126 1 : memset(mMemory, 0, count * size + count);
127 :
128 1 : mIndex = 0;
129 1 : mCount = count;
130 1 : mSize = size;
131 :
132 1 : return NS_OK;
133 : }
134 :
135 10 : NS_IMETHODIMP_(void*) BackwardsAllocator::Alloc(size_t size)
136 : {
137 10 : if (size != mSize)
138 : {
139 0 : NS_ERROR("umm, why would this be reached for this test?");
140 0 : return NULL;
141 : }
142 :
143 10 : PRUint32 index = mIndex;
144 :
145 20 : while ((index = previous(index)) != mIndex)
146 : {
147 10 : if (mMemory[mSize * mCount + index] == 1)
148 0 : continue;
149 10 : mMemory[mSize * mCount + index] = 1;
150 10 : mIndex = index;
151 10 : return &mMemory[mSize * index];
152 : }
153 :
154 0 : NS_ERROR("shouldn't reach here in this test");
155 0 : return NULL;
156 : }
157 :
158 0 : NS_IMETHODIMP_(void*) BackwardsAllocator::Realloc(void* ptr, size_t newSize)
159 : {
160 0 : NS_ERROR("shouldn't reach here in this test");
161 0 : return NULL;
162 : }
163 :
164 10 : NS_IMETHODIMP_(void) BackwardsAllocator::Free(void* ptr)
165 : {
166 10 : PRUint8* p = static_cast<PRUint8*>(ptr);
167 10 : if (p)
168 10 : mMemory[mCount * mSize + (p - mMemory) / mSize] = 0;
169 10 : }
170 :
171 0 : NS_IMETHODIMP BackwardsAllocator::HeapMinimize(bool immediate)
172 : {
173 0 : return NS_OK;
174 : }
175 :
176 0 : NS_IMETHODIMP BackwardsAllocator::IsLowMemory(bool* retval)
177 : {
178 0 : *retval = false;
179 0 : return NS_OK;
180 : }
181 :
182 :
183 1 : nsresult TestBackwardsAllocator()
184 : {
185 1 : const PRUint32 SEGMENT_COUNT = 10;
186 1 : const PRUint32 SEGMENT_SIZE = 10;
187 :
188 2 : nsRefPtr<BackwardsAllocator> allocator = new BackwardsAllocator();
189 1 : if (!allocator)
190 : {
191 0 : fail("Allocation of BackwardsAllocator failed!");
192 0 : return NS_ERROR_OUT_OF_MEMORY;
193 : }
194 1 : nsresult rv = allocator->Init(SEGMENT_COUNT, SEGMENT_SIZE);
195 1 : if (NS_FAILED(rv))
196 0 : return rv;
197 :
198 2 : nsCOMPtr<nsIAsyncInputStream> input;
199 2 : nsCOMPtr<nsIAsyncOutputStream> output;
200 1 : rv = TP_NewPipe2(getter_AddRefs(input),
201 1 : getter_AddRefs(output),
202 : false,
203 : false,
204 1 : SEGMENT_SIZE, SEGMENT_COUNT, allocator);
205 1 : if (NS_FAILED(rv))
206 : {
207 0 : fail("TP_NewPipe2 failed: %x", rv);
208 0 : return rv;
209 : }
210 :
211 1 : const PRUint32 BUFFER_LENGTH = 100;
212 : const char written[] =
213 : "0123456789"
214 : "1123456789"
215 : "2123456789"
216 : "3123456789"
217 : "4123456789"
218 : "5123456789"
219 : "6123456789"
220 : "7123456789"
221 : "8123456789"
222 1 : "9123456789"; // not just a memset, to ensure the allocator works correctly
223 : if (sizeof(written) < BUFFER_LENGTH)
224 : {
225 : fail("test error with string size");
226 : return NS_ERROR_FAILURE;
227 : }
228 :
229 : PRUint32 writeCount;
230 1 : rv = output->Write(written, BUFFER_LENGTH, &writeCount);
231 1 : if (NS_FAILED(rv) || writeCount != BUFFER_LENGTH)
232 : {
233 : fail("writing %d bytes (wrote %d bytes) to output failed: %x",
234 0 : BUFFER_LENGTH, writeCount, rv);
235 0 : return rv;
236 : }
237 :
238 : char read[BUFFER_LENGTH];
239 : PRUint32 readCount;
240 1 : rv = input->Read(read, BUFFER_LENGTH, &readCount);
241 1 : if (NS_FAILED(rv) || readCount != BUFFER_LENGTH)
242 : {
243 : fail("reading %d bytes (got %d bytes) from input failed: %x",
244 0 : BUFFER_LENGTH, readCount, rv);
245 0 : return rv;
246 : }
247 :
248 1 : if (0 != memcmp(written, read, BUFFER_LENGTH))
249 : {
250 0 : fail("didn't read the written data correctly!");
251 0 : return NS_ERROR_FAILURE;
252 : }
253 :
254 1 : passed("TestBackwardsAllocator");
255 1 : return NS_OK;
256 : }
257 :
258 1 : int main(int argc, char** argv)
259 : {
260 2 : ScopedXPCOM xpcom("nsPipe");
261 1 : if (xpcom.failed())
262 0 : return 1;
263 :
264 1 : int rv = 0;
265 :
266 1 : if (NS_FAILED(TestBackwardsAllocator()))
267 0 : rv = 1;
268 :
269 1 : return rv;
270 : }
|