Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 /*
7 ** File: arena.c
8 ** Description: Testing arenas
9 **
10 */
12 #include <string.h>
13 #include <time.h>
14 #include <stdlib.h>
15 #include "nspr.h"
16 #include "plarena.h"
17 #include "plgetopt.h"
19 PRLogModuleInfo *tLM;
20 PRIntn threadCount = 0;
21 PRMonitor *tMon;
22 PRBool failed_already = PR_FALSE;
24 /* Arguments from the command line with default values */
25 PRIntn debug_mode = 0;
26 PRIntn poolMin = 4096;
27 PRIntn poolMax = (100 * 4096);
28 PRIntn arenaMin = 40;
29 PRIntn arenaMax = (100 * 40);
30 PRIntn stressIterations = 15;
31 PRIntn maxAlloc = (1024 * 1024);
32 PRIntn stressThreads = 4;
34 void DumpAll( void )
35 {
36 return;
37 }
39 /*
40 ** Test Arena allocation.
41 */
42 static void ArenaAllocate( void )
43 {
44 PLArenaPool ap;
45 void *ptr;
46 PRInt32 i;
48 PL_InitArenaPool( &ap, "AllocArena", 2048, sizeof(double));
49 PR_LOG( tLM, PR_LOG_DEBUG, ("AA, InitPool -- Pool: %p. first: %p, current: %p, size: %d",
50 &ap, ap.first, ap.current, ap.arenasize ));
52 for( i = 0; i < 150; i++ )
53 {
54 PL_ARENA_ALLOCATE( ptr, &ap, 512 );
55 PR_LOG( tLM, PR_LOG_DEBUG,("AA, after alloc -- Pool: %p. first: %p, current: %p, size: %d",
56 &ap, ap.first, ap.current, ap.arenasize ));
57 PR_LOG( tLM, PR_LOG_DEBUG,(
58 "AA -- Pool: %p. alloc: %p ", &ap, ptr ));
59 }
61 PL_FreeArenaPool( &ap );
63 for( i = 0; i < 221; i++ )
64 {
65 PL_ARENA_ALLOCATE( ptr, &ap, 512 );
66 PR_LOG( tLM, PR_LOG_DEBUG,("AA, after alloc -- Pool: %p. first: %p, current: %p, size: %d",
67 &ap, ap.first, ap.current, ap.arenasize ));
68 PR_LOG( tLM, PR_LOG_DEBUG,(
69 "AA -- Pool: %p. alloc: %p ", &ap, ptr ));
70 }
72 PL_FreeArenaPool( &ap );
74 return;
75 } /* end ArenaGrow() */
76 /*
77 ** Test Arena grow.
78 */
79 static void ArenaGrow( void )
80 {
81 PLArenaPool ap;
82 void *ptr;
83 PRInt32 i;
85 PL_InitArenaPool( &ap, "TheArena", 4096, sizeof(double));
86 PL_ARENA_ALLOCATE( ptr, &ap, 512 );
88 PR_LOG( tLM, PR_LOG_DEBUG, ("Before growth -- Pool: %p. alloc: %p ", &ap, ptr ));
90 for( i = 0; i < 10; i++ )
91 {
92 PL_ARENA_GROW( ptr, &ap, 512, 7000 );
93 PR_LOG( tLM, PR_LOG_DEBUG, ("After growth -- Pool: %p. alloc: %p ", &ap, ptr ));
94 }
97 return;
98 } /* end ArenaGrow() */
101 /*
102 ** Test arena Mark and Release.
103 */
104 static void MarkAndRelease( void )
105 {
106 PLArenaPool ap;
107 void *ptr = NULL;
108 void *mark0, *mark1;
109 PRIntn i;
111 PL_InitArenaPool( &ap, "TheArena", 4096, sizeof(double));
112 mark0 = PL_ARENA_MARK( &ap );
113 PR_LOG( tLM, PR_LOG_DEBUG,
114 ("mark0. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p, m0: %p",
115 &ap, ap.first.next, ap.current, ap.arenasize, ptr, mark0 ));
117 for( i = 0; i < 201; i++ )
118 {
119 PL_ARENA_ALLOCATE( ptr, &ap, 512 );
120 PR_LOG( tLM, PR_LOG_DEBUG,
121 ("mr. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p",
122 &ap, ap.first.next, ap.current, ap.arenasize, ptr ));
123 }
125 mark1 = PL_ARENA_MARK( &ap );
126 PR_LOG( tLM, PR_LOG_DEBUG,
127 ("mark1. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p, m1: %p",
128 &ap, ap.first.next, ap.current, ap.arenasize, ptr, mark1 ));
131 for( i = 0; i < 225; i++ )
132 {
133 PL_ARENA_ALLOCATE( ptr, &ap, 512 );
134 PR_LOG( tLM, PR_LOG_DEBUG,
135 ("mr. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p",
136 &ap, ap.first.next, ap.current, ap.arenasize, ptr ));
137 }
139 PL_ARENA_RELEASE( &ap, mark1 );
140 PR_LOG( tLM, PR_LOG_DEBUG,
141 ("Release-1: %p -- Pool: %p. first: %p, current: %p, size: %d",
142 mark1, &ap, ap.first, ap.current, ap.arenasize ));
144 for( i = 0; i < 20; i++ )
145 {
146 PL_ARENA_ALLOCATE( ptr, &ap, 512 );
147 PR_LOG( tLM, PR_LOG_DEBUG,
148 ("mr. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p",
149 &ap, ap.first.next, ap.current, ap.arenasize, ptr ));
150 }
152 PL_ARENA_RELEASE( &ap, mark1 );
153 PR_LOG( tLM, PR_LOG_DEBUG,
154 ("Release-1. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p",
155 &ap, ap.first.next, ap.current, ap.arenasize, ptr ));
157 PL_ARENA_RELEASE( &ap, mark0 );
158 PR_LOG( tLM, PR_LOG_DEBUG,
159 ("Release-0. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p",
160 &ap, ap.first.next, ap.current, ap.arenasize, ptr ));
162 PL_FreeArenaPool( &ap );
163 PR_LOG( tLM, PR_LOG_DEBUG,
164 ("Free. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p",
165 &ap, ap.first.next, ap.current, ap.arenasize, ptr ));
167 PL_FinishArenaPool( &ap );
168 PR_LOG( tLM, PR_LOG_DEBUG,
169 ("Finish. ap: %p, ap.f: %p, ap.c: %p, ap.siz: %d, alloc: %p",
170 &ap, ap.first.next, ap.current, ap.arenasize, ptr ));
172 return;
173 } /* end MarkAndRelease() */
175 /*
176 ** RandSize() returns a random number in the range
177 ** min..max, rounded to the next doubleword
178 **
179 */
180 static PRIntn RandSize( PRIntn min, PRIntn max )
181 {
182 PRIntn sz = (rand() % (max -min)) + min + sizeof(double);
184 sz &= ~sizeof(double)-1;
186 return(sz);
187 }
190 /*
191 ** StressThread()
192 ** A bunch of these beat on individual arenas
193 ** This tests the free_list protection.
194 **
195 */
196 static void PR_CALLBACK StressThread( void *arg )
197 {
198 PLArenaPool ap;
199 PRIntn i;
200 PRIntn sz;
201 void *ptr;
202 PRThread *tp = PR_GetCurrentThread();
204 PR_LOG( tLM, PR_LOG_DEBUG, ("Stress Thread %p started\n", PR_GetCurrentThread()));
205 PL_InitArenaPool( &ap, "TheArena", RandSize( poolMin, poolMax), sizeof(double));
207 for ( i = 0; i < stressIterations; i++ )
208 {
209 PRIntn allocated = 0;
211 while ( allocated < maxAlloc )
212 {
213 sz = RandSize( arenaMin, arenaMax );
214 PL_ARENA_ALLOCATE( ptr, &ap, sz );
215 if ( ptr == NULL )
216 {
217 PR_LOG( tLM, PR_LOG_ERROR, ("ARENA_ALLOCATE() returned NULL\n\tAllocated: %d\n", allocated));
218 break;
219 }
220 allocated += sz;
221 }
222 PR_LOG( tLM, PR_LOG_DEBUG, ("Stress thread %p finished one iteration\n", tp));
223 PL_FreeArenaPool( &ap );
224 }
225 PR_LOG( tLM, PR_LOG_DEBUG, ("Stress thread %p finished all iteration\n", tp));
226 PL_FinishArenaPool( &ap );
227 PR_LOG( tLM, PR_LOG_DEBUG, ("Stress thread %p after FinishArenaPool()\n", tp));
229 /* That's all folks! let's quit */
230 PR_EnterMonitor(tMon);
231 threadCount--;
232 PR_Notify(tMon);
233 PR_ExitMonitor(tMon);
234 return;
235 }
237 /*
238 ** Stress()
239 ** Flog the hell out of arenas multi-threaded.
240 ** Do NOT pass an individual arena to another thread.
241 **
242 */
243 static void Stress( void )
244 {
245 PRThread *tt;
246 PRIntn i;
248 tMon = PR_NewMonitor();
250 for ( i = 0 ; i < stressThreads ; i++ )
251 {
252 PR_EnterMonitor(tMon);
253 tt = PR_CreateThread(PR_USER_THREAD,
254 StressThread,
255 NULL,
256 PR_PRIORITY_NORMAL,
257 PR_GLOBAL_THREAD,
258 PR_UNJOINABLE_THREAD,
259 0);
260 threadCount++;
261 PR_ExitMonitor(tMon);
262 }
264 /* Wait for all threads to exit */
265 PR_EnterMonitor(tMon);
266 while ( threadCount != 0 )
267 {
268 PR_Wait(tMon, PR_INTERVAL_NO_TIMEOUT);
269 }
270 PR_ExitMonitor(tMon);
271 PR_DestroyMonitor(tMon);
273 return;
274 } /* end Stress() */
276 /*
277 ** EvaluateResults()
278 ** uses failed_already to display results and set program
279 ** exit code.
280 */
281 static PRIntn EvaluateResults(void)
282 {
283 PRIntn rc = 0;
285 if ( failed_already == PR_TRUE )
286 {
287 PR_LOG( tLM, PR_LOG_DEBUG, ("FAIL\n"));
288 rc =1;
289 }
290 else
291 {
292 PR_LOG( tLM, PR_LOG_DEBUG, ("PASS\n"));
293 }
294 return(rc);
295 } /* EvaluateResults() */
297 void Help( void )
298 {
299 printf("arena [options]\n");
300 printf("where options are:\n");
301 printf("-p <n> minimum size of an arena pool. Default(%d)\n", poolMin);
302 printf("-P <n> maximum size of an arena pool. Default(%d)\n", poolMax);
303 printf("-a <n> minimum size of an arena allocation. Default(%d)\n", arenaMin);
304 printf("-A <n> maximum size of an arena allocation. Default(%d)\n", arenaMax);
305 printf("-i <n> number of iterations in a stress thread. Default(%d)\n", stressIterations);
306 printf("-s <n> maximum allocation for a single stress thread. Default(%d)\n", maxAlloc);
307 printf("-t <n> number of stress threads. Default(%d)\n", stressThreads );
308 printf("-d enable debug mode\n");
309 printf("\n");
310 exit(1);
311 }
313 PRIntn main(PRIntn argc, char *argv[])
314 {
315 PLOptStatus os;
316 PLOptState *opt = PL_CreateOptState(argc, argv, "dhp:P:a:A:i:s:t:");
317 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
318 {
319 if (PL_OPT_BAD == os) continue;
320 switch (opt->option)
321 {
322 case 'a': /* arena Min size */
323 arenaMin = atol( opt->value );
324 break;
325 case 'A': /* arena Max size */
326 arenaMax = atol( opt->value );
327 break;
328 case 'p': /* pool Min size */
329 poolMin = atol( opt->value );
330 break;
331 case 'P': /* pool Max size */
332 poolMax = atol( opt->value );
333 break;
334 case 'i': /* Iterations in stress tests */
335 stressIterations = atol( opt->value );
336 break;
337 case 's': /* storage to get per iteration */
338 maxAlloc = atol( opt->value );
339 break;
340 case 't': /* Number of stress threads to create */
341 stressThreads = atol( opt->value );
342 break;
343 case 'd': /* debug mode */
344 debug_mode = 1;
345 break;
346 case 'h': /* help */
347 default:
348 Help();
349 } /* end switch() */
350 } /* end while() */
351 PL_DestroyOptState(opt);
353 srand( (unsigned)time( NULL ) ); /* seed random number generator */
354 tLM = PR_NewLogModule("testcase");
357 #if 0
358 ArenaAllocate();
359 ArenaGrow();
360 #endif
362 MarkAndRelease();
364 Stress();
366 return(EvaluateResults());
367 } /* end main() */
369 /* arena.c */