mem1.c revision 80284
1284254Ssjg/*	$NetBSD: mem1.c,v 1.2 1995/07/03 21:24:25 cgd Exp $	*/
2246149Ssjg
3246149Ssjg/*
4246149Ssjg * Copyright (c) 1994, 1995 Jochen Pohl
5246149Ssjg * All Rights Reserved.
6246149Ssjg *
7246149Ssjg * Redistribution and use in source and binary forms, with or without
8246149Ssjg * modification, are permitted provided that the following conditions
9246149Ssjg * are met:
10246149Ssjg * 1. Redistributions of source code must retain the above copyright
11246149Ssjg *    notice, this list of conditions and the following disclaimer.
12246149Ssjg * 2. Redistributions in binary form must reproduce the above copyright
13246149Ssjg *    notice, this list of conditions and the following disclaimer in the
14246149Ssjg *    documentation and/or other materials provided with the distribution.
15246149Ssjg * 3. All advertising materials mentioning features or use of this software
16246149Ssjg *    must display the following acknowledgement:
17246149Ssjg *      This product includes software developed by Jochen Pohl for
18246149Ssjg *	The NetBSD Project.
19246149Ssjg * 4. The name of the author may not be used to endorse or promote products
20246149Ssjg *    derived from this software without specific prior written permission.
21246149Ssjg *
22246149Ssjg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23246149Ssjg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24246149Ssjg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25246149Ssjg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26246149Ssjg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27246149Ssjg * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28246149Ssjg * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29246149Ssjg * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30246149Ssjg * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31246149Ssjg * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32246149Ssjg */
33246149Ssjg
34246149Ssjg#ifndef lint
35246149Ssjgstatic const char rcsid[] =
36246149Ssjg  "$FreeBSD: head/usr.bin/xlint/lint1/mem1.c 80284 2001-07-24 14:02:07Z obrien $";
37246149Ssjg#endif
38281812Ssjg
39281812Ssjg#include <sys/types.h>
40281812Ssjg#include <sys/mman.h>
41281812Ssjg#include <sys/param.h>
42246149Ssjg#include <stdlib.h>
43281812Ssjg#include <string.h>
44281812Ssjg#include <unistd.h>
45246149Ssjg#include <err.h>
46246149Ssjg
47246149Ssjg#include "lint1.h"
48246149Ssjg
49246149Ssjg/*
50246149Ssjg * Filenames allocated by fnalloc() and fnnalloc() are shared.
51246149Ssjg */
52246149Ssjgtypedef struct fn {
53246149Ssjg	char	*fn_name;
54246149Ssjg	size_t	fn_len;
55281812Ssjg	int	fn_id;
56246149Ssjg	struct	fn *fn_nxt;
57249033Ssjg} fn_t;
58249033Ssjg
59249033Ssjgstatic	fn_t	*fnames;
60249033Ssjg
61249033Ssjgstatic	fn_t	*srchfn __P((const char *, size_t));
62246149Ssjg
63246149Ssjg/*
64249033Ssjg * Look for a Filename of length l.
65246149Ssjg */
66246149Ssjgstatic fn_t *
67246149Ssjgsrchfn(s, len)
68246149Ssjg	const	char *s;
69246149Ssjg	size_t	len;
70246149Ssjg{
71249033Ssjg	fn_t	*fn;
72246149Ssjg
73246149Ssjg	for (fn = fnames; fn != NULL; fn = fn->fn_nxt) {
74246149Ssjg		if (fn->fn_len == len && memcmp(fn->fn_name, s, len) == 0)
75246149Ssjg			break;
76246149Ssjg	}
77249033Ssjg	return (fn);
78246149Ssjg}
79246149Ssjg
80246149Ssjg/*
81246149Ssjg * Return a shared string for filename s.
82246149Ssjg */
83246149Ssjgconst char *
84249033Ssjgfnalloc(s)
85249033Ssjg	const	char *s;
86246149Ssjg{
87246149Ssjg	return (s != NULL ? fnnalloc(s, strlen(s)) : NULL);
88246149Ssjg}
89249033Ssjg
90246149Ssjgconst char *
91246149Ssjgfnnalloc(s, len)
92246149Ssjg	const	char *s;
93246149Ssjg	size_t	len;
94246149Ssjg{
95246149Ssjg	fn_t	*fn;
96246149Ssjg
97246149Ssjg	static	int	nxt_id = 0;
98246149Ssjg
99246149Ssjg	if (s == NULL)
100249033Ssjg		return (NULL);
101246149Ssjg
102246149Ssjg	if ((fn = srchfn(s, len)) == NULL) {
103246149Ssjg		if ((fn = malloc(sizeof (fn_t))) == NULL)
104249033Ssjg			nomem();
105246149Ssjg		/* Do not used strdup() because string is not NUL-terminated.*/
106246149Ssjg		if ((fn->fn_name = malloc(len + 1)) == NULL)
107246149Ssjg			nomem();
108246149Ssjg		(void)memcpy(fn->fn_name, s, len);
109246149Ssjg		fn->fn_name[len] = '\0';
110246149Ssjg		fn->fn_len = len;
111246149Ssjg		fn->fn_id = nxt_id++;
112246149Ssjg		fn->fn_nxt = fnames;
113246149Ssjg		fnames = fn;
114249033Ssjg		/* Write id of this filename to the output file. */
115249033Ssjg		outclr();
116246149Ssjg		outint(fn->fn_id);
117246149Ssjg		outchar('s');
118246149Ssjg		outstrg(fn->fn_name);
119246149Ssjg	}
120246149Ssjg	return (fn->fn_name);
121246149Ssjg}
122281812Ssjg
123281812Ssjg/*
124281812Ssjg * Get id of a filename.
125246149Ssjg */
126249033Ssjgint
127246149Ssjggetfnid(s)
128246149Ssjg	const	char *s;
129281812Ssjg{
130246149Ssjg	fn_t	*fn;
131246149Ssjg
132246149Ssjg	if (s == NULL || (fn = srchfn(s, strlen(s))) == NULL)
133246149Ssjg		return (-1);
134246149Ssjg	return (fn->fn_id);
135246149Ssjg}
136249033Ssjg
137246149Ssjg/*
138246149Ssjg * Memory for declarations and other things which must be available
139246149Ssjg * until the end of a block (or the end of the translation unit)
140246149Ssjg * are assoziated with the level (mblklev) of the block (or wiht 0).
141246149Ssjg * Because these memory is allocated in large blocks associated with
142281812Ssjg * a given level it can be freed easily at the end of a block.
143246149Ssjg */
144246149Ssjg#define	ML_INC	((size_t)32)		/* Increment for length of *mblks */
145246149Ssjg
146246149Ssjgtypedef struct mbl {
147246149Ssjg	void	*blk;			/* beginning of memory block */
148246149Ssjg	void	*ffree;			/* first free byte */
149281812Ssjg	size_t	nfree;			/* # of free bytes */
150246149Ssjg	size_t	size;			/* total size of memory block */
151246149Ssjg	struct	mbl *nxt;		/* next block */
152246149Ssjg} mbl_t;
153246149Ssjg
154246149Ssjg/*
155246149Ssjg * Array of pointers to lists of memory blocks. mblklev is used as
156246149Ssjg * index into this array.
157246149Ssjg */
158246149Ssjgstatic	mbl_t	**mblks;
159246149Ssjg
160246149Ssjg/* number of elements in *mblks */
161246149Ssjgstatic	size_t	nmblks;
162246149Ssjg
163246149Ssjg/* free list for memory blocks */
164246149Ssjgstatic	mbl_t	*frmblks;
165246149Ssjg
166246149Ssjg/* length of new allocated memory blocks */
167246149Ssjgstatic	size_t	mblklen;
168246149Ssjg
169246149Ssjgstatic	void	*xgetblk __P((mbl_t **, size_t));
170246149Ssjgstatic	void	xfreeblk __P((mbl_t **));
171246149Ssjgstatic	mbl_t	*xnewblk __P((void));
172246149Ssjg
173246149Ssjgstatic mbl_t *
174246149Ssjgxnewblk()
175249033Ssjg{
176246149Ssjg	mbl_t	*mb;
177246149Ssjg	int	prot, flags;
178246149Ssjg
179246149Ssjg	if ((mb = malloc(sizeof (mbl_t))) == NULL)
180246149Ssjg		nomem();
181246149Ssjg
182246149Ssjg	/* use mmap instead of malloc to avoid malloc's size overhead */
183246149Ssjg
184246149Ssjg	prot = PROT_READ | PROT_WRITE;
185249033Ssjg	flags = MAP_ANON | MAP_PRIVATE;
186246149Ssjg	mb->blk = mmap(NULL, mblklen, prot, flags, -1, (off_t)0);
187246149Ssjg	if (mb->blk == (void *)MAP_FAILED)
188246149Ssjg		err(1, "can't map memory");
189246149Ssjg	if (ALIGN((u_long)mb->blk) != (u_long)mb->blk)
190246149Ssjg		errx(1, "mapped address is not aligned");
191246149Ssjg
192246149Ssjg	mb->size = mblklen;
193246149Ssjg
194246149Ssjg	return (mb);
195249033Ssjg}
196246149Ssjg
197246149Ssjg/*
198246149Ssjg * Allocate new memory. If the first block of the list has not enough
199246149Ssjg * free space, or there is no first block, get a new block. The new
200246149Ssjg * block is taken from the free list or, if there is no block on the
201246149Ssjg * free list, is allocated using xnewblk(). If a new block is allocated
202246149Ssjg * it is initialized with zero. Blocks taken from the free list are
203246149Ssjg * zero'd in xfreeblk().
204246149Ssjg */
205246149Ssjgstatic void *
206246149Ssjgxgetblk(mbp, s)
207246149Ssjg	mbl_t	**mbp;
208246149Ssjg	size_t	s;
209246149Ssjg{
210246149Ssjg	mbl_t	*mb;
211249033Ssjg	void	*p;
212249033Ssjg
213246149Ssjg	s = ALIGN(s);
214246149Ssjg	if ((mb = *mbp) == NULL || mb->nfree < s) {
215246149Ssjg		if ((mb = frmblks) == NULL) {
216246149Ssjg			mb = xnewblk();
217246149Ssjg			(void)memset(mb->blk, 0, mb->size);
218246149Ssjg		} else {
219246149Ssjg			frmblks = mb->nxt;
220246149Ssjg		}
221284254Ssjg		mb->ffree = mb->blk;
222246149Ssjg		mb->nfree = mb->size;;
223246149Ssjg		mb->nxt = *mbp;
224246149Ssjg		*mbp = mb;
225246149Ssjg	}
226246149Ssjg	p = mb->ffree;
227281812Ssjg	mb->ffree = (char *)mb->ffree + s;
228249033Ssjg	mb->nfree -= s;
229249033Ssjg	return (p);
230249033Ssjg}
231249033Ssjg
232249033Ssjg/*
233249033Ssjg * Move all blocks from list *fmbp to free list. For each block, set all
234249033Ssjg * used memory to zero.
235249033Ssjg */
236249033Ssjgstatic void
237249033Ssjgxfreeblk(fmbp)
238249033Ssjg	mbl_t	**fmbp;
239249033Ssjg{
240249033Ssjg	mbl_t	*mb;
241284254Ssjg
242249033Ssjg	while ((mb = *fmbp) != NULL) {
243284254Ssjg		*fmbp = mb->nxt;
244249033Ssjg		mb->nxt = frmblks;
245250837Ssjg		frmblks = mb;
246250837Ssjg		(void)memset(mb->blk, 0, mb->size - mb->nfree);
247250837Ssjg	}
248246149Ssjg}
249250837Ssjg
250250837Ssjgvoid
251250837Ssjginitmem()
252250837Ssjg{
253250837Ssjg	int	pgsz;
254250837Ssjg
255250837Ssjg	pgsz = getpagesize();
256250837Ssjg	mblklen = ((MBLKSIZ + pgsz - 1) / pgsz) * pgsz;
257281812Ssjg
258250837Ssjg	if ((mblks = calloc(nmblks = ML_INC, sizeof (mbl_t *))) == NULL)
259281812Ssjg		nomem();
260281812Ssjg}
261281812Ssjg
262281812Ssjg
263281812Ssjg/*
264281812Ssjg * Allocate memory associated with level l.
265281812Ssjg */
266281812Ssjgvoid *
267281812Ssjggetlblk(l, s)
268281812Ssjg	int	l;
269281812Ssjg	size_t	s;
270281812Ssjg{
271281812Ssjg	while (l >= nmblks) {
272281812Ssjg		if ((mblks = realloc(mblks, (nmblks + ML_INC) *
273281812Ssjg		    sizeof (mbl_t *))) == NULL)
274281812Ssjg			nomem();
275281812Ssjg		(void)memset(&mblks[nmblks], 0, ML_INC * sizeof (mbl_t *));
276281812Ssjg		nmblks += ML_INC;
277250837Ssjg	}
278281812Ssjg	return (xgetblk(&mblks[l], s));
279281812Ssjg}
280
281void *
282getblk(s)
283	size_t	s;
284{
285	return (getlblk(mblklev, s));
286}
287
288/*
289 * Free all memory associated with level l.
290 */
291void
292freelblk(l)
293	int	l;
294{
295	xfreeblk(&mblks[l]);
296}
297
298void
299freeblk()
300{
301	freelblk(mblklev);
302}
303
304/*
305 * tgetblk() returns memory which is associated with the current
306 * expression.
307 */
308static	mbl_t	*tmblk;
309
310void *
311tgetblk(s)
312	size_t	s;
313{
314	return (xgetblk(&tmblk, s));
315}
316
317/*
318 * Get memory for a new tree node.
319 */
320tnode_t *
321getnode()
322{
323	return (tgetblk(sizeof (tnode_t)));
324}
325
326/*
327 * Free all memory which is allocated by the the current expression.
328 */
329void
330tfreeblk()
331{
332	xfreeblk(&tmblk);
333}
334
335/*
336 * Save the memory which is used by the current expression. This memory
337 * is not freed by the next tfreeblk() call. The pointer returned can be
338 * used to restore the memory.
339 */
340mbl_t *
341tsave()
342{
343	mbl_t	*tmem;
344
345	tmem = tmblk;
346	tmblk = NULL;
347	return (tmem);
348}
349
350/*
351 * Free all memory used for the current expression and the memory used
352 * be a previous expression and saved by tsave(). The next call to
353 * tfreeblk() frees the restored memory.
354 */
355void
356trestor(tmem)
357	mbl_t	*tmem;
358{
359	tfreeblk();
360	if (tmblk != NULL) {
361		free(tmblk->blk);
362		free(tmblk);
363	}
364	tmblk = tmem;
365}
366