]> git.sesse.net Git - rdpsrv/blob - Xserver/programs/Xserver/os/xalloc.c
Import X server from vnc-3.3.7.
[rdpsrv] / Xserver / programs / Xserver / os / xalloc.c
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 *
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 *
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 *
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 *
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 *
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
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
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 */