1 /******************************************************************************/ 2 /* */ 3 /* Copyright (c) International Business Machines Corp., 2001 */ 4 /* */ 5 /* This program is free software; you can redistribute it and/or modify */ 6 /* it under the terms of the GNU General Public License as published by */ 7 /* the Free Software Foundation; either version 2 of the License, or */ 8 /* (at your option) any later version. */ 9 /* */ 10 /* This program is distributed in the hope that it will be useful, */ 11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ 12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */ 13 /* the GNU General Public License for more details. */ 14 /* */ 15 /* You should have received a copy of the GNU General Public License */ 16 /* along with this program; if not, write to the Free Software */ 17 /* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ 18 /* */ 19 /******************************************************************************/ 20 21 /******************************************************************************/ 22 /* */ 23 /* History: Nov - 04 - 2001 Created - Manoj Iyer, IBM Austin TX. */ 24 /* email:manjo (at) austin.ibm.com */ 25 /* */ 26 /* Nov - 06 - 2001 Modified - Manoj Iyer, IBM Austin TX. */ 27 /* - added function alloc_mem() */ 28 /* */ 29 /* Nov - 08 - 2001 Modified - Manoj Iyer, IBM Austin TX. */ 30 /* - added logic to allocate memory in the size */ 31 /* of fibanocci numbers. */ 32 /* - fixed segmetation fault. */ 33 /* */ 34 /* Nov - 09 - 2001 Modified - Manoj Iyer, IBM Austin TX. */ 35 /* - separated alocation logic to allocate_free()*/ 36 /* function. */ 37 /* - introduced logic to randomly pick allocation*/ 38 /* scheme. size = fibannoci number, pow of 2 or*/ 39 /* power of 3. */ 40 /* - changed comments. */ 41 /* - Added test to LTP. */ 42 /* */ 43 /* Nov - 09 - 2001 Modified - Manoj Iyer,IBM Austin TX. */ 44 /* - Removed compile errors. */ 45 /* - too many missing arguments. */ 46 /* */ 47 /* Nov - 19 - 2001 Modified - Manoj Iyer, IBM Austin TX. */ 48 /* - fixed segmentation fault. */ 49 /* changed variable th_status from dynamic to */ 50 /* static array. */ 51 /* */ 52 /* May - 15 - 2002 Dan Kegel (dank (at) kegel.com) */ 53 /* - Fixed crash on > 30 threads */ 54 /* - Cleaned up, fixed compiler warnings */ 55 /* - Removed mallocs that could fail */ 56 /* - Note that pthread_create fails with EINTR */ 57 /* */ 58 /* File: mallocstress.c */ 59 /* */ 60 /* Description: This program stresses the VMM and C library */ 61 /* by spawning N threads which */ 62 /* malloc blocks of increasing size until malloc returns NULL. */ 63 /******************************************************************************/ 64 #include <stdio.h> 65 #include <pthread.h> 66 #include <stdlib.h> 67 #include <unistd.h> 68 #include <math.h> 69 #include <assert.h> 70 #include <errno.h> 71 #include <stdint.h> 72 #include <sys/types.h> 73 74 #include "tst_test.h" 75 #include "tst_safe_pthread.h" 76 77 /* Number of loops per-thread */ 78 #define NUM_LOOPS 100 79 80 /* Number of threads to create */ 81 #define NUM_THREADS 60 82 83 /* Define SPEW_SIGNALS to tickle thread_create bug (it fails if interrupted). */ 84 #define SPEW_SIGNALS 85 86 static pthread_t *thread_id; /* Spawned thread */ 87 88 static void my_yield(void) 89 { 90 #ifdef SPEW_SIGNALS 91 /* usleep just happens to use signals in glibc at moment. 92 * This is good because it allows us to test whether pthread_create 93 * improperly returns EINTR (which would violate SUSv3) 94 */ 95 usleep(0); 96 #else 97 /* If you want this test to pass, don't define SPEW_SIGNALS, 98 * as pthread_create is broken at moment, and fails if interrupted 99 */ 100 static const struct timespec t0 = { 0, 0 }; 101 nanosleep(&t0, NULL); 102 #endif 103 } 104 105 /* 106 * allocate_free() - Allocate and free test called per-thread 107 * 108 * @scheme: 0-3; selects how fast memory size grows 109 * 110 * This function does the allocation and free by calling malloc 111 * and free functions. The size of the memory to be malloced is 112 * determined by the caller of this function. The size can be 113 * a number from the fibannoaci series, power of 2 or 3 or 5 114 * 115 * Return: 116 * 0: success 117 * 1: failure 118 */ 119 int allocate_free(int scheme) 120 { 121 int loop; 122 const int MAXPTRS = 50; /* only 42 or so get used on 32 bit machine */ 123 124 for (loop = 0; loop < NUM_LOOPS; loop++) { 125 size_t oldsize = 5; 126 size_t size = sizeof(long); 127 long *ptrs[MAXPTRS]; 128 int num_alloc; 129 int i; 130 131 /* loop terminates in one of three ways: 132 * 1. after MAXPTRS iterations 133 * 2. if malloc fails 134 * 3. if new size overflows 135 */ 136 for (num_alloc = 0; num_alloc < MAXPTRS; num_alloc++) { 137 size_t newsize = 0; 138 139 /* Malloc the next block */ 140 ptrs[num_alloc] = malloc(size); 141 /* terminate loop if malloc fails */ 142 if (!ptrs[num_alloc]) 143 break; 144 ptrs[num_alloc][0] = num_alloc; 145 146 /* Increase size according to one of four schedules. */ 147 switch (scheme) { 148 case 0: 149 newsize = size + oldsize; 150 oldsize = size; 151 break; 152 case 1: 153 newsize = size * 2; 154 break; 155 case 2: 156 newsize = size * 3; 157 break; 158 case 3: 159 newsize = size * 5; 160 break; 161 default: 162 assert(0); 163 } 164 /* terminate loop on overflow */ 165 if (newsize < size) 166 break; 167 size = newsize; 168 169 my_yield(); 170 } 171 172 for (i = 0; i < num_alloc; i++) { 173 if (ptrs[i][0] != i) { 174 tst_res(TFAIL, 175 "pid[%d]: fail: bad sentinel value\n", 176 getpid()); 177 return 1; 178 } 179 free(ptrs[i]); 180 my_yield(); 181 } 182 183 my_yield(); 184 } 185 186 /* Success! */ 187 return 0; 188 } 189 190 void *alloc_mem(void *threadnum) 191 { 192 int err; 193 194 /* waiting for other threads starting */ 195 TST_CHECKPOINT_WAIT(0); 196 197 /* thread N will use growth scheme N mod 4 */ 198 err = allocate_free(((uintptr_t)threadnum) % 4); 199 tst_res(TINFO, 200 "Thread [%d]: allocate_free() returned %d, %s. Thread exiting.\n", 201 (int)(uintptr_t)threadnum, err, 202 (err ? "failed" : "succeeded")); 203 return (void *)(uintptr_t) (err ? -1 : 0); 204 } 205 206 static void stress_malloc(void) 207 { 208 int thread_index; 209 210 for (thread_index = 0; thread_index < NUM_THREADS; thread_index++) { 211 SAFE_PTHREAD_CREATE(&thread_id[thread_index], NULL, alloc_mem, 212 (void *)(uintptr_t)thread_index); 213 } 214 215 /* Wake up all threads */ 216 TST_CHECKPOINT_WAKE2(0, NUM_THREADS); 217 218 /* wait for all threads to finish */ 219 for (thread_index = 0; thread_index < NUM_THREADS; thread_index++) { 220 void *status; 221 222 SAFE_PTHREAD_JOIN(thread_id[thread_index], &status); 223 if ((intptr_t)status != 0) { 224 tst_res(TFAIL, "thread [%d] - exited with errors\n", 225 thread_index); 226 } 227 } 228 229 tst_res(TPASS, "malloc stress test finished successfully"); 230 } 231 232 static void setup(void) 233 { 234 thread_id = SAFE_MALLOC(sizeof(pthread_t) * NUM_THREADS); 235 } 236 237 static void cleanup(void) 238 { 239 if (thread_id) { 240 free(thread_id); 241 thread_id = NULL; 242 } 243 } 244 245 static struct tst_test test = { 246 .needs_checkpoints = 1, 247 .setup = setup, 248 .cleanup = cleanup, 249 .test_all = stress_malloc, 250 }; 251