1 /*
2 Copyright (C) 1995 Pascal Haible.  All Rights Reserved.
3 
4 Permission is hereby granted, free of charge, to any person obtaining a
5 copy of this software and associated documentation files (the "Software"),
6 to deal in the Software without restriction, including without limitation
7 the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 and/or sell copies of the Software, and to permit persons to whom the
9 Software is furnished to do so, subject to the following conditions:
10 
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 PASCAL HAIBLE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19 OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 SOFTWARE.
21 
22 Except as contained in this notice, the name of Pascal Haible shall
23 not be used in advertising or otherwise to promote the sale, use or other
24 dealings in this Software without prior written authorization from
25 Pascal Haible.
26 */
27 
28 /* $XFree86: xc/programs/Xserver/os/xalloc.c,v 3.12.2.1 1997/05/10 07:03:02 hohndel Exp $ */
29 
30 /* Only used if INTERNAL_MALLOC is defined
31  * - otherwise xalloc() in utils.c is used
32  */
33 #ifdef INTERNAL_MALLOC
34 
35 #if defined(__STDC__) || defined(AMOEBA)
36 #ifndef NOSTDHDRS
37 #include <stdlib.h>	/* for malloc() etc. */
38 #endif
39 #else
40 extern char *malloc();
41 extern char *calloc();
42 extern char *realloc();
43 #endif
44 
45 #include "Xos.h"
46 #include "misc.h"
47 #include "X.h"
48 
49 #ifdef XALLOC_LOG
50 #include <stdio.h>
51 #endif
52 
53 extern Bool Must_have_memory;
54 
55 /*
56  ***** New malloc approach for the X server *****
57  * Pascal Haible 1995
58  *
59  * Some statistics about memory allocation of the X server
60  * The test session included several clients of different size, including
61  * xv, emacs and xpaint with a new canvas of 3000x2000, zoom 5.
62  * All clients were running together.
63  * A protocolling version of Xalloc recorded 318917 allocating actions
64  * (191573 Xalloc, 85942 XNFalloc, 41438 Xrealloc, 279727 Xfree).
65  * Results grouped by size, excluding the next lower size
66  * (i.e. size=32 means 16<size<=32):
67  *
68  *    size   nr of alloc   max nr of blocks allocated together
69  *       8	1114		287
70  *      16	17341		4104
71  *      32	147352		2068
72  *      64	59053		2518
73  *     128	46882		1230
74  *     256	20544		1217
75  *     512	6808		117
76  *    1024	8254		171
77  *    2048	4841		287
78  *    4096	2429		84
79  *    8192	3364		85
80  *   16384	573		22
81  *   32768	49		7
82  *   65536	45		5
83  *  131072	48		2
84  *  262144	209		2
85  *  524288	7		4
86  * 1048576	2		1
87  * 8388608	2		2
88  *
89  * The most used sizes:
90  * count size
91  * 24	136267
92  * 40	37055
93  * 72	17278
94  * 56	13504
95  * 80	9372
96  * 16	8966
97  * 32	8411
98  * 136	8399
99  * 104	7690
100  * 12	7630
101  * 120	5512
102  * 88	4634
103  * 152	3062
104  * 52	2881
105  * 48	2736
106  * 156	1569
107  * 168	1487
108  * 160	1483
109  * 28	1446
110  * 1608	1379
111  * 184	1305
112  * 552	1270
113  * 64	934
114  * 320	891
115  * 8	754
116  *
117  * Conclusions: more than the half of all allocations are <= 32 bytes.
118  * But of these about 150,000 blocks, only a maximum of about 6,000 are
119  * allocated together (including memory leaks..).
120  * On the other side, only 935 of the 191573 or 0.5% were larger than 8kB
121  * (362 or 0.2% larger than 16k).
122  *
123  * What makes the server really grow is the fragmentation of the heap,
124  * and the fact that it can't shrink.
125  * To cure this, we do the following:
126  * - large blocks (>=11k) are mmapped on xalloc, and unmapped on xfree,
127  *   so we don't need any free lists etc.
128  *   As this needs 2 system calls, we only do this for the quite
129  *   infrequent large (>=11k) blocks.
130  * - instead of reinventing the wheel, we use system malloc for medium
131  *   sized blocks (>256, <11k).
132  * - for small blocks (<=256) we use an other approach:
133  *   As we need many small blocks, and most ones for a short time,
134  *   we don't go through the system malloc:
135  *   for each fixed sizes a seperate list of free blocks is kept.
136  *   to KISS (Keep it Small and Simple), we don't free them
137  *   (not freeing a block of 32 bytes won't be worse than having fragmented
138  *   a larger area on allocation).
139  *   This way, we (almost) allways have a fitting free block right at hand,
140  *   and don't have to walk any lists.
141  */
142 
143 /*
144  * structure layout of a allocated block
145  * unsigned long	size:
146  *				rounded up netto size for small and medium blocks
147  *				brutto size == mmap'ed area for large blocks
148  * unsigned long	DEBUG ? MAGIC : unused
149  * ....			data
150  * ( unsigned long	MAGIC2 ) only if SIZE_TAIL defined
151  *
152  */
153 
154 /* use otherwise unused long in the header to store a magic */
155 /* shouldn't this be removed for production release ? */
156 #define XALLOC_DEBUG
157 
158 #ifdef XALLOC_DEBUG
159 /* Xfree fills the memory with a certain pattern (currently 0xF0) */
160 /* this should really be removed for production release! */
161 #define XFREE_ERASES
162 #endif
163 
164 /* this must be a multiple of SIZE_STEPS below */
165 #define MAX_SMALL 264		/* quite many blocks of 264 */
166 
167 #define MIN_LARGE (11*1024)
168 /* worst case is 25% loss with a page size of 4k */
169 
170 /* SIZE_STEPS defines the granularity of size of small blocks -
171  * this makes blocks align to that, too! */
172 #define SIZE_STEPS		(sizeof(double))
173 #define SIZE_HEADER		(2*sizeof(long)) /* = sizeof(double) for 32bit */
174 #ifdef XALLOC_DEBUG
175 #if defined(__sparc__) || defined(__hppa__)
176 #define SIZE_TAIL		(2*sizeof(long)) /* = sizeof(double) for 32bit */
177 #else
178 #define SIZE_TAIL		(sizeof(long))
179 #endif
180 #endif
181 
182 #undef TAIL_SIZE
183 #ifdef SIZE_TAIL
184 #define TAIL_SIZE		SIZE_TAIL
185 #else
186 #define TAIL_SIZE		0
187 #endif
188 
189 #ifdef __alpha__
190 #define MAGIC			0x1404196414071968
191 #define MAGIC2			0x2515207525182079
192 #else
193 #define MAGIC			0x14071968
194 #define MAGIC2			0x25182079
195 #endif
196 
197 /* To get some statistics about memory allocation */
198 
199 #ifdef XALLOC_LOG
200 #define XALLOC_LOG_FILE "/tmp/Xalloc.log"	/* unsecure... */
201 #define LOG_BODY(_body)					\
202 		{ FILE *f;				\
203 		  f = fopen(XALLOC_LOG_FILE, "a");	\
204 		  if (NULL!=f) {			\
205 			_body;				\
206 			fclose(f);			\
207 		  }					\
208 		}
209 #if defined(linux) && defined(i386)
210 #define LOG_ALLOC(_fun, _size, _ret)						\
211 	{	unsigned long *from;						\
212 		__asm__("movl %%ebp,%0" : /*OUT*/ "=r" (from) : /*IN*/ );	\
213 		LOG_BODY(fprintf(f, "%s\t%i\t%p\t[%lu]\n", _fun, _size, _ret, *(from+1))) \
214 	}
215 #else
216 #define LOG_ALLOC(_fun, _size, _ret)				\
217 	LOG_BODY(fprintf(f, "%s\t%i\t%p\n", _fun, _size, _ret))
218 #endif
219 #define LOG_REALLOC(_fun, _ptr, _size, _ret)			\
220 	LOG_BODY(fprintf(f, "%s\t%p\t%i\t%p\n", _fun, _ptr, _size, _ret))
221 #define LOG_FREE(_fun, _ptr)					\
222 	LOG_BODY(fprintf(f, "%s\t%p\n", _fun, _ptr))
223 #else
224 #define LOG_ALLOC(_fun, _size, _ret)
225 #define LOG_REALLOC(_fun, _ptr, _size, _ret)
226 #define LOG_FREE(_fun, _ptr)
227 #endif /* XALLOC_LOG */
228 
229 static unsigned long *free_lists[MAX_SMALL/SIZE_STEPS];
230 
231 /*
232  * systems that support it should define HAS_MMAP_ANON or MMAP_DEV_ZERO
233  * and include the appropriate header files for
234  * mmap(), munmap(), PROT_READ, PROT_WRITE, MAP_PRIVATE,
235  * PAGE_SIZE or _SC_PAGESIZE (and MAP_ANON for HAS_MMAP_ANON).
236  *
237  * systems that don't support MAP_ANON fall through to the 2 fold behaviour
238  */
239 
240 #if defined(linux)
241 #define HAS_MMAP_ANON
242 #include <sys/types.h>
243 #include <sys/mman.h>
244 #include <asm/page.h>	/* PAGE_SIZE */
245 #endif /* linux */
246 
247 #if defined(CSRG_BASED)
248 #define HAS_MMAP_ANON
249 #define HAS_GETPAGESIZE
250 #include <sys/types.h>
251 #include <sys/mman.h>
252 #endif /* CSRG_BASED */
253 
254 #if defined(SVR4)
255 #define MMAP_DEV_ZERO
256 #include <sys/types.h>
257 #include <sys/mman.h>
258 #include <unistd.h>
259 #endif /* SVR4 */
260 
261 #if defined(sun) && !defined(SVR4) /* SunOS */
262 #define MMAP_DEV_ZERO	/* doesn't SunOS have MAP_ANON ?? */
263 #define HAS_GETPAGESIZE
264 #include <sys/types.h>
265 #include <sys/mman.h>
266 #endif /* sun && !SVR4 */
267 
268 #ifdef XNO_SYSCONF
269 #undef _SC_PAGESIZE
270 #endif
271 
272 #if defined(HAS_MMAP_ANON) || defined (MMAP_DEV_ZERO)
273 static int pagesize;
274 #endif
275 
276 #ifdef MMAP_DEV_ZERO
277 static int devzerofd = -1;
278 #include <errno.h>
279 #ifdef X_NOT_STDC_ENV
280 extern int errno;
281 #endif
282 #endif
283 
284 
285 unsigned long *
Xalloc(amount)286 Xalloc (amount)
287     unsigned long amount;
288 {
289     register unsigned long *ptr;
290     int indx;
291 
292     /* sanity checks */
293 
294     /* zero size requested */
295     if (amount == 0) {
296 	LOG_ALLOC("Xalloc=0", amount, 0);
297 	return (unsigned long *)NULL;
298     }
299     /* negative size (or size > 2GB) - what do we do? */
300     if ((long)amount < 0) {
301 	/* Diagnostic */
302 #ifdef FATALERRORS
303  	FatalError("Xalloc: Xalloc(<0)\n");
304 #else
305  	ErrorF("Xalloc warning: Xalloc(<0) ignored..\n");
306 #endif
307  	LOG_ALLOC("Xalloc<0", amount, 0);
308 	return (unsigned long *)NULL;
309     }
310 
311     /* alignment check */
312 #if defined(__alpha__) || defined(__sparc__) || defined(__mips__) || defined(__hppa__)
313     amount = (amount + (sizeof(long)-1)) & ~(sizeof(long)-1);
314 #endif
315 
316     if (amount <= MAX_SMALL) {
317 	/*
318 	 * small block
319 	 */
320 	/* pick a ready to use small chunk */
321 	indx = (amount-1) / SIZE_STEPS;
322 	ptr = free_lists[indx];
323 	if (NULL == ptr) {
324 		/* list empty - get 20 or 40 more */
325 		/* amount = size rounded up */
326 		amount = (indx+1) * SIZE_STEPS;
327 		ptr = (unsigned long *)calloc(1,(amount+SIZE_HEADER+TAIL_SIZE)
328 						* (amount<100 ? 40 : 20));
329 		if (NULL!=ptr) {
330 			int i;
331 			unsigned long *p1, *p2;
332 			p2 = (unsigned long *)((char *)ptr + SIZE_HEADER);
333 			for (i=0; i<(amount<100 ? 40 : 20); i++) {
334 				p1 = p2;
335 				p1[-2] = amount;
336 #ifdef XALLOC_DEBUG
337 				p1[-1] = MAGIC;
338 #endif /* XALLOC_DEBUG */
339 #ifdef SIZE_TAIL
340 				*(unsigned long *)((unsigned char *)p1 + amount) = MAGIC2;
341 #endif /* SIZE_TAIL */
342 				p2 = (unsigned long *)((char *)p1 + SIZE_HEADER + amount + TAIL_SIZE);
343 				*(unsigned long **)p1 = p2;
344 			}
345 			/* last one has no next one */
346 			*(unsigned long **)p1 = NULL;
347 			/* put the second in the list */
348 			free_lists[indx] = (unsigned long *)((char *)ptr + SIZE_HEADER + amount + TAIL_SIZE + SIZE_HEADER);
349 			/* take the fist one */
350 			ptr = (unsigned long *)((char *)ptr + SIZE_HEADER);
351 			LOG_ALLOC("Xalloc-S", amount, ptr);
352 			return ptr;
353 		} /* else fall through to 'Out of memory' */
354 	} else {
355 		/* take that piece of mem out of the list */
356 		free_lists[indx] = *((unsigned long **)ptr);
357 		/* already has size (and evtl. magic) filled in */
358 		LOG_ALLOC("Xalloc-S", amount, ptr);
359 		return ptr;
360 	}
361 
362 #if defined(HAS_MMAP_ANON) || defined(MMAP_DEV_ZERO)
363     } else if (amount >= MIN_LARGE) {
364 	/*
365 	 * large block
366 	 */
367 	/* mmapped malloc */
368 	/* round up amount */
369 	amount += SIZE_HEADER + TAIL_SIZE;
370 	/* round up brutto amount to a multiple of the page size */
371 	amount = (amount + pagesize-1) & ~(pagesize-1);
372 #ifdef MMAP_DEV_ZERO
373 	ptr = (unsigned long *)mmap((caddr_t)0,
374 					(size_t)amount,
375 					PROT_READ | PROT_WRITE,
376 					MAP_PRIVATE,
377 					devzerofd,
378 					(off_t)0);
379 #else
380 	ptr = (unsigned long *)mmap((caddr_t)0,
381 					(size_t)amount,
382 					PROT_READ | PROT_WRITE,
383 					MAP_ANON | MAP_PRIVATE,
384 					-1,
385 					(off_t)0);
386 #endif
387 	if (-1!=(long)ptr) {
388 		ptr[0] = amount - SIZE_HEADER - TAIL_SIZE;
389 #ifdef XALLOC_DEBUG
390 		ptr[1] = MAGIC;
391 #endif /* XALLOC_DEBUG */
392 #ifdef SIZE_TAIL
393 # ifdef __hppa__
394 		/* reserved space for 2 * sizeof(long), so use correct one */
395 		/* see SIZE_TAIL macro */
396 		((unsigned long *)((char *)ptr + amount))[-2] = MAGIC2;
397 # else
398 		((unsigned long *)((char *)ptr + amount))[-1] = MAGIC2;
399 # endif /* __hppa__ */
400 #endif /* SIZE_TAIL */
401 		ptr = (unsigned long *)((char *)ptr + SIZE_HEADER);
402 		LOG_ALLOC("Xalloc-L", amount, ptr);
403 		return ptr;
404 	} /* else fall through to 'Out of memory' */
405 #endif /* HAS_MMAP_ANON || MMAP_DEV_ZERO */
406     } else {
407 	/*
408 	 * medium sized block
409 	 */
410 	/* 'normal' malloc() */
411 	ptr=(unsigned long *)calloc(1,amount+SIZE_HEADER+TAIL_SIZE);
412 	if (ptr != (unsigned long *)NULL) {
413 		ptr[0] = amount;
414 #ifdef XALLOC_DEBUG
415 		ptr[1] = MAGIC;
416 #endif /* XALLOC_DEBUG */
417 #ifdef SIZE_TAIL
418 		*(unsigned long *)((char *)ptr + amount + SIZE_HEADER) = MAGIC2;
419 #endif /* SIZE_TAIL */
420 		ptr = (unsigned long *)((char *)ptr + SIZE_HEADER);
421 		LOG_ALLOC("Xalloc-M", amount, ptr);
422 		return ptr;
423 	}
424     }
425     if (Must_have_memory)
426 	FatalError("Out of memory");
427     LOG_ALLOC("Xalloc-oom", amount, 0);
428     return (unsigned long *)NULL;
429 }
430 
431 /*****************
432  * XNFalloc
433  * "no failure" realloc, alternate interface to Xalloc w/o Must_have_memory
434  *****************/
435 
436 unsigned long *
XNFalloc(amount)437 XNFalloc (amount)
438     unsigned long amount;
439 {
440     register unsigned long *ptr;
441 
442     /* zero size requested */
443     if (amount == 0) {
444 	LOG_ALLOC("XNFalloc=0", amount, 0);
445 	return (unsigned long *)NULL;
446     }
447     /* negative size (or size > 2GB) - what do we do? */
448     if ((long)amount < 0) {
449 	/* Diagnostic */
450 #ifdef FATALERRORS
451 	FatalError("Xalloc: XNFalloc(<0)\n");
452 #else
453 	ErrorF("Xalloc warning: XNFalloc(<0) ignored..\n");
454 #endif
455  	LOG_ALLOC("XNFalloc<0", amount, 0);
456 	return (unsigned long *)NULL;
457     }
458     ptr = Xalloc(amount);
459     if (!ptr)
460     {
461         FatalError("Out of memory");
462     }
463     return ptr;
464 }
465 
466 /*****************
467  * Xcalloc
468  *****************/
469 
470 unsigned long *
Xcalloc(amount)471 Xcalloc (amount)
472     unsigned long   amount;
473 {
474     unsigned long   *ret;
475 
476     ret = Xalloc (amount);
477     if (ret
478 #if defined(HAS_MMAP_ANON) || defined(MMAP_DEV_ZERO)
479 	    && (amount < MIN_LARGE)	/* mmaped anonymous mem is already cleared */
480 #endif
481        )
482 	bzero ((char *) ret, (int) amount);
483     return ret;
484 }
485 
486 /*****************
487  * Xrealloc
488  *****************/
489 
490 unsigned long *
Xrealloc(ptr,amount)491 Xrealloc (ptr, amount)
492     register pointer ptr;
493     unsigned long amount;
494 {
495     register unsigned long *new_ptr;
496 
497     /* zero size requested */
498     if (amount == 0) {
499 	if (ptr)
500 		Xfree(ptr);
501 	LOG_REALLOC("Xrealloc=0", ptr, amount, 0);
502 	return (unsigned long *)NULL;
503     }
504     /* negative size (or size > 2GB) - what do we do? */
505     if ((long)amount < 0) {
506 	/* Diagnostic */
507 #ifdef FATALERRORS
508 	FatalError("Xalloc: Xrealloc(<0)\n");
509 #else
510 	ErrorF("Xalloc warning: Xrealloc(<0) ignored..\n");
511 #endif
512 	if (ptr)
513 		Xfree(ptr);	/* ?? */
514 	LOG_REALLOC("Xrealloc<0", ptr, amount, 0);
515 	return (unsigned long *)NULL;
516     }
517 
518     new_ptr = Xalloc(amount);
519     if ( (new_ptr) && (ptr) ) {
520 	unsigned long old_size;
521 	old_size = ((unsigned long *)ptr)[-2];
522 #ifdef XALLOC_DEBUG
523 	if (MAGIC != ((unsigned long *)ptr)[-1]) {
524 #ifdef FATALERRORS
525 		FatalError("Xalloc error: header corrupt in Xrealloc() :-(\n");
526 #else
527 		ErrorF("Xalloc error: header corrupt in Xrealloc() :-(\n");
528 #endif
529 		LOG_REALLOC("Xalloc error: header corrupt in Xrealloc() :-(",
530 			ptr, amount, 0);
531 		return (unsigned long *)NULL;
532 	}
533 #endif /* XALLOC_DEBUG */
534 	/* copy min(old size, new size) */
535 	memcpy((char *)new_ptr, (char *)ptr, (amount < old_size ? amount : old_size));
536     }
537     if (ptr)
538 	Xfree(ptr);
539     if (new_ptr) {
540 	LOG_REALLOC("Xrealloc", ptr, amount, new_ptr);
541 	return new_ptr;
542     }
543     if (Must_have_memory)
544 	FatalError("Out of memory");
545     LOG_REALLOC("Xrealloc", ptr, amount, 0);
546     return (unsigned long *)NULL;
547 }
548 
549 /*****************
550  * XNFrealloc
551  * "no failure" realloc, alternate interface to Xrealloc w/o Must_have_memory
552  *****************/
553 
554 unsigned long *
XNFrealloc(ptr,amount)555 XNFrealloc (ptr, amount)
556     register pointer ptr;
557     unsigned long amount;
558 {
559     if (( ptr = (pointer)Xrealloc( ptr, amount ) ) == NULL)
560     {
561         FatalError( "Out of memory" );
562     }
563     return ((unsigned long *)ptr);
564 }
565 
566 /*****************
567  *  Xfree
568  *    calls free
569  *****************/
570 
571 void
Xfree(ptr)572 Xfree(ptr)
573     register pointer ptr;
574 {
575     unsigned long size;
576     unsigned long *pheader;
577 
578     /* free(NULL) IS valid :-(  - and widely used throughout the server.. */
579     if (!ptr)
580 	return;
581 
582     pheader = (unsigned long *)((char *)ptr - SIZE_HEADER);
583 #ifdef XALLOC_DEBUG
584     if (MAGIC != pheader[1]) {
585 	/* Diagnostic */
586 #ifdef FATALERRORS
587 	FatalError("Xalloc error: Header corrupt in Xfree() :-(\n");
588 #else
589 	ErrorF("Xalloc error: Header corrupt in Xfree() :-(\n");
590 #endif
591 	LOG_FREE("Xalloc error:  Header corrupt in Xfree() :-(", ptr);
592 	return;
593     }
594 #endif /* XALLOC_DEBUG */
595 
596     size = pheader[0];
597     if (size <= MAX_SMALL) {
598 	int indx;
599 	/*
600 	 * small block
601 	 */
602 #ifdef SIZE_TAIL
603 	if (MAGIC2 != *(unsigned long *)((char *)ptr + size)) {
604 		/* Diagnostic */
605 #ifdef FATALERRORS
606 		FatalError("Xalloc error: Tail corrupt in Xfree() for small block (adr=0x%x, val=0x%x)\n",(char *)ptr + size,*(unsigned long *)((char *)ptr + size));
607 #else
608 		ErrorF("Xalloc error: Tail corrupt in Xfree() for small block (adr=0x%x, val=0x%x)\n",(char *)ptr + size,*(unsigned long *)((char *)ptr + size));
609 #endif
610 		LOG_FREE("Xalloc error: Tail corrupt in Xfree() for small block", ptr);
611 		return;
612 	}
613 #endif /* SIZE_TAIL */
614 
615 #ifdef XFREE_ERASES
616 	memset(ptr,0xF0,size);
617 #endif /* XFREE_ERASES */
618 
619 	/* put this small block at the head of the list */
620 	indx = (size-1) / SIZE_STEPS;
621 	*(unsigned long **)(ptr) = free_lists[indx];
622 	free_lists[indx] = (unsigned long *)ptr;
623 	LOG_FREE("Xfree", ptr);
624 	return;
625 
626 #if defined(HAS_MMAP_ANON) || defined(MMAP_DEV_ZERO)
627     } else if (size >= MIN_LARGE) {
628 	/*
629 	 * large block
630 	 */
631 #ifdef SIZE_TAIL
632 	if (MAGIC2 != ((unsigned long *)((char *)ptr + size))[0]) {
633 		/* Diagnostic */
634 #ifdef FATALERRORS
635 		FatalError("Xalloc error: Tail corrupt in Xfree() for big block (adr=0x%x, val=0x%x)\n",(char *)ptr+size,((unsigned long *)((char *)ptr + size))[0]);
636 #else
637 		ErrorF("Xalloc error: Tail corrupt in Xfree() for big block (adr=0x%x, val=0x%x)\n",(char *)ptr+size,((unsigned long *)((char *)ptr + size))[0]);
638 #endif
639 		LOG_FREE("Xalloc error: Tail corrupt in Xfree() for big block", ptr);
640 		return;
641 	}
642 	size += SIZE_TAIL;
643 #endif /* SIZE_TAIL */
644 
645 	LOG_FREE("Xfree", ptr);
646 	size += SIZE_HEADER;
647 	munmap((caddr_t)pheader, (size_t)size);
648 	/* no need to clear - mem is inaccessible after munmap.. */
649 #endif /* HAS_MMAP_ANON */
650 
651     } else {
652 	/*
653 	 * medium sized block
654 	 */
655 #ifdef SIZE_TAIL
656 	if (MAGIC2 != *(unsigned long *)((char *)ptr + size)) {
657 		/* Diagnostic */
658 #ifdef FATALERRORS
659 		FatalError("Xalloc error: Tail corrupt in Xfree() for medium block (adr=0x%x, val=0x%x)\n",(char *)ptr + size,*(unsigned long *)((char *)ptr + size));
660 #else
661 		ErrorF("Xalloc error: Tail corrupt in Xfree() for medium block (adr=0x%x, val=0x%x)\n",(char *)ptr + size,*(unsigned long *)((char *)ptr + size));
662 #endif
663 		LOG_FREE("Xalloc error: Tail corrupt in Xfree() for medium block", ptr);
664 		return;
665 	}
666 #endif /* SIZE_TAIL */
667 
668 #ifdef XFREE_ERASES
669 	memset(pheader,0xF0,size+SIZE_HEADER);
670 #endif /* XFREE_ERASES */
671 
672 	LOG_FREE("Xfree", ptr);
673 	free((char *)pheader);
674     }
675 }
676 
677 void
OsInitAllocator()678 OsInitAllocator ()
679 {
680     static Bool beenhere = FALSE;
681 
682     if (beenhere)
683 	return;
684     beenhere = TRUE;
685 
686 #if defined(HAS_MMAP_ANON) || defined (MMAP_DEV_ZERO)
687 #if defined(_SC_PAGESIZE) /* || defined(linux) */
688     pagesize = sysconf(_SC_PAGESIZE);
689 #else
690 #ifdef HAS_GETPAGESIZE
691     pagesize = getpagesize();
692 #else
693     pagesize = PAGE_SIZE;
694 #endif
695 #endif
696 #endif
697 
698     /* set up linked lists of free blocks */
699     bzero ((char *) free_lists, MAX_SMALL/SIZE_STEPS*sizeof(unsigned long *));
700 
701 #ifdef MMAP_DEV_ZERO
702     /* open /dev/zero on systems that have mmap, but not MAP_ANON */
703     if (devzerofd < 0) {
704 	if ((devzerofd = open("/dev/zero", O_RDWR, 0)) < 0)
705 	    FatalError("OsInitAllocator: Cannot open /dev/zero (errno=%d)\n",
706 			errno);
707     }
708 #endif
709 
710 #ifdef XALLOC_LOG
711     /* reset the log file to zero length */
712     {
713 	FILE *f;
714 	f = fopen(XALLOC_LOG_FILE, "w");
715 	if (NULL!=f)
716 		fclose(f);
717     }
718 #endif
719 }
720 
721 #else /* !INTERNAL_MALLOC */
722 /* This is to avoid an empty .o */
723 static int no_internal_xalloc;
724 #endif /* INTERNAL_MALLOC */
725