1 //=================================================================
5 // Stress test malloc(), calloc(), realloc() and free()
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.
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.
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
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.
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.
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.
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####
43 // Author(s): jlarmour
46 // Description: Contains a rigorous multithreaded test for malloc(),
47 // calloc(), realloc() and free() functions
50 //####DESCRIPTIONEND####
56 #include <pkgconf/system.h>
57 #include <pkgconf/memalloc.h> // config header
58 #ifdef CYGPKG_ISOINFRA
59 # include <pkgconf/isoinfra.h>
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>
70 #include <cyg/infra/testcase.h>
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"
98 CYG_TEST_NA( NA_MSG );
99 CYG_TEST_FINISH("Done");
102 //#define DEBUGTEST 1
104 #include "testaux.hxx"
106 #include <cyg/infra/diag.h>
108 Cyg_Counting_Semaphore startsema;
110 volatile int stopnow = 0;
114 volatile size_t size;
115 volatile unsigned char busy;
118 #define STRINGIFY1( _x_ ) #_x_
119 #define STRINGIFY( _x_ ) STRINGIFY1( _x_ )
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)
127 int iterations = ITERATIONS;
129 static struct ptr ptrs[ NUM_PTRS ];
131 static __inline__ int
132 myrand(int limit, unsigned int *seed)
135 double l=(double)(limit+1);
136 r=(int)( l*rand_r(seed) / (RAND_MAX+1.0) );
143 fill_with_data( struct ptr *p )
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];
153 check_data( struct ptr *p )
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");
165 check_zeroes( struct ptr *p )
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");
178 thrmalloc( CYG_ADDRWORD data )
187 r = myrand( NUM_PTRS-1, &seed );
190 Cyg_Scheduler::lock();
193 if (!ptrs[i].busy && (ptrs[i].p == NULL) )
195 Cyg_Scheduler::unlock();
197 Cyg_Thread::self()->delay( myrand(WAITFORMEMDELAYMAX, &seed) );
201 Cyg_Scheduler::unlock();
202 r = myrand(memsize, &seed);
204 ptrs[i].p = (char *)mem;
208 diag_printf("malloc=%08x size=%d\n", mem, r);
210 fill_with_data( &ptrs[i] );
213 Cyg_Thread::self()->delay( myrand(LOOPDELAYMAX, &seed) );
218 thrcalloc( CYG_ADDRWORD data )
227 r = myrand( NUM_PTRS-1, &seed );
230 Cyg_Scheduler::lock();
233 if (!ptrs[i].busy && (ptrs[i].p == NULL) )
235 Cyg_Scheduler::unlock();
237 Cyg_Thread::self()->delay( myrand(WAITFORMEMDELAYMAX, &seed) );
241 Cyg_Scheduler::unlock();
242 r = myrand(memsize, &seed);
243 mem = calloc( 1, r );
244 ptrs[i].p = (char *)mem;
248 diag_printf("calloc=%08x size=%d\n", mem, r);
250 check_zeroes( &ptrs[i] );
251 fill_with_data( &ptrs[i] );
254 Cyg_Thread::self()->delay( myrand(LOOPDELAYMAX, &seed) );
259 thrrealloc( CYG_ADDRWORD data )
268 r = myrand( NUM_PTRS-1, &seed );
271 Cyg_Scheduler::lock();
274 if (!ptrs[i].busy && (ptrs[i].p != NULL) )
276 Cyg_Scheduler::unlock();
278 Cyg_Thread::self()->delay( myrand(WAITFORMEMDELAYMAX, &seed) );
282 Cyg_Scheduler::unlock();
283 check_data( &ptrs[i] );
284 r = myrand(memsize - 1, &seed) + 1;
285 mem = realloc( (void *)ptrs[i].p, r );
288 diag_printf("realloc=%08x oldsize=%d newsize=%d\n", mem, ptrs[i].size, r);
291 ptrs[i].p = (char *)mem;
292 fill_with_data( &ptrs[i] );
295 Cyg_Thread::self()->delay( myrand(LOOPDELAYMAX, &seed) );
300 thrfree( CYG_ADDRWORD data )
304 struct mallinfo minfo;
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 );
312 // wake the three threads above.
313 startsema.post(); startsema.post(); startsema.post();
315 Cyg_Thread::self()->delay(1);
318 if ( (iter > 0) && (0 == (iter % OUTPUTINTERVAL)) ) {
320 diag_printf("INFO:<Iteration %d, arenasize=%d, "
321 "space free=%d, maxfree=%d>\n",
322 iter, minfo.arena, minfo.fordblks, minfo.maxfree );
325 if ( iterations == iter++ )
328 r = myrand( NUM_PTRS-1, &seed );
331 Cyg_Scheduler::lock();
334 if (!ptrs[i].busy && (ptrs[i].p != NULL) )
336 Cyg_Scheduler::unlock();
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
342 for (j=0; j<NUM_PTRS; j++)
347 struct mallinfo minfo;
350 diag_printf("INFO:<Iteration %d, arenasize=%d, "
351 "space free=%d, maxfree=%d>\n",
352 iter, minfo.arena, minfo.fordblks,
354 CYG_TEST_PASS_FINISH("malloc4 test completed successfully");
356 Cyg_Thread::self()->delay(
357 myrand(WAITFORMEMDELAYMAX, &seed) );
362 Cyg_Scheduler::unlock();
363 check_data( &ptrs[i] );
365 diag_printf("about to free %08x\n", ptrs[i].p);
367 free( (void *)ptrs[i].p );
370 Cyg_Thread::self()->delay( myrand(LOOPDELAYMAX, &seed) );
378 #ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG
379 cyg_hal_invoke_constructors();
382 CYG_TEST_INFO("Starting malloc4 test");
384 new_thread(thrmalloc, 0);
385 new_thread(thrcalloc, 1);
386 new_thread(thrrealloc, 2);
387 new_thread(thrfree, 3);
389 Cyg_Scheduler::start();
391 CYG_TEST_FAIL_FINISH("Not reached");