1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1999-2013 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <glenn.s.fowler@gmail.com> *
18 * *
19 ***********************************************************************/
20 #include "terror.h"
21
22 #include <setjmp.h>
23
24 #ifndef VMALLOC
25 #define VMALLOC 1
26 #endif
27 #if VMALLOC
28 #include <vmalloc.h>
29 #endif
30
31 static int Nalloc = 100000;
32 static int Life = 100;
33 static size_t Minsize = 100;
34 static size_t Maxsize = 1000;
35
36 #ifndef NIL
37 #define NIL(t) ((t)0)
38 #endif
39
40 typedef struct _piece_s Piece_t;
41 struct _piece_s
42 { Piece_t* next;
43 Piece_t* free;
44 void* data;
45 size_t size;
46 };
47
48 static int Step = 0; /* number of allocation steps done */
49 static int Allocing = 0; /* longjmp while in a malloc call */
50 static int Nlongjmp = 0; /* total number of such jumps */
51 static sigjmp_buf Jmpbuf;
52
sighup(int sig)53 static void sighup(int sig)
54 {
55 if(Allocing)
56 {
57 Allocing = 0; /* reset state now to reduce unnecessary longjmps */
58 #if VMALLOC
59 vmclrlock(0); /* unnecessary when vmalloc wraps siglongjmp() */
60 #endif
61 Nlongjmp += 1;
62
63 signal(sig, sighup); /* restore signal handler */
64
65 siglongjmp(Jmpbuf, SIGHUP);
66 }
67 else signal(sig, sighup);
68 }
69
sigalarm(int sig)70 static void sigalarm(int sig)
71 {
72 #if VMALLOC
73 { Vmstat_t vmst;
74 vmstat(Vmregion, &vmst);
75 tinfo(vmst.mesg);
76 }
77 #endif
78
79 terror("Process hang after running step=%d: SIGALRM was received", Step);
80 }
81
simulate(Piece_t * list,size_t nalloc)82 int simulate(Piece_t* list, size_t nalloc)
83 {
84 int k, p;
85 unsigned int rand;
86 size_t sz;
87 Piece_t *up, *next;
88 void *data;
89 int nfree, nresize;
90 unsigned int Rand = 1001; /* use a local RNG so that threads work uniformly */
91 #define RANDOM() (Rand = Rand*((1<<24)+(1<<8)+0x93) + 0xbadbeef)
92
93 nfree = nresize = 0;
94 sigsetjmp(Jmpbuf, 1);
95 if(Nlongjmp >= 1000) /* enough signal/longjmp */
96 return 0;
97
98 for(; Step < nalloc; ++Step)
99 { k = Step;
100
101 /* update all that needs updating */
102 for(up = list[k].free; up; up = next)
103 { next = up->next;
104
105 if(!up->data || up->size <= 0)
106 continue;
107
108 if((rand = RANDOM()%100) < 75)
109 {
110 Allocing = 1;
111 free(up->data);
112 Allocing = 0;
113
114 nfree += 1;
115 up->data = NIL(void*);
116 up->size = 0;
117 }
118 else
119 { sz = RANDOM()%(2*up->size) + 1;
120
121 Allocing = 1;
122 up->data = realloc(up->data, sz);
123 Allocing = 0;
124
125 if(!up->data)
126 terror("Failed to realloc(org=%d sz=%d)", up->size, sz);
127
128 nresize += 1;
129 up->size = sz;
130 }
131 }
132
133 /* get a random size in given range */
134 sz = (RANDOM() % (Maxsize-Minsize+1)) + Minsize;
135
136 Allocing = 1;
137 list[k].data = malloc(sz);
138 Allocing = 0;
139
140 if(!list[k].data)
141 {
142 #if VMALLOC
143 { Vmstat_t vmst;
144 vmstat(Vmregion, &vmst);
145 tinfo(vmst.mesg);
146 }
147 #endif
148 terror("Failed to malloc(%d) at step=%d", sz, Step);
149 }
150
151 list[k].size = sz;
152
153 /* get a random point in the future to update */
154 if((p = k+1 + RANDOM()%Life) < nalloc )
155 { list[k].next = list[p].free;
156 list[p].free = &list[k];
157 }
158 }
159
160 tinfo("nalloc=%d nfree=%d nresize=%d", nalloc, nfree, nresize);
161
162 return 0;
163 }
164
tmain()165 tmain()
166 {
167 int i, rv;
168 Piece_t *list;
169 size_t sz;
170 void *status;
171 pid_t ppid, cpid;
172
173 tinfo("Configuration: Nalloc=%d Life=%d Minsize=%d Maxsize=%d", Nalloc, Life, Minsize, Maxsize);
174
175 ppid = getpid(); /* pid of parent process */
176 cpid = 0;
177 signal(SIGHUP, sighup);
178 signal(SIGALRM,sigalarm);
179
180 #if 1
181 switch((cpid = fork()) )
182 { case 0 : /* child process */
183 for(;;) /* keep sending sighup to parent */
184 { asorelax(2012);
185 kill(ppid, SIGHUP);
186 }
187 break;
188
189 case -1:
190 terror("Can't fork() subprocess");
191 break;
192
193 default: /* parent */
194 break;
195 }
196 #endif
197
198 tresource(-1, 0);
199 sz = Nalloc*sizeof(Piece_t);
200 if(!(list = (Piece_t*)malloc(sz)) )
201 terror("Failed allocating list of objects nalloc=%d", Nalloc);
202 memset(list, 0, sz);
203
204 alarm(2);
205 simulate(list, Nalloc);
206 alarm(0);
207
208 if(cpid > 0)
209 kill(cpid, SIGKILL);
210
211 tinfo("ExecutedStep=%d vs. MaxStep=%d; Nlongjmp=%d", Step, Nalloc, Nlongjmp);
212 tresource(0, 0);
213
214 #if VMALLOC
215 { Vmstat_t vmst;
216 vmstat(Vmregion, &vmst);
217 tinfo(vmst.mesg);
218 }
219 #endif
220
221 texit(0);
222 }
223