xref: /netbsd/usr.bin/xlint/lint1/mem1.c (revision c4a72b64)
1 /*	$NetBSD: mem1.c,v 1.8 2002/06/28 05:03:55 jmc Exp $	*/
2 
3 /*
4  * Copyright (c) 1994, 1995 Jochen Pohl
5  * All Rights Reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by Jochen Pohl for
18  *	The NetBSD Project.
19  * 4. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <sys/cdefs.h>
35 #if defined(__RCSID) && !defined(lint)
36 __RCSID("$NetBSD: mem1.c,v 1.8 2002/06/28 05:03:55 jmc Exp $");
37 #endif
38 
39 #include <sys/types.h>
40 #include <sys/mman.h>
41 #include <sys/param.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45 
46 #include "lint1.h"
47 
48 /*
49  * Filenames allocated by fnalloc() and fnnalloc() are shared.
50  */
51 typedef struct fn {
52 	char	*fn_name;
53 	size_t	fn_len;
54 	int	fn_id;
55 	struct	fn *fn_nxt;
56 } fn_t;
57 
58 static	fn_t	*fnames;
59 
60 static	fn_t	*srchfn(const char *, size_t);
61 
62 /*
63  * Look for a Filename of length l.
64  */
65 static fn_t *
66 srchfn(const char *s, size_t len)
67 {
68 	fn_t	*fn;
69 
70 	for (fn = fnames; fn != NULL; fn = fn->fn_nxt) {
71 		if (fn->fn_len == len && memcmp(fn->fn_name, s, len) == 0)
72 			break;
73 	}
74 	return (fn);
75 }
76 
77 /*
78  * Return a shared string for filename s.
79  */
80 const char *
81 fnalloc(const char *s)
82 {
83 
84 	return (s != NULL ? fnnalloc(s, strlen(s)) : NULL);
85 }
86 
87 const char *
88 fnnalloc(const char *s, size_t len)
89 {
90 	fn_t	*fn;
91 
92 	static	int	nxt_id = 0;
93 
94 	if (s == NULL)
95 		return (NULL);
96 
97 	if ((fn = srchfn(s, len)) == NULL) {
98 		fn = xmalloc(sizeof (fn_t));
99 		/* Do not used strdup() because string is not NUL-terminated.*/
100 		fn->fn_name = xmalloc(len + 1);
101 		(void)memcpy(fn->fn_name, s, len);
102 		fn->fn_name[len] = '\0';
103 		fn->fn_len = len;
104 		fn->fn_id = nxt_id++;
105 		fn->fn_nxt = fnames;
106 		fnames = fn;
107 		/* Write id of this filename to the output file. */
108 		outclr();
109 		outint(fn->fn_id);
110 		outchar('s');
111 		outstrg(fn->fn_name);
112 	}
113 	return (fn->fn_name);
114 }
115 
116 /*
117  * Get id of a filename.
118  */
119 int
120 getfnid(const char *s)
121 {
122 	fn_t	*fn;
123 
124 	if (s == NULL || (fn = srchfn(s, strlen(s))) == NULL)
125 		return (-1);
126 	return (fn->fn_id);
127 }
128 
129 /*
130  * Memory for declarations and other things which must be available
131  * until the end of a block (or the end of the translation unit)
132  * are assoziated with the level (mblklev) of the block (or wiht 0).
133  * Because these memory is allocated in large blocks associated with
134  * a given level it can be freed easily at the end of a block.
135  */
136 #define	ML_INC	((size_t)32)		/* Increment for length of *mblks */
137 
138 typedef struct mbl {
139 	void	*blk;			/* beginning of memory block */
140 	void	*ffree;			/* first free byte */
141 	size_t	nfree;			/* # of free bytes */
142 	size_t	size;			/* total size of memory block */
143 	struct	mbl *nxt;		/* next block */
144 } mbl_t;
145 
146 /*
147  * Array of pointers to lists of memory blocks. mblklev is used as
148  * index into this array.
149  */
150 static	mbl_t	**mblks;
151 
152 /* number of elements in *mblks */
153 static	size_t	nmblks;
154 
155 /* free list for memory blocks */
156 static	mbl_t	*frmblks;
157 
158 /* length of new allocated memory blocks */
159 static	size_t	mblklen;
160 
161 static	void	*xgetblk(mbl_t **, size_t);
162 static	void	xfreeblk(mbl_t **);
163 static	mbl_t	*xnewblk(void);
164 
165 static mbl_t *
166 xnewblk(void)
167 {
168 	mbl_t	*mb;
169 	int	prot, flags;
170 
171 	mb = xmalloc(sizeof (mbl_t));
172 
173 	/* use mmap instead of malloc to avoid malloc's size overhead */
174 
175 	prot = PROT_READ | PROT_WRITE;
176 	flags = MAP_ANON | MAP_PRIVATE;
177 	mb->blk = mmap(NULL, mblklen, prot, flags, -1, (off_t)0);
178 	if (mb->blk == (void *)-1)
179 		err(1, "can't map memory");
180 
181 	mb->size = mblklen;
182 
183 	return (mb);
184 }
185 
186 /*
187  * Allocate new memory. If the first block of the list has not enough
188  * free space, or there is no first block, get a new block. The new
189  * block is taken from the free list or, if there is no block on the
190  * free list, is allocated using xnewblk(). If a new block is allocated
191  * it is initialized with zero. Blocks taken from the free list are
192  * zero'd in xfreeblk().
193  */
194 static void *
195 xgetblk(mbl_t **mbp, size_t s)
196 {
197 	mbl_t	*mb;
198 	void	*p;
199 	size_t	t = 0;
200 
201 	s = ALIGN(s);
202 	if ((mb = *mbp) == NULL || mb->nfree < s) {
203 		if ((mb = frmblks) == NULL) {
204 			if (s > mblklen) {
205 				t = mblklen;
206 				mblklen = s;
207 			}
208 			mb = xnewblk();
209 			if (t)
210 				mblklen = t;
211 			(void)memset(mb->blk, 0, mb->size);
212 		} else {
213 			frmblks = mb->nxt;
214 		}
215 		mb->ffree = mb->blk;
216 		mb->nfree = mb->size;;
217 		mb->nxt = *mbp;
218 		*mbp = mb;
219 	}
220 	p = mb->ffree;
221 	mb->ffree = (char *)mb->ffree + s;
222 	mb->nfree -= s;
223 	return (p);
224 }
225 
226 /*
227  * Move all blocks from list *fmbp to free list. For each block, set all
228  * used memory to zero.
229  */
230 static void
231 xfreeblk(mbl_t **fmbp)
232 {
233 	mbl_t	*mb;
234 
235 	while ((mb = *fmbp) != NULL) {
236 		*fmbp = mb->nxt;
237 		mb->nxt = frmblks;
238 		frmblks = mb;
239 		(void)memset(mb->blk, 0, mb->size - mb->nfree);
240 	}
241 }
242 
243 void
244 initmem(void)
245 {
246 	int	pgsz;
247 
248 	pgsz = getpagesize();
249 	mblklen = ((MBLKSIZ + pgsz - 1) / pgsz) * pgsz;
250 
251 	mblks = xcalloc(nmblks = ML_INC, sizeof (mbl_t *));
252 }
253 
254 
255 /*
256  * Allocate memory associated with level l.
257  */
258 void *
259 getlblk(int l, size_t s)
260 {
261 
262 	while (l >= nmblks) {
263 		mblks = xrealloc(mblks, (nmblks + ML_INC) * sizeof (mbl_t *));
264 		(void)memset(&mblks[nmblks], 0, ML_INC * sizeof (mbl_t *));
265 		nmblks += ML_INC;
266 	}
267 	return (xgetblk(&mblks[l], s));
268 }
269 
270 void *
271 getblk(size_t s)
272 {
273 
274 	return (getlblk(mblklev, s));
275 }
276 
277 /*
278  * Free all memory associated with level l.
279  */
280 void
281 freelblk(int l)
282 {
283 
284 	xfreeblk(&mblks[l]);
285 }
286 
287 void
288 freeblk(void)
289 {
290 
291 	freelblk(mblklev);
292 }
293 
294 /*
295  * tgetblk() returns memory which is associated with the current
296  * expression.
297  */
298 static	mbl_t	*tmblk;
299 
300 void *
301 tgetblk(size_t s)
302 {
303 
304 	return (xgetblk(&tmblk, s));
305 }
306 
307 /*
308  * Get memory for a new tree node.
309  */
310 tnode_t *
311 getnode(void)
312 {
313 
314 	return (tgetblk(sizeof (tnode_t)));
315 }
316 
317 /*
318  * Free all memory which is allocated by the current expression.
319  */
320 void
321 tfreeblk(void)
322 {
323 
324 	xfreeblk(&tmblk);
325 }
326 
327 /*
328  * Save the memory which is used by the current expression. This memory
329  * is not freed by the next tfreeblk() call. The pointer returned can be
330  * used to restore the memory.
331  */
332 mbl_t *
333 tsave(void)
334 {
335 	mbl_t	*tmem;
336 
337 	tmem = tmblk;
338 	tmblk = NULL;
339 	return (tmem);
340 }
341 
342 /*
343  * Free all memory used for the current expression and the memory used
344  * be a previous expression and saved by tsave(). The next call to
345  * tfreeblk() frees the restored memory.
346  */
347 void
348 trestor(mbl_t *tmem)
349 {
350 
351 	tfreeblk();
352 	if (tmblk != NULL) {
353 		free(tmblk->blk);
354 		free(tmblk);
355 	}
356 	tmblk = tmem;
357 }
358