]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/services/memalloc/common/v2_0/tests/malloc4.cxx
Initial revision
[karo-tx-redboot.git] / packages / services / memalloc / common / v2_0 / tests / malloc4.cxx
1 //=================================================================
2 //
3 //        malloc4.cxx
4 //
5 //        Stress test malloc(), calloc(), realloc() and free()
6 //
7 //=================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //=================================================================
41 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):     jlarmour
44 // Contributors:  
45 // Date:          2000-05-30
46 // Description:   Contains a rigorous multithreaded test for malloc(),
47 //                calloc(), realloc() and free() functions
48 //
49 //
50 //####DESCRIPTIONEND####
51
52 // #define DEBUGTEST
53
54 // INCLUDES
55
56 #include <pkgconf/system.h>
57 #include <pkgconf/memalloc.h> // config header
58 #ifdef CYGPKG_ISOINFRA
59 # include <pkgconf/isoinfra.h>
60 # include <stdlib.h>
61 #endif
62 #ifdef CYGPKG_KERNEL
63 # include <pkgconf/kernel.h>
64 # include <cyg/kernel/thread.hxx>
65 # include <cyg/kernel/thread.inl>
66 # include <cyg/kernel/sched.hxx>
67 # include <cyg/kernel/sched.inl>
68 # include <cyg/kernel/sema.hxx>
69 #endif
70 #include <cyg/infra/testcase.h>
71
72 #if !defined(CYGPKG_KERNEL)
73 # define NA_MSG "Requires kernel"
74 #elif !defined(CYGFUN_KERNEL_THREADS_TIMER)
75 # define NA_MSG "Requires thread timers"
76 #elif !defined(CYGPKG_ISOINFRA)
77 # define NA_MSG "Requires isoinfra package"
78 #elif !CYGINT_ISO_MALLOC
79 # define NA_MSG "Requires malloc"
80 #elif !CYGINT_ISO_MALLINFO
81 # define NA_MSG "Requires mallinfo"
82 #elif !CYGINT_ISO_RAND
83 # define NA_MSG "Requires rand"
84 #elif defined(CYGIMP_MEMALLOC_MALLOC_DLMALLOC) && \
85       !defined(CYGIMP_MEMALLOC_ALLOCATOR_DLMALLOC_THREADAWARE)
86 # define NA_MSG "Requires thread-safe dlmalloc"
87 #elif defined(CYGIMP_MEMALLOC_MALLOC_VARIABLE_SIMPLE) && \
88       !defined(CYGSEM_MEMALLOC_ALLOCATOR_VARIABLE_THREADAWARE)
89 # define NA_MSG "Requires thread-safe variable block allocator"
90 #endif
91
92 #ifdef NA_MSG
93
94 externC void
95 cyg_start(void)
96 {
97     CYG_TEST_INIT();
98     CYG_TEST_NA( NA_MSG );
99     CYG_TEST_FINISH("Done");
100 }
101 #else
102 //#define DEBUGTEST 1
103 #define NTHREADS 4
104 #include "testaux.hxx"
105
106 #include <cyg/infra/diag.h>
107
108 Cyg_Counting_Semaphore startsema;
109
110 volatile int stopnow = 0;
111
112 struct ptr {
113     char* volatile p;
114     volatile size_t size;
115     volatile unsigned char busy;
116 };
117
118 #define STRINGIFY1( _x_ ) #_x_
119 #define STRINGIFY( _x_ ) STRINGIFY1( _x_ )
120
121 #define NUM_PTRS 100
122 #define WAITFORMEMDELAYMAX (cyg_test_is_simulator ? 1 : 3)
123 #define LOOPDELAYMAX       (cyg_test_is_simulator ? 1 : 3)
124 #define ITERATIONS         (cyg_test_is_simulator ? 10 : 200)
125 #define OUTPUTINTERVAL     (cyg_test_is_simulator ? 1 : 10)
126
127 int iterations = ITERATIONS;
128
129 static struct ptr ptrs[ NUM_PTRS ];
130
131 static __inline__ int
132 myrand(int limit, unsigned int *seed)
133 {
134     int r;
135     double l=(double)(limit+1);
136     r=(int)( l*rand_r(seed) / (RAND_MAX+1.0) );
137     return r;
138 }
139
140 size_t memsize;
141
142 static void
143 fill_with_data( struct ptr *p )
144 {
145     unsigned int i, j;
146     for (i=0; i < (p->size/4); i++)
147         ((unsigned int *)p->p)[i] = (unsigned int)p;
148     for ( j=i*4; j < p->size ; j++ )
149         p->p[j] = ((char *)p)[j-i*4];
150 }
151
152 static void
153 check_data( struct ptr *p )
154 {
155     unsigned int i, j;
156     for (i=0; i < (p->size/4); i++)
157         CYG_TEST_CHECK( ((unsigned int *)p->p)[i] == (unsigned int)p,
158                         "Data didn't compare correctly");
159     for ( j=i*4; j < p->size ; j++ )
160         CYG_TEST_CHECK( p->p[j] == ((char *)p)[j-i*4],
161                         "Data didn't compare correctly");
162 }
163
164 static void
165 check_zeroes( struct ptr *p )
166 {
167     unsigned int i, j;
168     for (i=0; i < (p->size/4); i++)
169         CYG_TEST_CHECK( ((int *)p->p)[i] == 0,
170                         "Zeroed data didn't compare correctly");
171     for ( j=i*4; j < p->size ; j++ )
172         CYG_TEST_CHECK( p->p[j] == 0,
173                         "Zeroed data didn't compare correctly");
174 }
175
176
177 static void
178 thrmalloc( CYG_ADDRWORD data )
179 {
180     int r, i;
181     void *mem;
182     unsigned int seed;
183
184     startsema.wait();
185         
186     while (!stopnow) {
187         r = myrand( NUM_PTRS-1, &seed );
188         
189         for (i=r+1; ; i++) {
190             Cyg_Scheduler::lock();
191             if (i == NUM_PTRS)
192                 i=0;
193             if (!ptrs[i].busy && (ptrs[i].p == NULL) )
194                 break;
195             Cyg_Scheduler::unlock();
196             if ( i==r ) {
197                 Cyg_Thread::self()->delay( myrand(WAITFORMEMDELAYMAX, &seed) );
198             }
199         }
200         ptrs[i].busy = 1;
201         Cyg_Scheduler::unlock();
202         r = myrand(memsize, &seed);
203         mem = malloc(r);
204         ptrs[i].p = (char *)mem;
205         ptrs[i].size = r;
206         if ( NULL != mem ) {
207 #ifdef DEBUGTEST
208             diag_printf("malloc=%08x size=%d\n", mem, r);
209 #endif
210             fill_with_data( &ptrs[i] );
211         }
212         ptrs[i].busy = 0;        
213         Cyg_Thread::self()->delay( myrand(LOOPDELAYMAX, &seed) );
214     }
215 }
216
217 static void
218 thrcalloc( CYG_ADDRWORD data )
219 {
220     int r, i;
221     void *mem;
222     unsigned int seed;
223
224     startsema.wait();
225         
226     while (!stopnow) {
227         r = myrand( NUM_PTRS-1, &seed );
228         
229         for (i=r+1; ; i++) {
230             Cyg_Scheduler::lock();
231             if (i == NUM_PTRS)
232                 i=0;
233             if (!ptrs[i].busy && (ptrs[i].p == NULL) )
234                 break;
235             Cyg_Scheduler::unlock();
236             if ( i==r ) {
237                 Cyg_Thread::self()->delay( myrand(WAITFORMEMDELAYMAX, &seed) );
238             }
239         }
240         ptrs[i].busy = 1;
241         Cyg_Scheduler::unlock();
242         r = myrand(memsize, &seed);
243         mem = calloc( 1, r );
244         ptrs[i].p = (char *)mem;
245         ptrs[i].size = r;
246         if ( NULL != mem ) {
247 #ifdef DEBUGTEST
248             diag_printf("calloc=%08x size=%d\n", mem, r);
249 #endif
250             check_zeroes( &ptrs[i] );
251             fill_with_data( &ptrs[i] );
252         }
253         ptrs[i].busy = 0;        
254         Cyg_Thread::self()->delay( myrand(LOOPDELAYMAX, &seed) );
255     }
256 }
257
258 static void
259 thrrealloc( CYG_ADDRWORD data )
260 {
261     int r, i;
262     void *mem;
263     unsigned int seed;
264
265     startsema.wait();
266         
267     while (!stopnow) {
268         r = myrand( NUM_PTRS-1, &seed );
269         
270         for (i=r+1; ; i++) {
271             Cyg_Scheduler::lock();
272             if (i == NUM_PTRS)
273                 i=0;
274             if (!ptrs[i].busy && (ptrs[i].p != NULL) )
275                 break;
276             Cyg_Scheduler::unlock();
277             if ( i==r ) {
278                 Cyg_Thread::self()->delay( myrand(WAITFORMEMDELAYMAX, &seed) );
279             }
280         }
281         ptrs[i].busy = 1;
282         Cyg_Scheduler::unlock();
283         check_data( &ptrs[i] );
284         r = myrand(memsize - 1, &seed) + 1;
285         mem = realloc( (void *)ptrs[i].p, r );
286         if ( NULL != mem ) {
287 #ifdef DEBUGTEST
288             diag_printf("realloc=%08x oldsize=%d newsize=%d\n", mem, ptrs[i].size, r);
289 #endif
290             ptrs[i].size = r;
291             ptrs[i].p = (char *)mem;
292             fill_with_data( &ptrs[i] );
293         }
294         ptrs[i].busy = 0;        
295         Cyg_Thread::self()->delay( myrand(LOOPDELAYMAX, &seed) );
296     }
297 }
298
299 static void
300 thrfree( CYG_ADDRWORD data )
301 {
302     int r, i;
303     int iter = 0;
304     struct mallinfo minfo;
305     unsigned int seed;
306
307     minfo = mallinfo();
308     memsize = (unsigned long) minfo.maxfree;
309     diag_printf("INFO:<Iteration 0, arenasize=%d, space free=%d, maxfree=%d>\n",
310                 minfo.arena, minfo.fordblks, minfo.maxfree );
311
312     // wake the three threads above.
313     startsema.post(); startsema.post(); startsema.post();
314         
315     Cyg_Thread::self()->delay(1);
316
317     while (1) {
318         if ( (iter > 0) && (0 == (iter % OUTPUTINTERVAL)) ) {
319             minfo = mallinfo();
320             diag_printf("INFO:<Iteration %d, arenasize=%d, "
321                         "space free=%d, maxfree=%d>\n",
322                         iter, minfo.arena, minfo.fordblks, minfo.maxfree );
323         }
324
325         if ( iterations == iter++ )
326             stopnow++;
327
328         r = myrand( NUM_PTRS-1, &seed );
329         
330         for (i=r+1; ; i++) {
331             Cyg_Scheduler::lock();
332             if (i >= NUM_PTRS)
333                 i=0;
334             if (!ptrs[i].busy && (ptrs[i].p != NULL) )
335                 break;
336             Cyg_Scheduler::unlock();
337             if ( i==r ) {
338                 if ( stopnow ) {
339                     // we may have gone round all the ptrs even though one
340                     // or more of them was busy, so check again just for that
341                     int j;
342                     for (j=0; j<NUM_PTRS; j++)
343                         if (ptrs[j].busy)
344                             break;
345                     if ( j<NUM_PTRS )
346                         continue;
347                     struct mallinfo minfo;
348
349                     minfo = mallinfo();
350                     diag_printf("INFO:<Iteration %d, arenasize=%d, "
351                                 "space free=%d, maxfree=%d>\n",
352                                 iter, minfo.arena, minfo.fordblks,
353                                 minfo.maxfree );
354                     CYG_TEST_PASS_FINISH("malloc4 test completed successfully");
355                 } else {
356                     Cyg_Thread::self()->delay( 
357                         myrand(WAITFORMEMDELAYMAX, &seed) );
358                 }
359             }
360         }
361         ptrs[i].busy = 1;
362         Cyg_Scheduler::unlock();
363         check_data( &ptrs[i] );
364 #ifdef DEBUGTEST
365         diag_printf("about to free %08x\n", ptrs[i].p);
366 #endif
367         free( (void *)ptrs[i].p );
368         ptrs[i].p = NULL;
369         ptrs[i].busy = 0;
370         Cyg_Thread::self()->delay( myrand(LOOPDELAYMAX, &seed) );
371     }
372 }
373
374
375 externC void
376 cyg_start(void)
377 {
378 #ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
379     cyg_hal_invoke_constructors();
380 #endif
381     CYG_TEST_INIT();
382     CYG_TEST_INFO("Starting malloc4 test");
383
384     new_thread(thrmalloc, 0);
385     new_thread(thrcalloc, 1);
386     new_thread(thrrealloc, 2);
387     new_thread(thrfree, 3);
388
389     Cyg_Scheduler::start();
390
391     CYG_TEST_FAIL_FINISH("Not reached");
392 } // cyg_start()
393
394 #endif // !NA_MSG
395
396 // EOF malloc4.cxx