xref: /netbsd-src/libexec/ld.elf_so/xmalloc.c (revision f7f3399458f42b9439fea15269e7939c43135c52)
1*f7f33994Schristos /*	$NetBSD: xmalloc.c,v 1.12 2013/01/24 17:57:29 christos Exp $	*/
241fe218bScgd 
341fe218bScgd /*
441fe218bScgd  * Copyright 1996 John D. Polstra.
541fe218bScgd  * Copyright 1996 Matt Thomas <matt@3am-software.com>
641fe218bScgd  * All rights reserved.
741fe218bScgd  *
841fe218bScgd  * Redistribution and use in source and binary forms, with or without
941fe218bScgd  * modification, are permitted provided that the following conditions
1041fe218bScgd  * are met:
1141fe218bScgd  * 1. Redistributions of source code must retain the above copyright
1241fe218bScgd  *    notice, this list of conditions and the following disclaimer.
1341fe218bScgd  * 2. Redistributions in binary form must reproduce the above copyright
1441fe218bScgd  *    notice, this list of conditions and the following disclaimer in the
1541fe218bScgd  *    documentation and/or other materials provided with the distribution.
1641fe218bScgd  * 3. All advertising materials mentioning features or use of this software
1741fe218bScgd  *    must display the following acknowledgement:
1841fe218bScgd  *      This product includes software developed by John Polstra.
1941fe218bScgd  * 4. The name of the author may not be used to endorse or promote products
2041fe218bScgd  *    derived from this software without specific prior written permission.
2141fe218bScgd  *
2241fe218bScgd  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2341fe218bScgd  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2441fe218bScgd  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2541fe218bScgd  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2641fe218bScgd  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2741fe218bScgd  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2841fe218bScgd  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2941fe218bScgd  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3041fe218bScgd  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3141fe218bScgd  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3241fe218bScgd  */
3341fe218bScgd 
34bf4b000dSad /*
35bf4b000dSad  * Copyright (c) 1983 Regents of the University of California.
36bf4b000dSad  * All rights reserved.
37bf4b000dSad  *
38bf4b000dSad  * Redistribution and use in source and binary forms, with or without
39bf4b000dSad  * modification, are permitted provided that the following conditions
40bf4b000dSad  * are met:
41bf4b000dSad  * 1. Redistributions of source code must retain the above copyright
42bf4b000dSad  *    notice, this list of conditions and the following disclaimer.
43bf4b000dSad  * 2. Redistributions in binary form must reproduce the above copyright
44bf4b000dSad  *    notice, this list of conditions and the following disclaimer in the
45bf4b000dSad  *    documentation and/or other materials provided with the distribution.
46bf4b000dSad  * 3. Neither the name of the University nor the names of its contributors
47bf4b000dSad  *    may be used to endorse or promote products derived from this software
48bf4b000dSad  *    without specific prior written permission.
49bf4b000dSad  *
50bf4b000dSad  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51bf4b000dSad  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52bf4b000dSad  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53bf4b000dSad  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54bf4b000dSad  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55bf4b000dSad  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56bf4b000dSad  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57bf4b000dSad  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58bf4b000dSad  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59bf4b000dSad  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60bf4b000dSad  * SUCH DAMAGE.
61bf4b000dSad  */
62bf4b000dSad 
63bf4b000dSad #if defined(LIBC_SCCS) && !defined(lint)
64bf4b000dSad /*static char *sccsid = "from: @(#)malloc.c	5.11 (Berkeley) 2/23/91";*/
65bf4b000dSad #endif /* LIBC_SCCS and not lint */
66bf4b000dSad 
67bf4b000dSad /*
68bf4b000dSad  * malloc.c (Caltech) 2/21/82
69bf4b000dSad  * Chris Kingsley, kingsley@cit-20.
70bf4b000dSad  *
71bf4b000dSad  * This is a very fast storage allocator.  It allocates blocks of a small
72bf4b000dSad  * number of different sizes, and keeps free lists of each size.  Blocks that
73bf4b000dSad  * don't exactly fit are passed up to the next larger size.  In this
74bf4b000dSad  * implementation, the available sizes are 2^n-4 (or 2^n-10) bytes long.
75bf4b000dSad  * This is designed for use in a virtual memory environment.
76bf4b000dSad  */
77bf4b000dSad 
7826475619Schristos #include <sys/cdefs.h>
792728318eSskrll #ifndef lint
80*f7f33994Schristos __RCSID("$NetBSD: xmalloc.c,v 1.12 2013/01/24 17:57:29 christos Exp $");
812728318eSskrll #endif /* not lint */
822728318eSskrll 
8341fe218bScgd #include <stdlib.h>
8441fe218bScgd #include <string.h>
85bf4b000dSad #include <unistd.h>
86bf4b000dSad #include <errno.h>
87bf4b000dSad 
88bf4b000dSad #include <sys/types.h>
89bf4b000dSad #include <sys/param.h>
90bf4b000dSad #include <sys/mman.h>
91bf4b000dSad #include <sys/stat.h>
92bf4b000dSad 
93bf4b000dSad #include "rtld.h"
94bf4b000dSad 
95bf4b000dSad /*
96bf4b000dSad  * Pre-allocate mmap'ed pages
97bf4b000dSad  */
98bf4b000dSad #define	NPOOLPAGES	(32*1024/pagesz)
99fa64a5bfSchristos static char 		*pagepool_start, *pagepool_end;
100bf4b000dSad static int		morepages(int);
101fa64a5bfSchristos #define PAGEPOOL_SIZE	(size_t)(pagepool_end - pagepool_start)
102bf4b000dSad 
103bf4b000dSad /*
104bf4b000dSad  * The overhead on a block is at least 4 bytes.  When free, this space
105bf4b000dSad  * contains a pointer to the next free block, and the bottom two bits must
106bf4b000dSad  * be zero.  When in use, the first byte is set to MAGIC, and the second
107bf4b000dSad  * byte is the size index.  The remaining bytes are for alignment.
108bf4b000dSad  * If range checking is enabled then a second word holds the size of the
109bf4b000dSad  * requested block, less 1, rounded up to a multiple of sizeof(RMAGIC).
110bf4b000dSad  * The order of elements is critical: ov_magic must overlay the low order
111bf4b000dSad  * bits of ov_next, and ov_magic can not be a valid ov_next bit pattern.
112bf4b000dSad  */
113bf4b000dSad union	overhead {
114bf4b000dSad 	union	overhead *ov_next;	/* when free */
115bf4b000dSad 	struct {
116bf4b000dSad 		u_char	ovu_magic;	/* magic number */
117bf4b000dSad 		u_char	ovu_index;	/* bucket # */
118bf4b000dSad #ifdef RCHECK
119bf4b000dSad 		u_short	ovu_rmagic;	/* range magic number */
120bf4b000dSad 		u_int	ovu_size;	/* actual block size */
121bf4b000dSad #endif
122bf4b000dSad 	} ovu;
123bf4b000dSad #define	ov_magic	ovu.ovu_magic
124bf4b000dSad #define	ov_index	ovu.ovu_index
125bf4b000dSad #define	ov_rmagic	ovu.ovu_rmagic
126bf4b000dSad #define	ov_size		ovu.ovu_size
127bf4b000dSad };
128bf4b000dSad 
129fa64a5bfSchristos static void morecore(size_t);
130bf4b000dSad static void *imalloc(size_t);
131bf4b000dSad 
132bf4b000dSad #define	MAGIC		0xef		/* magic # on accounting info */
133bf4b000dSad #define RMAGIC		0x5555		/* magic # on range info */
134bf4b000dSad 
135bf4b000dSad #ifdef RCHECK
136bf4b000dSad #define	RSLOP		(sizeof (u_short))
137bf4b000dSad #else
138bf4b000dSad #define	RSLOP		0
139bf4b000dSad #endif
140bf4b000dSad 
141bf4b000dSad /*
142bf4b000dSad  * nextf[i] is the pointer to the next free block of size 2^(i+3).  The
143bf4b000dSad  * smallest allocatable block is 8 bytes.  The overhead information
144bf4b000dSad  * precedes the data area returned to the user.
145bf4b000dSad  */
146bf4b000dSad #define	NBUCKETS 30
147bf4b000dSad static	union overhead *nextf[NBUCKETS];
148bf4b000dSad 
149fa64a5bfSchristos static	size_t pagesz;			/* page size */
150fa64a5bfSchristos static	size_t pagebucket;		/* page size bucket */
151b9972d39Schristos static	size_t pageshift;		/* page size shift */
152bf4b000dSad 
153bf4b000dSad #ifdef MSTATS
154bf4b000dSad /*
155bf4b000dSad  * nmalloc[i] is the difference between the number of mallocs and frees
156bf4b000dSad  * for a given block size.
157bf4b000dSad  */
158bf4b000dSad static	u_int nmalloc[NBUCKETS];
159bf4b000dSad #endif
160bf4b000dSad 
161bf4b000dSad #if defined(MALLOC_DEBUG) || defined(RCHECK)
162bf4b000dSad #define	ASSERT(p)   if (!(p)) botch("p")
163bf4b000dSad static void
botch(const char * s)16491118529Sjoerg botch(const char *s)
165bf4b000dSad {
166bf4b000dSad     xwarnx("\r\nassertion botched: %s\r\n", s);
167bf4b000dSad     abort();
168bf4b000dSad }
169bf4b000dSad #else
170bf4b000dSad #define	ASSERT(p)
171bf4b000dSad #endif
172bf4b000dSad 
173bf4b000dSad #define TRACE()	xprintf("TRACE %s:%d\n", __FILE__, __LINE__)
174bf4b000dSad 
175bf4b000dSad static void *
imalloc(size_t nbytes)176bf4b000dSad imalloc(size_t nbytes)
177bf4b000dSad {
178fa64a5bfSchristos   	union overhead *op;
179fa64a5bfSchristos   	size_t bucket;
180fa64a5bfSchristos 	size_t n, m;
181fa64a5bfSchristos 	unsigned amt;
182bf4b000dSad 
183bf4b000dSad 	/*
184bf4b000dSad 	 * First time malloc is called, setup page size and
185bf4b000dSad 	 * align break pointer so all data will be page aligned.
186bf4b000dSad 	 */
187bf4b000dSad 	if (pagesz == 0) {
188bf4b000dSad 		pagesz = n = _rtld_pagesz;
189bf4b000dSad 		if (morepages(NPOOLPAGES) == 0)
190bf4b000dSad 			return NULL;
191bf4b000dSad 		op = (union overhead *)(pagepool_start);
192fa64a5bfSchristos 		m = sizeof (*op) - (((char *)op - (char *)NULL) & (n - 1));
193fa64a5bfSchristos 		if (n < m)
194fa64a5bfSchristos 			n += pagesz - m;
195fa64a5bfSchristos 		else
196fa64a5bfSchristos 			n -= m;
197bf4b000dSad   		if (n) {
198bf4b000dSad 			pagepool_start += n;
199bf4b000dSad 		}
200bf4b000dSad 		bucket = 0;
201bf4b000dSad 		amt = sizeof(union overhead);
202bf4b000dSad 		while (pagesz > amt) {
203bf4b000dSad 			amt <<= 1;
204bf4b000dSad 			bucket++;
205bf4b000dSad 		}
206bf4b000dSad 		pagebucket = bucket;
207b9972d39Schristos 		pageshift = ffs(pagesz) - 1;
208bf4b000dSad 	}
209bf4b000dSad 	/*
210bf4b000dSad 	 * Convert amount of memory requested into closest block size
211bf4b000dSad 	 * stored in hash buckets which satisfies request.
212bf4b000dSad 	 * Account for space used per block for accounting.
213bf4b000dSad 	 */
214bf4b000dSad 	if (nbytes <= (n = pagesz - sizeof (*op) - RSLOP)) {
215bf4b000dSad 		if (sizeof(union overhead) & (sizeof(union overhead) - 1)) {
216bf4b000dSad 		    amt = sizeof(union overhead) * 2;
217bf4b000dSad 		    bucket = 1;
218bf4b000dSad 		} else {
219bf4b000dSad 		    amt = sizeof(union overhead); /* size of first bucket */
220bf4b000dSad 		    bucket = 0;
221bf4b000dSad 		}
222bf4b000dSad 		n = -(sizeof (*op) + RSLOP);
223bf4b000dSad 	} else {
224bf4b000dSad 		amt = pagesz;
225bf4b000dSad 		bucket = pagebucket;
226bf4b000dSad 	}
227bf4b000dSad 	while (nbytes > amt + n) {
228bf4b000dSad 		amt <<= 1;
229bf4b000dSad 		if (amt == 0)
230bf4b000dSad 			return (NULL);
231bf4b000dSad 		bucket++;
232bf4b000dSad 	}
233bf4b000dSad 	/*
234bf4b000dSad 	 * If nothing in hash bucket right now,
235bf4b000dSad 	 * request more memory from the system.
236bf4b000dSad 	 */
237bf4b000dSad   	if ((op = nextf[bucket]) == NULL) {
238bf4b000dSad   		morecore(bucket);
239bf4b000dSad   		if ((op = nextf[bucket]) == NULL)
240bf4b000dSad   			return (NULL);
241bf4b000dSad 	}
242bf4b000dSad 	/* remove from linked list */
243bf4b000dSad   	nextf[bucket] = op->ov_next;
244bf4b000dSad 	op->ov_magic = MAGIC;
245bf4b000dSad 	op->ov_index = bucket;
246bf4b000dSad #ifdef MSTATS
247bf4b000dSad   	nmalloc[bucket]++;
248bf4b000dSad #endif
249bf4b000dSad #ifdef RCHECK
250bf4b000dSad 	/*
251bf4b000dSad 	 * Record allocated size of block and
252bf4b000dSad 	 * bound space with magic numbers.
253bf4b000dSad 	 */
254bf4b000dSad 	op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
255bf4b000dSad 	op->ov_rmagic = RMAGIC;
256bf4b000dSad   	*(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
257bf4b000dSad #endif
258bf4b000dSad   	return ((char *)(op + 1));
259bf4b000dSad }
260bf4b000dSad 
261bf4b000dSad /*
262bf4b000dSad  * Allocate more memory to the indicated bucket.
263bf4b000dSad  */
264bf4b000dSad static void
morecore(size_t bucket)265fa64a5bfSchristos morecore(size_t bucket)
266bf4b000dSad {
267fa64a5bfSchristos   	union overhead *op;
268fa64a5bfSchristos 	size_t sz;		/* size of desired block */
269fa64a5bfSchristos   	size_t amt;		/* amount to allocate */
270fa64a5bfSchristos   	size_t nblks;		/* how many blocks we get */
271bf4b000dSad 
272bf4b000dSad 	/*
273bf4b000dSad 	 * sbrk_size <= 0 only for big, FLUFFY, requests (about
274bf4b000dSad 	 * 2^30 bytes on a VAX, I think) or for a negative arg.
275bf4b000dSad 	 */
276bf4b000dSad 	sz = 1 << (bucket + 3);
277bf4b000dSad #ifdef MALLOC_DEBUG
278bf4b000dSad 	ASSERT(sz > 0);
279bf4b000dSad #endif
280bf4b000dSad 	if (sz < pagesz) {
281bf4b000dSad 		amt = pagesz;
282b9972d39Schristos 		nblks = amt >> (bucket + 3);
283bf4b000dSad 	} else {
284bf4b000dSad 		amt = sz + pagesz;
285bf4b000dSad 		nblks = 1;
286bf4b000dSad 	}
287fa64a5bfSchristos 	if (amt > PAGEPOOL_SIZE)
288b9972d39Schristos 		if (morepages((amt >> pageshift) + NPOOLPAGES) == 0)
289bf4b000dSad 			return;
290bf4b000dSad 	op = (union overhead *)pagepool_start;
291bf4b000dSad 	pagepool_start += amt;
292bf4b000dSad 
293bf4b000dSad 	/*
294bf4b000dSad 	 * Add new memory allocated to that on
295bf4b000dSad 	 * free list for this hash bucket.
296bf4b000dSad 	 */
297bf4b000dSad   	nextf[bucket] = op;
298bf4b000dSad   	while (--nblks > 0) {
299bf4b000dSad 		op->ov_next = (union overhead *)((caddr_t)op + sz);
300bf4b000dSad 		op = (union overhead *)((caddr_t)op + sz);
301bf4b000dSad   	}
302bf4b000dSad }
303bf4b000dSad 
304bf4b000dSad void
xfree(void * cp)30591118529Sjoerg xfree(void *cp)
306bf4b000dSad {
307fa64a5bfSchristos   	int size;
308fa64a5bfSchristos 	union overhead *op;
309bf4b000dSad 
310bf4b000dSad   	if (cp == NULL)
311bf4b000dSad   		return;
312bf4b000dSad 	op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
313bf4b000dSad #ifdef MALLOC_DEBUG
314bf4b000dSad   	ASSERT(op->ov_magic == MAGIC);		/* make sure it was in use */
315bf4b000dSad #else
316bf4b000dSad 	if (op->ov_magic != MAGIC)
317bf4b000dSad 		return;				/* sanity */
318bf4b000dSad #endif
319bf4b000dSad #ifdef RCHECK
320bf4b000dSad   	ASSERT(op->ov_rmagic == RMAGIC);
321bf4b000dSad 	ASSERT(*(u_short *)((caddr_t)(op + 1) + op->ov_size) == RMAGIC);
322bf4b000dSad #endif
323bf4b000dSad   	size = op->ov_index;
324bf4b000dSad   	ASSERT(size < NBUCKETS);
325bf4b000dSad 	op->ov_next = nextf[size];	/* also clobbers ov_magic */
326bf4b000dSad   	nextf[size] = op;
327bf4b000dSad #ifdef MSTATS
328bf4b000dSad   	nmalloc[size]--;
329bf4b000dSad #endif
330bf4b000dSad }
331bf4b000dSad 
332bf4b000dSad static void *
irealloc(void * cp,size_t nbytes)333bf4b000dSad irealloc(void *cp, size_t nbytes)
334bf4b000dSad {
335fa64a5bfSchristos   	size_t onb;
336fa64a5bfSchristos 	size_t i;
337bf4b000dSad 	union overhead *op;
338bf4b000dSad   	char *res;
339bf4b000dSad 
340bf4b000dSad   	if (cp == NULL)
341bf4b000dSad   		return (imalloc(nbytes));
342bf4b000dSad 	op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
343bf4b000dSad 	if (op->ov_magic != MAGIC) {
344bf4b000dSad 		static const char *err_str =
345bf4b000dSad 		    "memory corruption or double free in realloc\n";
3469795e155Sad 		extern char *__progname;
347bf4b000dSad 	        write(STDERR_FILENO, __progname, strlen(__progname));
348bf4b000dSad 		write(STDERR_FILENO, err_str, strlen(err_str));
349bf4b000dSad 		abort();
350bf4b000dSad 	}
351bf4b000dSad 
352bf4b000dSad 	i = op->ov_index;
353bf4b000dSad 	onb = 1 << (i + 3);
354bf4b000dSad 	if (onb < pagesz)
355bf4b000dSad 		onb -= sizeof (*op) + RSLOP;
356bf4b000dSad 	else
357bf4b000dSad 		onb += pagesz - sizeof (*op) - RSLOP;
358bf4b000dSad 	/* avoid the copy if same size block */
359bf4b000dSad 	if (i) {
360bf4b000dSad 		i = 1 << (i + 2);
361bf4b000dSad 		if (i < pagesz)
362bf4b000dSad 			i -= sizeof (*op) + RSLOP;
363bf4b000dSad 		else
364bf4b000dSad 			i += pagesz - sizeof (*op) - RSLOP;
365bf4b000dSad 	}
366bf4b000dSad 	if (nbytes <= onb && nbytes > i) {
367bf4b000dSad #ifdef RCHECK
368bf4b000dSad 		op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
369bf4b000dSad 		*(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
370bf4b000dSad #endif
371bf4b000dSad 		return(cp);
372*f7f33994Schristos 	}
373bf4b000dSad   	if ((res = imalloc(nbytes)) == NULL)
374bf4b000dSad   		return (NULL);
375*f7f33994Schristos   	if (cp != res) {	/* common optimization if "compacting" */
376bf4b000dSad 		memcpy(res, cp, (nbytes < onb) ? nbytes : onb);
377*f7f33994Schristos 		xfree(cp);
378*f7f33994Schristos 	}
379bf4b000dSad   	return (res);
380bf4b000dSad }
381bf4b000dSad 
382bf4b000dSad #ifdef MSTATS
383bf4b000dSad /*
384bf4b000dSad  * mstats - print out statistics about malloc
385bf4b000dSad  *
386bf4b000dSad  * Prints two lines of numbers, one showing the length of the free list
387bf4b000dSad  * for each size category, the second showing the number of mallocs -
388bf4b000dSad  * frees for each size category.
389bf4b000dSad  */
39091118529Sjoerg void
mstats(char * s)391bf4b000dSad mstats(char *s)
392bf4b000dSad {
393fa64a5bfSchristos   	int i, j;
394fa64a5bfSchristos   	union overhead *p;
395bf4b000dSad   	int totfree = 0,
396bf4b000dSad   	totused = 0;
397bf4b000dSad 
398bf4b000dSad   	xprintf("Memory allocation statistics %s\nfree:\t", s);
399bf4b000dSad   	for (i = 0; i < NBUCKETS; i++) {
400bf4b000dSad   		for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
401bf4b000dSad   			;
402bf4b000dSad   		xprintf(" %d", j);
403bf4b000dSad   		totfree += j * (1 << (i + 3));
404bf4b000dSad   	}
405bf4b000dSad   	xprintf("\nused:\t");
406bf4b000dSad   	for (i = 0; i < NBUCKETS; i++) {
407bf4b000dSad   		xprintf(" %d", nmalloc[i]);
408bf4b000dSad   		totused += nmalloc[i] * (1 << (i + 3));
409bf4b000dSad   	}
410bf4b000dSad   	xprintf("\n\tTotal in use: %d, total free: %d\n",
411bf4b000dSad 	    totused, totfree);
412bf4b000dSad }
413bf4b000dSad #endif
414bf4b000dSad 
415bf4b000dSad 
416bf4b000dSad static int
morepages(int n)417bf4b000dSad morepages(int n)
418bf4b000dSad {
419bf4b000dSad 	int	fd = -1;
420bf4b000dSad 	int	offset;
421bf4b000dSad 
422bf4b000dSad #ifdef NEED_DEV_ZERO
423bf4b000dSad 	fd = open("/dev/zero", O_RDWR, 0);
424bf4b000dSad 	if (fd == -1)
425bf4b000dSad 		xerr(1, "/dev/zero");
426bf4b000dSad #endif
427bf4b000dSad 
428fa64a5bfSchristos 	if (PAGEPOOL_SIZE > pagesz) {
429bf4b000dSad 		caddr_t	addr = (caddr_t)
430bf4b000dSad 			(((long)pagepool_start + pagesz - 1) & ~(pagesz - 1));
431bf4b000dSad 		if (munmap(addr, pagepool_end - addr) != 0)
432bf4b000dSad 			xwarn("morepages: munmap %p", addr);
433bf4b000dSad 	}
434bf4b000dSad 
435bf4b000dSad 	offset = (long)pagepool_start - ((long)pagepool_start & ~(pagesz - 1));
436bf4b000dSad 
437bf4b000dSad 	if ((pagepool_start = mmap(0, n * pagesz,
438bf4b000dSad 			PROT_READ|PROT_WRITE,
439bf4b000dSad 			MAP_ANON|MAP_PRIVATE, fd, 0)) == (caddr_t)-1) {
440bf4b000dSad 		xprintf("Cannot map anonymous memory");
441bf4b000dSad 		return 0;
442bf4b000dSad 	}
443bf4b000dSad 	pagepool_end = pagepool_start + n * pagesz;
444bf4b000dSad 	pagepool_start += offset;
445bf4b000dSad 
446bf4b000dSad #ifdef NEED_DEV_ZERO
447bf4b000dSad 	close(fd);
448bf4b000dSad #endif
449bf4b000dSad 	return n;
450bf4b000dSad }
45141fe218bScgd 
45241fe218bScgd void *
xcalloc(size_t size)4535f573ab6Sskrll xcalloc(size_t size)
45441fe218bScgd {
455a9f5b3f8Ssimonb 
45641fe218bScgd 	return memset(xmalloc(size), 0, size);
45741fe218bScgd }
45841fe218bScgd 
45941fe218bScgd void *
xmalloc(size_t size)4605f573ab6Sskrll xmalloc(size_t size)
46141fe218bScgd {
462bf4b000dSad 	void *p = imalloc(size);
463a9f5b3f8Ssimonb 
46441fe218bScgd 	if (p == NULL)
46526475619Schristos 		xerr(1, "%s", xstrerror(errno));
46641fe218bScgd 	return p;
46741fe218bScgd }
46841fe218bScgd 
469596c6ec5Schristos void *
xrealloc(void * p,size_t size)470596c6ec5Schristos xrealloc(void *p, size_t size)
471596c6ec5Schristos {
472bf4b000dSad 	p = irealloc(p, size);
473596c6ec5Schristos 
474596c6ec5Schristos 	if (p == NULL)
475596c6ec5Schristos 		xerr(1, "%s", xstrerror(errno));
476596c6ec5Schristos 	return p;
477596c6ec5Schristos }
478596c6ec5Schristos 
47941fe218bScgd char *
xstrdup(const char * str)480bf4b000dSad xstrdup(const char *str)
48141fe218bScgd {
482bf4b000dSad 	size_t len;
483bf4b000dSad 	char *copy;
484a9f5b3f8Ssimonb 
485bf4b000dSad 	len = strlen(str) + 1;
486bf4b000dSad 	copy = xmalloc(len);
487bf4b000dSad 	memcpy(copy, str, len);
488bf4b000dSad 	return (copy);
48941fe218bScgd }
490