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@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@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
my_yield(void)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 */
allocate_free(int scheme)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
alloc_mem(void * threadnum)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
stress_malloc(void)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
setup(void)232 static void setup(void)
233 {
234 thread_id = SAFE_MALLOC(sizeof(pthread_t) * NUM_THREADS);
235 }
236
cleanup(void)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 .timeout = 600,
247 .needs_checkpoints = 1,
248 .setup = setup,
249 .cleanup = cleanup,
250 .test_all = stress_malloc,
251 };
252