xref: /netbsd/usr.bin/xlint/lint1/mem1.c (revision bf9ec67e)
1 /*	$NetBSD: mem1.c,v 1.7 2002/01/31 19:36:54 tv 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.7 2002/01/31 19:36:54 tv 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 
200 	s = ALIGN(s);
201 	if ((mb = *mbp) == NULL || mb->nfree < s) {
202 		if ((mb = frmblks) == NULL) {
203 			mb = xnewblk();
204 			(void)memset(mb->blk, 0, mb->size);
205 		} else {
206 			frmblks = mb->nxt;
207 		}
208 		mb->ffree = mb->blk;
209 		mb->nfree = mb->size;;
210 		mb->nxt = *mbp;
211 		*mbp = mb;
212 	}
213 	p = mb->ffree;
214 	mb->ffree = (char *)mb->ffree + s;
215 	mb->nfree -= s;
216 	return (p);
217 }
218 
219 /*
220  * Move all blocks from list *fmbp to free list. For each block, set all
221  * used memory to zero.
222  */
223 static void
224 xfreeblk(mbl_t **fmbp)
225 {
226 	mbl_t	*mb;
227 
228 	while ((mb = *fmbp) != NULL) {
229 		*fmbp = mb->nxt;
230 		mb->nxt = frmblks;
231 		frmblks = mb;
232 		(void)memset(mb->blk, 0, mb->size - mb->nfree);
233 	}
234 }
235 
236 void
237 initmem(void)
238 {
239 	int	pgsz;
240 
241 	pgsz = getpagesize();
242 	mblklen = ((MBLKSIZ + pgsz - 1) / pgsz) * pgsz;
243 
244 	mblks = xcalloc(nmblks = ML_INC, sizeof (mbl_t *));
245 }
246 
247 
248 /*
249  * Allocate memory associated with level l.
250  */
251 void *
252 getlblk(int l, size_t s)
253 {
254 
255 	while (l >= nmblks) {
256 		mblks = xrealloc(mblks, (nmblks + ML_INC) * sizeof (mbl_t *));
257 		(void)memset(&mblks[nmblks], 0, ML_INC * sizeof (mbl_t *));
258 		nmblks += ML_INC;
259 	}
260 	return (xgetblk(&mblks[l], s));
261 }
262 
263 void *
264 getblk(size_t s)
265 {
266 
267 	return (getlblk(mblklev, s));
268 }
269 
270 /*
271  * Free all memory associated with level l.
272  */
273 void
274 freelblk(int l)
275 {
276 
277 	xfreeblk(&mblks[l]);
278 }
279 
280 void
281 freeblk(void)
282 {
283 
284 	freelblk(mblklev);
285 }
286 
287 /*
288  * tgetblk() returns memory which is associated with the current
289  * expression.
290  */
291 static	mbl_t	*tmblk;
292 
293 void *
294 tgetblk(size_t s)
295 {
296 
297 	return (xgetblk(&tmblk, s));
298 }
299 
300 /*
301  * Get memory for a new tree node.
302  */
303 tnode_t *
304 getnode(void)
305 {
306 
307 	return (tgetblk(sizeof (tnode_t)));
308 }
309 
310 /*
311  * Free all memory which is allocated by the current expression.
312  */
313 void
314 tfreeblk(void)
315 {
316 
317 	xfreeblk(&tmblk);
318 }
319 
320 /*
321  * Save the memory which is used by the current expression. This memory
322  * is not freed by the next tfreeblk() call. The pointer returned can be
323  * used to restore the memory.
324  */
325 mbl_t *
326 tsave(void)
327 {
328 	mbl_t	*tmem;
329 
330 	tmem = tmblk;
331 	tmblk = NULL;
332 	return (tmem);
333 }
334 
335 /*
336  * Free all memory used for the current expression and the memory used
337  * be a previous expression and saved by tsave(). The next call to
338  * tfreeblk() frees the restored memory.
339  */
340 void
341 trestor(mbl_t *tmem)
342 {
343 
344 	tfreeblk();
345 	if (tmblk != NULL) {
346 		free(tmblk->blk);
347 		free(tmblk);
348 	}
349 	tmblk = tmem;
350 }
351