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