mem1.c revision 12100
1/*	$NetBSD: mem1.c,v 1.2 1995/07/03 21:24:25 cgd 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#ifndef lint
35static char rcsid[] = "$NetBSD: mem1.c,v 1.2 1995/07/03 21:24:25 cgd Exp $";
36#endif
37
38#include <sys/types.h>
39#include <sys/mman.h>
40#include <sys/param.h>
41#include <stdlib.h>
42#include <string.h>
43#include <unistd.h>
44#include <err.h>
45
46#include "lint1.h"
47
48/*
49 * Filenames allocated by fnalloc() and fnnalloc() are shared.
50 */
51typedef struct fn {
52	char	*fn_name;
53	size_t	fn_len;
54	int	fn_id;
55	struct	fn *fn_nxt;
56} fn_t;
57
58static	fn_t	*fnames;
59
60static	fn_t	*srchfn __P((const char *, size_t));
61
62/*
63 * Look for a Filename of length l.
64 */
65static fn_t *
66srchfn(s, len)
67	const	char *s;
68	size_t	len;
69{
70	fn_t	*fn;
71
72	for (fn = fnames; fn != NULL; fn = fn->fn_nxt) {
73		if (fn->fn_len == len && memcmp(fn->fn_name, s, len) == 0)
74			break;
75	}
76	return (fn);
77}
78
79/*
80 * Return a shared string for filename s.
81 */
82const char *
83fnalloc(s)
84	const	char *s;
85{
86	return (s != NULL ? fnnalloc(s, strlen(s)) : NULL);
87}
88
89const char *
90fnnalloc(s, len)
91	const	char *s;
92	size_t	len;
93{
94	fn_t	*fn;
95
96	static	int	nxt_id = 0;
97
98	if (s == NULL)
99		return (NULL);
100
101	if ((fn = srchfn(s, len)) == NULL) {
102		fn = xmalloc(sizeof (fn_t));
103		/* Do not used strdup() because string is not NUL-terminated.*/
104		fn->fn_name = xmalloc(len + 1);
105		(void)memcpy(fn->fn_name, s, len);
106		fn->fn_name[len] = '\0';
107		fn->fn_len = len;
108		fn->fn_id = nxt_id++;
109		fn->fn_nxt = fnames;
110		fnames = fn;
111		/* Write id of this filename to the output file. */
112		outclr();
113		outint(fn->fn_id);
114		outchar('s');
115		outstrg(fn->fn_name);
116	}
117	return (fn->fn_name);
118}
119
120/*
121 * Get id of a filename.
122 */
123int
124getfnid(s)
125	const	char *s;
126{
127	fn_t	*fn;
128
129	if (s == NULL || (fn = srchfn(s, strlen(s))) == NULL)
130		return (-1);
131	return (fn->fn_id);
132}
133
134/*
135 * Memory for declarations and other things which must be available
136 * until the end of a block (or the end of the translation unit)
137 * are assoziated with the level (mblklev) of the block (or wiht 0).
138 * Because these memory is allocated in large blocks associated with
139 * a given level it can be freed easily at the end of a block.
140 */
141#define	ML_INC	((size_t)32)		/* Increment for length of *mblks */
142
143typedef struct mbl {
144	void	*blk;			/* beginning of memory block */
145	void	*ffree;			/* first free byte */
146	size_t	nfree;			/* # of free bytes */
147	size_t	size;			/* total size of memory block */
148	struct	mbl *nxt;		/* next block */
149} mbl_t;
150
151/*
152 * Array of pointers to lists of memory blocks. mblklev is used as
153 * index into this array.
154 */
155static	mbl_t	**mblks;
156
157/* number of elements in *mblks */
158static	size_t	nmblks;
159
160/* free list for memory blocks */
161static	mbl_t	*frmblks;
162
163/* length of new allocated memory blocks */
164static	size_t	mblklen;
165
166static	void	*xgetblk __P((mbl_t **, size_t));
167static	void	xfreeblk __P((mbl_t **));
168static	mbl_t	*xnewblk __P((void));
169
170static mbl_t *
171xnewblk()
172{
173	mbl_t	*mb;
174	int	prot, flags;
175
176	mb = xmalloc(sizeof (mbl_t));
177
178	/* use mmap instead of malloc to avoid malloc's size overhead */
179
180	prot = PROT_READ | PROT_WRITE;
181	flags = MAP_ANON | MAP_PRIVATE;
182	mb->blk = mmap(NULL, mblklen, prot, flags, -1, (off_t)0);
183	if (mb->blk == (void *)-1)
184		err(1, "can't map memory");
185	if (ALIGN((u_long)mb->blk) != (u_long)mb->blk)
186		errx(1, "mapped address is not aligned");
187
188	mb->size = mblklen;
189
190	return (mb);
191}
192
193/*
194 * Allocate new memory. If the first block of the list has not enough
195 * free space, or there is no first block, get a new block. The new
196 * block is taken from the free list or, if there is no block on the
197 * free list, is allocated using xnewblk(). If a new block is allocated
198 * it is initialized with zero. Blocks taken from the free list are
199 * zero'd in xfreeblk().
200 */
201static void *
202xgetblk(mbp, s)
203	mbl_t	**mbp;
204	size_t	s;
205{
206	mbl_t	*mb;
207	void	*p;
208
209	s = ALIGN(s);
210	if ((mb = *mbp) == NULL || mb->nfree < s) {
211		if ((mb = frmblks) == NULL) {
212			mb = xnewblk();
213			(void)memset(mb->blk, 0, mb->size);
214		} else {
215			frmblks = mb->nxt;
216		}
217		mb->ffree = mb->blk;
218		mb->nfree = mb->size;;
219		mb->nxt = *mbp;
220		*mbp = mb;
221	}
222	p = mb->ffree;
223	mb->ffree = (char *)mb->ffree + s;
224	mb->nfree -= s;
225	return (p);
226}
227
228/*
229 * Move all blocks from list *fmbp to free list. For each block, set all
230 * used memory to zero.
231 */
232static void
233xfreeblk(fmbp)
234	mbl_t	**fmbp;
235{
236	mbl_t	*mb;
237
238	while ((mb = *fmbp) != NULL) {
239		*fmbp = mb->nxt;
240		mb->nxt = frmblks;
241		frmblks = mb;
242		(void)memset(mb->blk, 0, mb->size - mb->nfree);
243	}
244}
245
246void
247initmem()
248{
249	int	pgsz;
250
251	pgsz = getpagesize();
252	mblklen = ((MBLKSIZ + pgsz - 1) / pgsz) * pgsz;
253
254	mblks = xcalloc(nmblks = ML_INC, sizeof (mbl_t *));
255}
256
257
258/*
259 * Allocate memory associated with level l.
260 */
261void *
262getlblk(l, s)
263	int	l;
264	size_t	s;
265{
266	while (l >= nmblks) {
267		mblks = xrealloc(mblks, (nmblks + ML_INC) * sizeof (mbl_t *));
268		(void)memset(&mblks[nmblks], 0, ML_INC * sizeof (mbl_t *));
269		nmblks += ML_INC;
270	}
271	return (xgetblk(&mblks[l], s));
272}
273
274void *
275getblk(s)
276	size_t	s;
277{
278	return (getlblk(mblklev, s));
279}
280
281/*
282 * Free all memory associated with level l.
283 */
284void
285freelblk(l)
286	int	l;
287{
288	xfreeblk(&mblks[l]);
289}
290
291void
292freeblk()
293{
294	freelblk(mblklev);
295}
296
297/*
298 * tgetblk() returns memory which is associated with the current
299 * expression.
300 */
301static	mbl_t	*tmblk;
302
303void *
304tgetblk(s)
305	size_t	s;
306{
307	return (xgetblk(&tmblk, s));
308}
309
310/*
311 * Get memory for a new tree node.
312 */
313tnode_t *
314getnode()
315{
316	return (tgetblk(sizeof (tnode_t)));
317}
318
319/*
320 * Free all memory which is allocated by the the current expression.
321 */
322void
323tfreeblk()
324{
325	xfreeblk(&tmblk);
326}
327
328/*
329 * Save the memory which is used by the current expression. This memory
330 * is not freed by the next tfreeblk() call. The pointer returned can be
331 * used to restore the memory.
332 */
333mbl_t *
334tsave()
335{
336	mbl_t	*tmem;
337
338	tmem = tmblk;
339	tmblk = NULL;
340	return (tmem);
341}
342
343/*
344 * Free all memory used for the current expression and the memory used
345 * be a previous expression and saved by tsave(). The next call to
346 * tfreeblk() frees the restored memory.
347 */
348void
349trestor(tmem)
350	mbl_t	*tmem;
351{
352	tfreeblk();
353	if (tmblk != NULL) {
354		free(tmblk->blk);
355		free(tmblk);
356	}
357	tmblk = tmem;
358}
359