src/3rdparty/ptmalloc/ptmalloc3.c
changeset 0 1918ee327afb
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /*
       
     2  * $Id: ptmalloc3.c,v 1.8 2006/03/31 15:57:28 wg Exp $
       
     3  * 
       
     4 
       
     5 ptmalloc3 -- wrapper for Doug Lea's malloc-2.8.3 with concurrent
       
     6              allocations
       
     7 
       
     8 Copyright (c) 2005, 2006 Wolfram Gloger  <ptmalloc@malloc.de>
       
     9 
       
    10 Permission to use, copy, modify, distribute, and sell this software
       
    11 and its documentation for any purpose is hereby granted without fee,
       
    12 provided that (i) the above copyright notices and this permission
       
    13 notice appear in all copies of the software and related documentation,
       
    14 and (ii) the name of Wolfram Gloger may not be used in any advertising
       
    15 or publicity relating to the software.
       
    16 
       
    17 THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
       
    18 EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
       
    19 WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
       
    20 
       
    21 IN NO EVENT SHALL WOLFRAM GLOGER BE LIABLE FOR ANY SPECIAL,
       
    22 INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY
       
    23 DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
       
    24 WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY
       
    25 OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
       
    26 PERFORMANCE OF THIS SOFTWARE.
       
    27 
       
    28  */
       
    29 
       
    30 /*
       
    31  * TODO: optimization / better integration with malloc.c (partly done)
       
    32  *       malloc_{get,set}_state (probably hard to keep compatibility)
       
    33  *       debugging hooks
       
    34  *       better mstats
       
    35  */
       
    36 
       
    37 #include <sys/types.h>   /* For size_t */
       
    38 #include <sys/mman.h>    /* for mmap */
       
    39 #include <errno.h>
       
    40 #include <stdlib.h>
       
    41 #include <stdio.h>
       
    42 #include <string.h>      /* for memset */
       
    43 
       
    44 #include <malloc-machine.h>
       
    45 
       
    46 #include "malloc-2.8.3.h"
       
    47 
       
    48 /* ----------------------------------------------------------------------- */
       
    49 
       
    50 /* The following section is replicated from malloc.c */
       
    51 
       
    52 #include "malloc-private.h"
       
    53 
       
    54 /* end of definitions replicated from malloc.c */
       
    55 
       
    56 #define munmap_chunk(mst, p) do {                         \
       
    57   size_t prevsize = (p)->prev_foot & ~IS_MMAPPED_BIT;     \
       
    58   size_t psize = chunksize(p) + prevsize + MMAP_FOOT_PAD; \
       
    59   if (CALL_MUNMAP((char*)(p) - prevsize, psize) == 0)     \
       
    60     ((struct malloc_state*)(mst))->footprint -= psize;    \
       
    61 } while (0)
       
    62 
       
    63 /* ---------------------------------------------------------------------- */
       
    64 
       
    65 /* Minimum size for a newly created arena.  */
       
    66 #ifndef ARENA_SIZE_MIN
       
    67 # define ARENA_SIZE_MIN	   (128*1024)
       
    68 #endif
       
    69 #define HAVE_MEMCPY        1
       
    70 
       
    71 /* If THREAD_STATS is non-zero, some statistics on mutex locking are
       
    72    computed.  */
       
    73 #ifndef THREAD_STATS
       
    74 # define THREAD_STATS 0
       
    75 #endif
       
    76 
       
    77 #ifndef MALLOC_DEBUG
       
    78 # define MALLOC_DEBUG 0
       
    79 #endif
       
    80 
       
    81 #define my_powerof2(x) ((((x)-1)&(x))==0)
       
    82 
       
    83 /* Already initialized? */
       
    84 int __malloc_initialized = -1;
       
    85 
       
    86 #ifndef RETURN_ADDRESS
       
    87 # define RETURN_ADDRESS(X_) (NULL)
       
    88 #endif
       
    89 
       
    90 #if THREAD_STATS
       
    91 # define THREAD_STAT(x) x
       
    92 #else
       
    93 # define THREAD_STAT(x) do ; while(0)
       
    94 #endif
       
    95 
       
    96 #ifdef _LIBC
       
    97 
       
    98 /* Special defines for the GNU C library.  */
       
    99 #define public_cALLOc    __libc_calloc
       
   100 #define public_fREe      __libc_free
       
   101 #define public_cFREe     __libc_cfree
       
   102 #define public_mALLOc    __libc_malloc
       
   103 #define public_mEMALIGn  __libc_memalign
       
   104 #define public_rEALLOc   __libc_realloc
       
   105 #define public_vALLOc    __libc_valloc
       
   106 #define public_pVALLOc   __libc_pvalloc
       
   107 #define public_pMEMALIGn __posix_memalign
       
   108 #define public_mALLINFo  __libc_mallinfo
       
   109 #define public_mALLOPt   __libc_mallopt
       
   110 #define public_mTRIm     __malloc_trim
       
   111 #define public_mSTATs    __malloc_stats
       
   112 #define public_mUSABLe   __malloc_usable_size
       
   113 #define public_iCALLOc   __libc_independent_calloc
       
   114 #define public_iCOMALLOc __libc_independent_comalloc
       
   115 #define public_gET_STATe __malloc_get_state
       
   116 #define public_sET_STATe __malloc_set_state
       
   117 #define malloc_getpagesize __getpagesize()
       
   118 #define open             __open
       
   119 #define mmap             __mmap
       
   120 #define munmap           __munmap
       
   121 #define mremap           __mremap
       
   122 #define mprotect         __mprotect
       
   123 #define MORECORE         (*__morecore)
       
   124 #define MORECORE_FAILURE 0
       
   125 
       
   126 void * __default_morecore (ptrdiff_t);
       
   127 void *(*__morecore)(ptrdiff_t) = __default_morecore;
       
   128 
       
   129 #else /* !_LIBC */
       
   130 
       
   131 #define public_cALLOc    calloc
       
   132 #define public_fREe      free
       
   133 #define public_cFREe     cfree
       
   134 #define public_mALLOc    malloc
       
   135 #define public_mEMALIGn  memalign
       
   136 #define public_rEALLOc   realloc
       
   137 #define public_vALLOc    valloc
       
   138 #define public_pVALLOc   pvalloc
       
   139 #define public_pMEMALIGn posix_memalign
       
   140 #define public_mALLINFo  mallinfo
       
   141 #define public_mALLOPt   mallopt
       
   142 #define public_mTRIm     malloc_trim
       
   143 #define public_mSTATs    malloc_stats
       
   144 #define public_mUSABLe   malloc_usable_size
       
   145 #define public_iCALLOc   independent_calloc
       
   146 #define public_iCOMALLOc independent_comalloc
       
   147 #define public_gET_STATe malloc_get_state
       
   148 #define public_sET_STATe malloc_set_state
       
   149 
       
   150 #endif /* _LIBC */
       
   151 
       
   152 #if !defined _LIBC && (!defined __GNUC__ || __GNUC__<3)
       
   153 #define __builtin_expect(expr, val) (expr)
       
   154 #endif
       
   155 
       
   156 #if MALLOC_DEBUG
       
   157 #include <assert.h>
       
   158 #else
       
   159 #undef assert
       
   160 #define assert(x) ((void)0)
       
   161 #endif
       
   162 
       
   163 /* USE_STARTER determines if and when the special "starter" hook
       
   164    functions are used: not at all (0), during ptmalloc_init (first bit
       
   165    set), or from the beginning until an explicit call to ptmalloc_init
       
   166    (second bit set).  This is necessary if thread-related
       
   167    initialization functions (e.g.  pthread_key_create) require
       
   168    malloc() calls (set USE_STARTER=1), or if those functions initially
       
   169    cannot be used at all (set USE_STARTER=2 and perform an explicit
       
   170    ptmalloc_init() when the thread library is ready, typically at the
       
   171    start of main()). */
       
   172 
       
   173 #ifndef USE_STARTER
       
   174 # ifndef _LIBC
       
   175 #  define USE_STARTER 1
       
   176 # else
       
   177 #  if USE___THREAD || (defined USE_TLS && !defined SHARED)
       
   178     /* These routines are never needed in this configuration.  */
       
   179 #   define USE_STARTER 0
       
   180 #  else
       
   181 #   define USE_STARTER (USE_TLS ? 4 : 1)
       
   182 #  endif
       
   183 # endif
       
   184 #endif
       
   185 
       
   186 /*----------------------------------------------------------------------*/
       
   187 
       
   188 /* Arenas */
       
   189 static tsd_key_t arena_key;
       
   190 static mutex_t list_lock;
       
   191 
       
   192 /* Arena structure */
       
   193 struct malloc_arena {
       
   194   /* Serialize access.  */
       
   195   mutex_t mutex;
       
   196 
       
   197   /* Statistics for locking.  Only used if THREAD_STATS is defined.  */
       
   198   long stat_lock_direct, stat_lock_loop, stat_lock_wait;
       
   199   long stat_starter;
       
   200 
       
   201   /* Linked list */
       
   202   struct malloc_arena *next;
       
   203 
       
   204   /* Space for mstate.  The size is just the minimum such that
       
   205      create_mspace_with_base can be successfully called.  */
       
   206   char buf_[pad_request(sizeof(struct malloc_state)) + TOP_FOOT_SIZE +
       
   207 	    CHUNK_ALIGN_MASK + 1];
       
   208 };
       
   209 #define MSPACE_OFFSET (((offsetof(struct malloc_arena, buf_) \
       
   210 			 + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK))
       
   211 #define arena_to_mspace(a) ((void *)chunk2mem((char*)(a) + MSPACE_OFFSET))
       
   212 
       
   213 /* check for chunk from non-main arena */
       
   214 #define chunk_non_main_arena(p) ((p)->head & NON_MAIN_ARENA)
       
   215 
       
   216 static struct malloc_arena* _int_new_arena(size_t size);
       
   217 
       
   218 /* Buffer for the main arena. */
       
   219 static struct malloc_arena main_arena;
       
   220 
       
   221 /* For now, store arena in footer.  This means typically 4bytes more
       
   222    overhead for each non-main-arena chunk, but is fast and easy to
       
   223    compute.  Note that the pointer stored in the extra footer must be
       
   224    properly aligned, though. */
       
   225 #define FOOTER_OVERHEAD \
       
   226  (2*sizeof(struct malloc_arena*) - SIZE_T_SIZE)
       
   227 
       
   228 #define arena_for_chunk(ptr) \
       
   229  (chunk_non_main_arena(ptr) ? *(struct malloc_arena**)              \
       
   230   ((char*)(ptr) + chunksize(ptr) - (FOOTER_OVERHEAD - SIZE_T_SIZE)) \
       
   231   : &main_arena)
       
   232 
       
   233 /* special because of extra overhead */
       
   234 #define arena_for_mmap_chunk(ptr) \
       
   235  (chunk_non_main_arena(ptr) ? *(struct malloc_arena**)             \
       
   236   ((char*)(ptr) + chunksize(ptr) - sizeof(struct malloc_arena*))   \
       
   237   : &main_arena)
       
   238 
       
   239 #define set_non_main_arena(mem, ar_ptr) do {                   		      \
       
   240   mchunkptr P = mem2chunk(mem);                                               \
       
   241   size_t SZ = chunksize(P) - (is_mmapped(P) ? sizeof(struct malloc_arena*)    \
       
   242                               : (FOOTER_OVERHEAD - SIZE_T_SIZE));             \
       
   243   assert((unsigned long)((char*)(P) + SZ)%sizeof(struct malloc_arena*) == 0); \
       
   244   *(struct malloc_arena**)((char*)(P) + SZ) = (ar_ptr);                       \
       
   245   P->head |= NON_MAIN_ARENA;                                                  \
       
   246 } while (0)
       
   247 
       
   248 /* arena_get() acquires an arena and locks the corresponding mutex.
       
   249    First, try the one last locked successfully by this thread.  (This
       
   250    is the common case and handled with a macro for speed.)  Then, loop
       
   251    once over the circularly linked list of arenas.  If no arena is
       
   252    readily available, create a new one.  In this latter case, `size'
       
   253    is just a hint as to how much memory will be required immediately
       
   254    in the new arena. */
       
   255 
       
   256 #define arena_get(ptr, size) do { \
       
   257   void *vptr = NULL; \
       
   258   ptr = (struct malloc_arena*)tsd_getspecific(arena_key, vptr); \
       
   259   if(ptr && !mutex_trylock(&ptr->mutex)) { \
       
   260     THREAD_STAT(++(ptr->stat_lock_direct)); \
       
   261   } else \
       
   262     ptr = arena_get2(ptr, (size)); \
       
   263 } while(0)
       
   264 
       
   265 static struct malloc_arena*
       
   266 arena_get2(struct malloc_arena* a_tsd, size_t size)
       
   267 {
       
   268   struct malloc_arena* a;
       
   269   int err;
       
   270 
       
   271   if(!a_tsd)
       
   272     a = a_tsd = &main_arena;
       
   273   else {
       
   274     a = a_tsd->next;
       
   275     if(!a) {
       
   276       /* This can only happen while initializing the new arena. */
       
   277       (void)mutex_lock(&main_arena.mutex);
       
   278       THREAD_STAT(++(main_arena.stat_lock_wait));
       
   279       return &main_arena;
       
   280     }
       
   281   }
       
   282 
       
   283   /* Check the global, circularly linked list for available arenas. */
       
   284  repeat:
       
   285   do {
       
   286     if(!mutex_trylock(&a->mutex)) {
       
   287       THREAD_STAT(++(a->stat_lock_loop));
       
   288       tsd_setspecific(arena_key, (void *)a);
       
   289       return a;
       
   290     }
       
   291     a = a->next;
       
   292   } while(a != a_tsd);
       
   293 
       
   294   /* If not even the list_lock can be obtained, try again.  This can
       
   295      happen during `atfork', or for example on systems where thread
       
   296      creation makes it temporarily impossible to obtain _any_
       
   297      locks. */
       
   298   if(mutex_trylock(&list_lock)) {
       
   299     a = a_tsd;
       
   300     goto repeat;
       
   301   }
       
   302   (void)mutex_unlock(&list_lock);
       
   303 
       
   304   /* Nothing immediately available, so generate a new arena.  */
       
   305   a = _int_new_arena(size);
       
   306   if(!a)
       
   307     return 0;
       
   308 
       
   309   tsd_setspecific(arena_key, (void *)a);
       
   310   mutex_init(&a->mutex);
       
   311   err = mutex_lock(&a->mutex); /* remember result */
       
   312 
       
   313   /* Add the new arena to the global list.  */
       
   314   (void)mutex_lock(&list_lock);
       
   315   a->next = main_arena.next;
       
   316   atomic_write_barrier ();
       
   317   main_arena.next = a;
       
   318   (void)mutex_unlock(&list_lock);
       
   319 
       
   320   if(err) /* locking failed; keep arena for further attempts later */
       
   321     return 0;
       
   322 
       
   323   THREAD_STAT(++(a->stat_lock_loop));
       
   324   return a;
       
   325 }
       
   326 
       
   327 /* Create a new arena with room for a chunk of size "size".  */
       
   328 
       
   329 static struct malloc_arena*
       
   330 _int_new_arena(size_t size)
       
   331 {
       
   332   struct malloc_arena* a;
       
   333   size_t mmap_sz = sizeof(*a) + pad_request(size);
       
   334   void *m;
       
   335 
       
   336   if (mmap_sz < ARENA_SIZE_MIN)
       
   337     mmap_sz = ARENA_SIZE_MIN;
       
   338   /* conservative estimate for page size */
       
   339   mmap_sz = (mmap_sz + 8191) & ~(size_t)8191;
       
   340   a = CALL_MMAP(mmap_sz);
       
   341   if ((char*)a == (char*)-1)
       
   342     return 0;
       
   343 
       
   344   m = create_mspace_with_base((char*)a + MSPACE_OFFSET,
       
   345 			      mmap_sz - MSPACE_OFFSET,
       
   346 			      0);
       
   347 
       
   348   if (!m) { 
       
   349     CALL_MUNMAP(a, mmap_sz);
       
   350     a = 0;
       
   351   } else {
       
   352     /*a->next = NULL;*/
       
   353     /*a->system_mem = a->max_system_mem = h->size;*/
       
   354   }
       
   355 
       
   356   return a;
       
   357 }
       
   358 
       
   359 /*------------------------------------------------------------------------*/
       
   360 
       
   361 /* Hook mechanism for proper initialization and atfork support. */
       
   362 
       
   363 /* Define and initialize the hook variables.  These weak definitions must
       
   364    appear before any use of the variables in a function.  */
       
   365 #ifndef weak_variable
       
   366 #ifndef _LIBC
       
   367 #define weak_variable /**/
       
   368 #else
       
   369 /* In GNU libc we want the hook variables to be weak definitions to
       
   370    avoid a problem with Emacs.  */
       
   371 #define weak_variable weak_function
       
   372 #endif
       
   373 #endif
       
   374 
       
   375 #if !(USE_STARTER & 2)
       
   376 # define free_hook_ini     NULL
       
   377 /* Forward declarations.  */
       
   378 static void* malloc_hook_ini (size_t sz, const void *caller);
       
   379 static void* realloc_hook_ini (void* ptr, size_t sz, const void* caller);
       
   380 static void* memalign_hook_ini (size_t alignment, size_t sz,
       
   381 				const void* caller);
       
   382 #else
       
   383 # define free_hook_ini     free_starter
       
   384 # define malloc_hook_ini   malloc_starter
       
   385 # define realloc_hook_ini  NULL
       
   386 # define memalign_hook_ini memalign_starter
       
   387 #endif
       
   388 
       
   389 void weak_variable (*__malloc_initialize_hook) (void) = NULL;
       
   390 void weak_variable (*__free_hook) (void * __ptr, const void *)
       
   391      = free_hook_ini;
       
   392 void * weak_variable (*__malloc_hook) (size_t __size, const void *)
       
   393      = malloc_hook_ini;
       
   394 void * weak_variable (*__realloc_hook)
       
   395      (void * __ptr, size_t __size, const void *) = realloc_hook_ini;
       
   396 void * weak_variable (*__memalign_hook)
       
   397   (size_t __alignment, size_t __size, const void *) = memalign_hook_ini;
       
   398 /*void weak_variable (*__after_morecore_hook) (void) = NULL;*/
       
   399 
       
   400 /* The initial hooks just call the initialization routine, then do the
       
   401    normal work. */
       
   402 
       
   403 #if !(USE_STARTER & 2)
       
   404 static
       
   405 #endif
       
   406 void ptmalloc_init(void);
       
   407 
       
   408 #if !(USE_STARTER & 2)
       
   409 
       
   410 static void*
       
   411 malloc_hook_ini(size_t sz, const void * caller)
       
   412 {
       
   413   __malloc_hook = NULL;
       
   414   ptmalloc_init();
       
   415   return public_mALLOc(sz);
       
   416 }
       
   417 
       
   418 static void *
       
   419 realloc_hook_ini(void *ptr, size_t sz, const void * caller)
       
   420 {
       
   421   __malloc_hook = NULL;
       
   422   __realloc_hook = NULL;
       
   423   ptmalloc_init();
       
   424   return public_rEALLOc(ptr, sz);
       
   425 }
       
   426 
       
   427 static void*
       
   428 memalign_hook_ini(size_t alignment, size_t sz, const void * caller)
       
   429 {
       
   430   __memalign_hook = NULL;
       
   431   ptmalloc_init();
       
   432   return public_mEMALIGn(alignment, sz);
       
   433 }
       
   434 
       
   435 #endif /* !(USE_STARTER & 2) */
       
   436 
       
   437 /*----------------------------------------------------------------------*/
       
   438 
       
   439 #if !defined NO_THREADS && USE_STARTER
       
   440 
       
   441 /* The following hooks are used when the global initialization in
       
   442    ptmalloc_init() hasn't completed yet. */
       
   443 
       
   444 static void*
       
   445 malloc_starter(size_t sz, const void *caller)
       
   446 {
       
   447   void* victim;
       
   448 
       
   449   /*ptmalloc_init_minimal();*/
       
   450   victim = mspace_malloc(arena_to_mspace(&main_arena), sz);
       
   451   THREAD_STAT(++main_arena.stat_starter);
       
   452 
       
   453   return victim;
       
   454 }
       
   455 
       
   456 static void*
       
   457 memalign_starter(size_t align, size_t sz, const void *caller)
       
   458 {
       
   459   void* victim;
       
   460 
       
   461   /*ptmalloc_init_minimal();*/
       
   462   victim = mspace_memalign(arena_to_mspace(&main_arena), align, sz);
       
   463   THREAD_STAT(++main_arena.stat_starter);
       
   464 
       
   465   return victim;
       
   466 }
       
   467 
       
   468 static void
       
   469 free_starter(void* mem, const void *caller)
       
   470 {
       
   471   if (mem) {
       
   472     mchunkptr p = mem2chunk(mem);
       
   473     void *msp = arena_to_mspace(&main_arena);
       
   474     if (is_mmapped(p))
       
   475       munmap_chunk(msp, p);
       
   476     else
       
   477       mspace_free(msp, mem);
       
   478   }
       
   479   THREAD_STAT(++main_arena.stat_starter);
       
   480 }
       
   481 
       
   482 #endif /* !defined NO_THREADS && USE_STARTER */
       
   483 
       
   484 /*----------------------------------------------------------------------*/
       
   485 
       
   486 #ifndef NO_THREADS
       
   487 
       
   488 /* atfork support.  */
       
   489 
       
   490 static void * (*save_malloc_hook) (size_t __size, const void *);
       
   491 # if !defined _LIBC || !defined USE_TLS || (defined SHARED && !USE___THREAD)
       
   492 static void * (*save_memalign_hook) (size_t __align, size_t __size,
       
   493 				     const void *);
       
   494 # endif
       
   495 static void   (*save_free_hook) (void * __ptr, const void *);
       
   496 static void*  save_arena;
       
   497 
       
   498 /* Magic value for the thread-specific arena pointer when
       
   499    malloc_atfork() is in use.  */
       
   500 
       
   501 #define ATFORK_ARENA_PTR ((void*)-1)
       
   502 
       
   503 /* The following hooks are used while the `atfork' handling mechanism
       
   504    is active. */
       
   505 
       
   506 static void*
       
   507 malloc_atfork(size_t sz, const void *caller)
       
   508 {
       
   509   void *vptr = NULL;
       
   510 
       
   511   tsd_getspecific(arena_key, vptr);
       
   512   if(vptr == ATFORK_ARENA_PTR) {
       
   513     /* We are the only thread that may allocate at all.  */
       
   514     return mspace_malloc(arena_to_mspace(&main_arena), sz);
       
   515   } else {
       
   516     /* Suspend the thread until the `atfork' handlers have completed.
       
   517        By that time, the hooks will have been reset as well, so that
       
   518        mALLOc() can be used again. */
       
   519     (void)mutex_lock(&list_lock);
       
   520     (void)mutex_unlock(&list_lock);
       
   521     return public_mALLOc(sz);
       
   522   }
       
   523 }
       
   524 
       
   525 static void
       
   526 free_atfork(void* mem, const void *caller)
       
   527 {
       
   528   void *vptr = NULL;
       
   529   struct malloc_arena *ar_ptr;
       
   530   mchunkptr p;                          /* chunk corresponding to mem */
       
   531 
       
   532   if (mem == 0)                              /* free(0) has no effect */
       
   533     return;
       
   534 
       
   535   p = mem2chunk(mem);
       
   536 
       
   537   if (is_mmapped(p)) {                      /* release mmapped memory. */
       
   538     ar_ptr = arena_for_mmap_chunk(p);
       
   539     munmap_chunk(arena_to_mspace(ar_ptr), p);
       
   540     return;
       
   541   }
       
   542 
       
   543   ar_ptr = arena_for_chunk(p);
       
   544   tsd_getspecific(arena_key, vptr);
       
   545   if(vptr != ATFORK_ARENA_PTR)
       
   546     (void)mutex_lock(&ar_ptr->mutex);
       
   547   mspace_free(arena_to_mspace(ar_ptr), mem);
       
   548   if(vptr != ATFORK_ARENA_PTR)
       
   549     (void)mutex_unlock(&ar_ptr->mutex);
       
   550 }
       
   551 
       
   552 /* The following two functions are registered via thread_atfork() to
       
   553    make sure that the mutexes remain in a consistent state in the
       
   554    fork()ed version of a thread.  Also adapt the malloc and free hooks
       
   555    temporarily, because the `atfork' handler mechanism may use
       
   556    malloc/free internally (e.g. in LinuxThreads). */
       
   557 
       
   558 static void
       
   559 ptmalloc_lock_all (void)
       
   560 {
       
   561   struct malloc_arena* ar_ptr;
       
   562 
       
   563   if(__malloc_initialized < 1)
       
   564     return;
       
   565   (void)mutex_lock(&list_lock);
       
   566   for(ar_ptr = &main_arena;;) {
       
   567     (void)mutex_lock(&ar_ptr->mutex);
       
   568     ar_ptr = ar_ptr->next;
       
   569     if(ar_ptr == &main_arena)
       
   570       break;
       
   571   }
       
   572   save_malloc_hook = __malloc_hook;
       
   573   save_free_hook = __free_hook;
       
   574   __malloc_hook = malloc_atfork;
       
   575   __free_hook = free_atfork;
       
   576   /* Only the current thread may perform malloc/free calls now. */
       
   577   tsd_getspecific(arena_key, save_arena);
       
   578   tsd_setspecific(arena_key, ATFORK_ARENA_PTR);
       
   579 }
       
   580 
       
   581 static void
       
   582 ptmalloc_unlock_all (void)
       
   583 {
       
   584   struct malloc_arena *ar_ptr;
       
   585 
       
   586   if(__malloc_initialized < 1)
       
   587     return;
       
   588   tsd_setspecific(arena_key, save_arena);
       
   589   __malloc_hook = save_malloc_hook;
       
   590   __free_hook = save_free_hook;
       
   591   for(ar_ptr = &main_arena;;) {
       
   592     (void)mutex_unlock(&ar_ptr->mutex);
       
   593     ar_ptr = ar_ptr->next;
       
   594     if(ar_ptr == &main_arena) break;
       
   595   }
       
   596   (void)mutex_unlock(&list_lock);
       
   597 }
       
   598 
       
   599 #ifdef __linux__
       
   600 
       
   601 /* In LinuxThreads, unlocking a mutex in the child process after a
       
   602    fork() is currently unsafe, whereas re-initializing it is safe and
       
   603    does not leak resources.  Therefore, a special atfork handler is
       
   604    installed for the child. */
       
   605 
       
   606 static void
       
   607 ptmalloc_unlock_all2(void)
       
   608 {
       
   609   struct malloc_arena *ar_ptr;
       
   610 
       
   611   if(__malloc_initialized < 1)
       
   612     return;
       
   613 #if defined _LIBC || 1 /*defined MALLOC_HOOKS*/
       
   614   tsd_setspecific(arena_key, save_arena);
       
   615   __malloc_hook = save_malloc_hook;
       
   616   __free_hook = save_free_hook;
       
   617 #endif
       
   618   for(ar_ptr = &main_arena;;) {
       
   619     (void)mutex_init(&ar_ptr->mutex);
       
   620     ar_ptr = ar_ptr->next;
       
   621     if(ar_ptr == &main_arena) break;
       
   622   }
       
   623   (void)mutex_init(&list_lock);
       
   624 }
       
   625 
       
   626 #else
       
   627 
       
   628 #define ptmalloc_unlock_all2 ptmalloc_unlock_all
       
   629 
       
   630 #endif
       
   631 
       
   632 #endif /* !defined NO_THREADS */
       
   633 
       
   634 /*---------------------------------------------------------------------*/
       
   635 
       
   636 #if !(USE_STARTER & 2)
       
   637 static
       
   638 #endif
       
   639 void
       
   640 ptmalloc_init(void)
       
   641 {
       
   642   const char* s;
       
   643   int secure = 0;
       
   644   void *mspace;
       
   645 
       
   646   if(__malloc_initialized >= 0) return;
       
   647   __malloc_initialized = 0;
       
   648 
       
   649   /*if (mp_.pagesize == 0)
       
   650     ptmalloc_init_minimal();*/
       
   651 
       
   652 #ifndef NO_THREADS
       
   653 # if USE_STARTER & 1
       
   654   /* With some threads implementations, creating thread-specific data
       
   655      or initializing a mutex may call malloc() itself.  Provide a
       
   656      simple starter version (realloc() won't work). */
       
   657   save_malloc_hook = __malloc_hook;
       
   658   save_memalign_hook = __memalign_hook;
       
   659   save_free_hook = __free_hook;
       
   660   __malloc_hook = malloc_starter;
       
   661   __memalign_hook = memalign_starter;
       
   662   __free_hook = free_starter;
       
   663 #  ifdef _LIBC
       
   664   /* Initialize the pthreads interface. */
       
   665   if (__pthread_initialize != NULL)
       
   666     __pthread_initialize();
       
   667 #  endif /* !defined _LIBC */
       
   668 # endif /* USE_STARTER & 1 */
       
   669 #endif /* !defined NO_THREADS */
       
   670   mutex_init(&main_arena.mutex);
       
   671   main_arena.next = &main_arena;
       
   672   mspace = create_mspace_with_base((char*)&main_arena + MSPACE_OFFSET,
       
   673 				   sizeof(main_arena) - MSPACE_OFFSET,
       
   674 				   0);
       
   675   assert(mspace == arena_to_mspace(&main_arena));
       
   676 
       
   677   mutex_init(&list_lock);
       
   678   tsd_key_create(&arena_key, NULL);
       
   679   tsd_setspecific(arena_key, (void *)&main_arena);
       
   680   thread_atfork(ptmalloc_lock_all, ptmalloc_unlock_all, ptmalloc_unlock_all2);
       
   681 #ifndef NO_THREADS
       
   682 # if USE_STARTER & 1
       
   683   __malloc_hook = save_malloc_hook;
       
   684   __memalign_hook = save_memalign_hook;
       
   685   __free_hook = save_free_hook;
       
   686 # endif
       
   687 # if USE_STARTER & 2
       
   688   __malloc_hook = 0;
       
   689   __memalign_hook = 0;
       
   690   __free_hook = 0;
       
   691 # endif
       
   692 #endif
       
   693 #ifdef _LIBC
       
   694   secure = __libc_enable_secure;
       
   695 #else
       
   696   if (! secure) {
       
   697     if ((s = getenv("MALLOC_TRIM_THRESHOLD_")))
       
   698       public_mALLOPt(M_TRIM_THRESHOLD, atoi(s));
       
   699     if ((s = getenv("MALLOC_TOP_PAD_")) ||
       
   700 	(s = getenv("MALLOC_GRANULARITY_")))
       
   701       public_mALLOPt(M_GRANULARITY, atoi(s));
       
   702     if ((s = getenv("MALLOC_MMAP_THRESHOLD_")))
       
   703       public_mALLOPt(M_MMAP_THRESHOLD, atoi(s));
       
   704     /*if ((s = getenv("MALLOC_MMAP_MAX_"))) this is no longer available
       
   705       public_mALLOPt(M_MMAP_MAX, atoi(s));*/
       
   706   }
       
   707   s = getenv("MALLOC_CHECK_");
       
   708 #endif
       
   709   if (s) {
       
   710     /*if(s[0]) mALLOPt(M_CHECK_ACTION, (int)(s[0] - '0'));
       
   711       __malloc_check_init();*/
       
   712   }
       
   713   if (__malloc_initialize_hook != NULL)
       
   714     (*__malloc_initialize_hook)();
       
   715   __malloc_initialized = 1;
       
   716 }
       
   717 
       
   718 /*------------------------ Public wrappers. --------------------------------*/
       
   719 
       
   720 void*
       
   721 public_mALLOc(size_t bytes)
       
   722 {
       
   723   struct malloc_arena* ar_ptr;
       
   724   void *victim;
       
   725 
       
   726   void * (*hook) (size_t, const void *) = __malloc_hook;
       
   727   if (hook != NULL)
       
   728     return (*hook)(bytes, RETURN_ADDRESS (0));
       
   729 
       
   730   arena_get(ar_ptr, bytes + FOOTER_OVERHEAD);
       
   731   if (!ar_ptr)
       
   732     return 0;
       
   733   if (ar_ptr != &main_arena)
       
   734     bytes += FOOTER_OVERHEAD;
       
   735   victim = mspace_malloc(arena_to_mspace(ar_ptr), bytes);
       
   736   if (victim && ar_ptr != &main_arena)
       
   737     set_non_main_arena(victim, ar_ptr);
       
   738   (void)mutex_unlock(&ar_ptr->mutex);
       
   739   assert(!victim || is_mmapped(mem2chunk(victim)) ||
       
   740 	 ar_ptr == arena_for_chunk(mem2chunk(victim)));
       
   741   return victim;
       
   742 }
       
   743 #ifdef libc_hidden_def
       
   744 libc_hidden_def(public_mALLOc)
       
   745 #endif
       
   746 
       
   747 void
       
   748 public_fREe(void* mem)
       
   749 {
       
   750   struct malloc_arena* ar_ptr;
       
   751   mchunkptr p;                          /* chunk corresponding to mem */
       
   752 
       
   753   void (*hook) (void *, const void *) = __free_hook;
       
   754   if (hook != NULL) {
       
   755     (*hook)(mem, RETURN_ADDRESS (0));
       
   756     return;
       
   757   }
       
   758 
       
   759   if (mem == 0)                              /* free(0) has no effect */
       
   760     return;
       
   761 
       
   762   p = mem2chunk(mem);
       
   763 
       
   764   if (is_mmapped(p)) {                      /* release mmapped memory. */
       
   765     ar_ptr = arena_for_mmap_chunk(p);
       
   766     munmap_chunk(arena_to_mspace(ar_ptr), p);
       
   767     return;
       
   768   }
       
   769 
       
   770   ar_ptr = arena_for_chunk(p);
       
   771 #if THREAD_STATS
       
   772   if(!mutex_trylock(&ar_ptr->mutex))
       
   773     ++(ar_ptr->stat_lock_direct);
       
   774   else {
       
   775     (void)mutex_lock(&ar_ptr->mutex);
       
   776     ++(ar_ptr->stat_lock_wait);
       
   777   }
       
   778 #else
       
   779   (void)mutex_lock(&ar_ptr->mutex);
       
   780 #endif
       
   781   mspace_free(arena_to_mspace(ar_ptr), mem);
       
   782   (void)mutex_unlock(&ar_ptr->mutex);
       
   783 }
       
   784 #ifdef libc_hidden_def
       
   785 libc_hidden_def (public_fREe)
       
   786 #endif
       
   787 
       
   788 void*
       
   789 public_rEALLOc(void* oldmem, size_t bytes)
       
   790 {
       
   791   struct malloc_arena* ar_ptr;
       
   792 
       
   793   mchunkptr oldp;             /* chunk corresponding to oldmem */
       
   794 
       
   795   void* newp;             /* chunk to return */
       
   796 
       
   797   void * (*hook) (void *, size_t, const void *) = __realloc_hook;
       
   798   if (hook != NULL)
       
   799     return (*hook)(oldmem, bytes, RETURN_ADDRESS (0));
       
   800 
       
   801 #if REALLOC_ZERO_BYTES_FREES
       
   802   if (bytes == 0 && oldmem != NULL) { public_fREe(oldmem); return 0; }
       
   803 #endif
       
   804 
       
   805   /* realloc of null is supposed to be same as malloc */
       
   806   if (oldmem == 0)
       
   807     return public_mALLOc(bytes);
       
   808 
       
   809   oldp    = mem2chunk(oldmem);
       
   810   if (is_mmapped(oldp))
       
   811     ar_ptr = arena_for_mmap_chunk(oldp); /* FIXME: use mmap_resize */
       
   812   else
       
   813     ar_ptr = arena_for_chunk(oldp);
       
   814 #if THREAD_STATS
       
   815   if(!mutex_trylock(&ar_ptr->mutex))
       
   816     ++(ar_ptr->stat_lock_direct);
       
   817   else {
       
   818     (void)mutex_lock(&ar_ptr->mutex);
       
   819     ++(ar_ptr->stat_lock_wait);
       
   820   }
       
   821 #else
       
   822   (void)mutex_lock(&ar_ptr->mutex);
       
   823 #endif
       
   824 
       
   825 #ifndef NO_THREADS
       
   826   /* As in malloc(), remember this arena for the next allocation. */
       
   827   tsd_setspecific(arena_key, (void *)ar_ptr);
       
   828 #endif
       
   829 
       
   830   if (ar_ptr != &main_arena)
       
   831     bytes += FOOTER_OVERHEAD;
       
   832   newp = mspace_realloc(arena_to_mspace(ar_ptr), oldmem, bytes);
       
   833 
       
   834   if (newp && ar_ptr != &main_arena)
       
   835     set_non_main_arena(newp, ar_ptr);
       
   836   (void)mutex_unlock(&ar_ptr->mutex);
       
   837 
       
   838   assert(!newp || is_mmapped(mem2chunk(newp)) ||
       
   839 	 ar_ptr == arena_for_chunk(mem2chunk(newp)));
       
   840   return newp;
       
   841 }
       
   842 #ifdef libc_hidden_def
       
   843 libc_hidden_def (public_rEALLOc)
       
   844 #endif
       
   845 
       
   846 void*
       
   847 public_mEMALIGn(size_t alignment, size_t bytes)
       
   848 {
       
   849   struct malloc_arena* ar_ptr;
       
   850   void *p;
       
   851 
       
   852   void * (*hook) (size_t, size_t, const void *) = __memalign_hook;
       
   853   if (hook != NULL)
       
   854     return (*hook)(alignment, bytes, RETURN_ADDRESS (0));
       
   855 
       
   856   /* If need less alignment than we give anyway, just relay to malloc */
       
   857   if (alignment <= MALLOC_ALIGNMENT) return public_mALLOc(bytes);
       
   858 
       
   859   /* Otherwise, ensure that it is at least a minimum chunk size */
       
   860   if (alignment <  MIN_CHUNK_SIZE)
       
   861     alignment = MIN_CHUNK_SIZE;
       
   862 
       
   863   arena_get(ar_ptr,
       
   864 	    bytes + FOOTER_OVERHEAD + alignment + MIN_CHUNK_SIZE);
       
   865   if(!ar_ptr)
       
   866     return 0;
       
   867 
       
   868   if (ar_ptr != &main_arena)
       
   869     bytes += FOOTER_OVERHEAD;
       
   870   p = mspace_memalign(arena_to_mspace(ar_ptr), alignment, bytes);
       
   871 
       
   872   if (p && ar_ptr != &main_arena)
       
   873     set_non_main_arena(p, ar_ptr);
       
   874   (void)mutex_unlock(&ar_ptr->mutex);
       
   875 
       
   876   assert(!p || is_mmapped(mem2chunk(p)) ||
       
   877 	 ar_ptr == arena_for_chunk(mem2chunk(p)));
       
   878   return p;
       
   879 }
       
   880 #ifdef libc_hidden_def
       
   881 libc_hidden_def (public_mEMALIGn)
       
   882 #endif
       
   883 
       
   884 void*
       
   885 public_vALLOc(size_t bytes)
       
   886 {
       
   887   struct malloc_arena* ar_ptr;
       
   888   void *p;
       
   889 
       
   890   if(__malloc_initialized < 0)
       
   891     ptmalloc_init ();
       
   892   arena_get(ar_ptr, bytes + FOOTER_OVERHEAD + MIN_CHUNK_SIZE);
       
   893   if(!ar_ptr)
       
   894     return 0;
       
   895   if (ar_ptr != &main_arena)
       
   896     bytes += FOOTER_OVERHEAD;
       
   897   p = mspace_memalign(arena_to_mspace(ar_ptr), 4096, bytes);
       
   898 
       
   899   if (p && ar_ptr != &main_arena)
       
   900     set_non_main_arena(p, ar_ptr);
       
   901   (void)mutex_unlock(&ar_ptr->mutex);
       
   902   return p;
       
   903 }
       
   904 
       
   905 int
       
   906 public_pMEMALIGn (void **memptr, size_t alignment, size_t size)
       
   907 {
       
   908   void *mem;
       
   909 
       
   910   /* Test whether the SIZE argument is valid.  It must be a power of
       
   911      two multiple of sizeof (void *).  */
       
   912   if (alignment % sizeof (void *) != 0
       
   913       || !my_powerof2 (alignment / sizeof (void *)) != 0
       
   914       || alignment == 0)
       
   915     return EINVAL;
       
   916 
       
   917   mem = public_mEMALIGn (alignment, size);
       
   918 
       
   919   if (mem != NULL) {
       
   920     *memptr = mem;
       
   921     return 0;
       
   922   }
       
   923 
       
   924   return ENOMEM;
       
   925 }
       
   926 
       
   927 void*
       
   928 public_cALLOc(size_t n_elements, size_t elem_size)
       
   929 {
       
   930   struct malloc_arena* ar_ptr;
       
   931   size_t bytes, sz;
       
   932   void* mem;
       
   933   void * (*hook) (size_t, const void *) = __malloc_hook;
       
   934 
       
   935   /* size_t is unsigned so the behavior on overflow is defined.  */
       
   936   bytes = n_elements * elem_size;
       
   937 #define HALF_INTERNAL_SIZE_T \
       
   938   (((size_t) 1) << (8 * sizeof (size_t) / 2))
       
   939   if (__builtin_expect ((n_elements | elem_size) >= HALF_INTERNAL_SIZE_T, 0)) {
       
   940     if (elem_size != 0 && bytes / elem_size != n_elements) {
       
   941       /*MALLOC_FAILURE_ACTION;*/
       
   942       return 0;
       
   943     }
       
   944   }
       
   945 
       
   946   if (hook != NULL) {
       
   947     sz = bytes;
       
   948     mem = (*hook)(sz, RETURN_ADDRESS (0));
       
   949     if(mem == 0)
       
   950       return 0;
       
   951 #ifdef HAVE_MEMCPY
       
   952     return memset(mem, 0, sz);
       
   953 #else
       
   954     while(sz > 0) ((char*)mem)[--sz] = 0; /* rather inefficient */
       
   955     return mem;
       
   956 #endif
       
   957   }
       
   958 
       
   959   arena_get(ar_ptr, bytes + FOOTER_OVERHEAD);
       
   960   if(!ar_ptr)
       
   961     return 0;
       
   962 
       
   963   if (ar_ptr != &main_arena)
       
   964     bytes += FOOTER_OVERHEAD;
       
   965   mem = mspace_calloc(arena_to_mspace(ar_ptr), bytes, 1);
       
   966 
       
   967   if (mem && ar_ptr != &main_arena)
       
   968     set_non_main_arena(mem, ar_ptr);
       
   969   (void)mutex_unlock(&ar_ptr->mutex);
       
   970   
       
   971   assert(!mem || is_mmapped(mem2chunk(mem)) ||
       
   972 	 ar_ptr == arena_for_chunk(mem2chunk(mem)));
       
   973 
       
   974   return mem;
       
   975 }
       
   976 
       
   977 void**
       
   978 public_iCALLOc(size_t n, size_t elem_size, void* chunks[])
       
   979 {
       
   980   struct malloc_arena* ar_ptr;
       
   981   void** m;
       
   982 
       
   983   arena_get(ar_ptr, n*(elem_size + FOOTER_OVERHEAD));
       
   984   if (!ar_ptr)
       
   985     return 0;
       
   986 
       
   987   if (ar_ptr != &main_arena)
       
   988     elem_size += FOOTER_OVERHEAD;
       
   989   m = mspace_independent_calloc(arena_to_mspace(ar_ptr), n, elem_size, chunks);
       
   990 
       
   991   if (m && ar_ptr != &main_arena) {
       
   992     while (n > 0)
       
   993       set_non_main_arena(m[--n], ar_ptr);
       
   994   }
       
   995   (void)mutex_unlock(&ar_ptr->mutex);
       
   996   return m;
       
   997 }
       
   998 
       
   999 void**
       
  1000 public_iCOMALLOc(size_t n, size_t sizes[], void* chunks[])
       
  1001 {
       
  1002   struct malloc_arena* ar_ptr;
       
  1003   size_t* m_sizes;
       
  1004   size_t i;
       
  1005   void** m;
       
  1006 
       
  1007   arena_get(ar_ptr, n*sizeof(size_t));
       
  1008   if (!ar_ptr)
       
  1009     return 0;
       
  1010 
       
  1011   if (ar_ptr != &main_arena) {
       
  1012     /* Temporary m_sizes[] array is ugly but it would be surprising to
       
  1013        change the original sizes[]... */
       
  1014     m_sizes = mspace_malloc(arena_to_mspace(ar_ptr), n*sizeof(size_t));
       
  1015     if (!m_sizes) {
       
  1016       (void)mutex_unlock(&ar_ptr->mutex);
       
  1017       return 0;
       
  1018     }
       
  1019     for (i=0; i<n; ++i)
       
  1020       m_sizes[i] = sizes[i] + FOOTER_OVERHEAD;
       
  1021     if (!chunks) {
       
  1022       chunks = mspace_malloc(arena_to_mspace(ar_ptr),
       
  1023 			     n*sizeof(void*)+FOOTER_OVERHEAD);
       
  1024       if (!chunks) {
       
  1025 	mspace_free(arena_to_mspace(ar_ptr), m_sizes);
       
  1026 	(void)mutex_unlock(&ar_ptr->mutex);
       
  1027 	return 0;
       
  1028       }
       
  1029       set_non_main_arena(chunks, ar_ptr);
       
  1030     }
       
  1031   } else
       
  1032     m_sizes = sizes;
       
  1033 
       
  1034   m = mspace_independent_comalloc(arena_to_mspace(ar_ptr), n, m_sizes, chunks);
       
  1035 
       
  1036   if (ar_ptr != &main_arena) {
       
  1037     mspace_free(arena_to_mspace(ar_ptr), m_sizes);
       
  1038     if (m)
       
  1039       for (i=0; i<n; ++i)
       
  1040 	set_non_main_arena(m[i], ar_ptr);
       
  1041   }
       
  1042   (void)mutex_unlock(&ar_ptr->mutex);
       
  1043   return m;
       
  1044 }
       
  1045 
       
  1046 #if 0 && !defined _LIBC
       
  1047 
       
  1048 void
       
  1049 public_cFREe(void* m)
       
  1050 {
       
  1051   public_fREe(m);
       
  1052 }
       
  1053 
       
  1054 #endif /* _LIBC */
       
  1055 
       
  1056 int
       
  1057 public_mTRIm(size_t s)
       
  1058 {
       
  1059   int result;
       
  1060 
       
  1061   (void)mutex_lock(&main_arena.mutex);
       
  1062   result = mspace_trim(arena_to_mspace(&main_arena), s);
       
  1063   (void)mutex_unlock(&main_arena.mutex);
       
  1064   return result;
       
  1065 }
       
  1066 
       
  1067 size_t
       
  1068 public_mUSABLe(void* mem)
       
  1069 {
       
  1070   if (mem != 0) {
       
  1071     mchunkptr p = mem2chunk(mem);
       
  1072     if (cinuse(p))
       
  1073       return chunksize(p) - overhead_for(p);
       
  1074   }
       
  1075   return 0;
       
  1076 }
       
  1077 
       
  1078 int
       
  1079 public_mALLOPt(int p, int v)
       
  1080 {
       
  1081   int result;
       
  1082   result = mspace_mallopt(p, v);
       
  1083   return result;
       
  1084 }
       
  1085 
       
  1086 void
       
  1087 public_mSTATs(void)
       
  1088 {
       
  1089   int i;
       
  1090   struct malloc_arena* ar_ptr;
       
  1091   /*unsigned long in_use_b, system_b, avail_b;*/
       
  1092 #if THREAD_STATS
       
  1093   long stat_lock_direct = 0, stat_lock_loop = 0, stat_lock_wait = 0;
       
  1094 #endif
       
  1095 
       
  1096   if(__malloc_initialized < 0)
       
  1097     ptmalloc_init ();
       
  1098   for (i=0, ar_ptr = &main_arena;; ++i) {
       
  1099     struct malloc_state* msp = arena_to_mspace(ar_ptr);
       
  1100 
       
  1101     fprintf(stderr, "Arena %d:\n", i);
       
  1102     mspace_malloc_stats(msp);
       
  1103 #if THREAD_STATS
       
  1104     stat_lock_direct += ar_ptr->stat_lock_direct;
       
  1105     stat_lock_loop += ar_ptr->stat_lock_loop;
       
  1106     stat_lock_wait += ar_ptr->stat_lock_wait;
       
  1107 #endif
       
  1108     if (MALLOC_DEBUG > 1) {
       
  1109       struct malloc_segment* mseg = &msp->seg;
       
  1110       while (mseg) {
       
  1111 	fprintf(stderr, " seg %08lx-%08lx\n", (unsigned long)mseg->base,
       
  1112 		(unsigned long)(mseg->base + mseg->size));
       
  1113 	mseg = mseg->next;
       
  1114       }
       
  1115     }
       
  1116     ar_ptr = ar_ptr->next;
       
  1117     if (ar_ptr == &main_arena)
       
  1118       break;
       
  1119   }
       
  1120 #if THREAD_STATS
       
  1121   fprintf(stderr, "locked directly  = %10ld\n", stat_lock_direct);
       
  1122   fprintf(stderr, "locked in loop   = %10ld\n", stat_lock_loop);
       
  1123   fprintf(stderr, "locked waiting   = %10ld\n", stat_lock_wait);
       
  1124   fprintf(stderr, "locked total     = %10ld\n",
       
  1125           stat_lock_direct + stat_lock_loop + stat_lock_wait);
       
  1126   if (main_arena.stat_starter > 0)
       
  1127     fprintf(stderr, "starter hooks    = %10ld\n", main_arena.stat_starter);
       
  1128 #endif
       
  1129 }
       
  1130 
       
  1131 /*
       
  1132  * Local variables:
       
  1133  * c-basic-offset: 2
       
  1134  * End:
       
  1135  */