alpha: Fix all users of SYSCALL_ERROR_HANDLER
[glibc.git] / malloc / arena.c
blobb209e3b7cd4432f31b6d4ebb7eba3ec6e0124291
1 /* Malloc implementation for multiple threads without lock contention.
2 Copyright (C) 2001-2012 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Wolfram Gloger <wg@malloc.de>, 2001.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation; either version 2.1 of the
9 License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If
18 not, see <http://www.gnu.org/licenses/>. */
20 #include <stdbool.h>
22 /* Get the implementation for check_may_shrink_heap. */
23 #include <malloc-sysdep.h>
25 /* Compile-time constants. */
27 #define HEAP_MIN_SIZE (32*1024)
28 #ifndef HEAP_MAX_SIZE
29 # ifdef DEFAULT_MMAP_THRESHOLD_MAX
30 # define HEAP_MAX_SIZE (2 * DEFAULT_MMAP_THRESHOLD_MAX)
31 # else
32 # define HEAP_MAX_SIZE (1024*1024) /* must be a power of two */
33 # endif
34 #endif
36 /* HEAP_MIN_SIZE and HEAP_MAX_SIZE limit the size of mmap()ed heaps
37 that are dynamically created for multi-threaded programs. The
38 maximum size must be a power of two, for fast determination of
39 which heap belongs to a chunk. It should be much larger than the
40 mmap threshold, so that requests with a size just below that
41 threshold can be fulfilled without creating too many heaps. */
44 #ifndef THREAD_STATS
45 #define THREAD_STATS 0
46 #endif
48 /* If THREAD_STATS is non-zero, some statistics on mutex locking are
49 computed. */
51 /***************************************************************************/
53 #define top(ar_ptr) ((ar_ptr)->top)
55 /* A heap is a single contiguous memory region holding (coalesceable)
56 malloc_chunks. It is allocated with mmap() and always starts at an
57 address aligned to HEAP_MAX_SIZE. */
59 typedef struct _heap_info {
60 mstate ar_ptr; /* Arena for this heap. */
61 struct _heap_info *prev; /* Previous heap. */
62 size_t size; /* Current size in bytes. */
63 size_t mprotect_size; /* Size in bytes that has been mprotected
64 PROT_READ|PROT_WRITE. */
65 /* Make sure the following data is properly aligned, particularly
66 that sizeof (heap_info) + 2 * SIZE_SZ is a multiple of
67 MALLOC_ALIGNMENT. */
68 char pad[-6 * SIZE_SZ & MALLOC_ALIGN_MASK];
69 } heap_info;
71 /* Get a compile-time error if the heap_info padding is not correct
72 to make alignment work as expected in sYSMALLOc. */
73 extern int sanity_check_heap_info_alignment[(sizeof (heap_info)
74 + 2 * SIZE_SZ) % MALLOC_ALIGNMENT
75 ? -1 : 1];
77 /* Thread specific data */
79 static tsd_key_t arena_key;
80 static mutex_t list_lock = MUTEX_INITIALIZER;
81 #ifdef PER_THREAD
82 static size_t narenas = 1;
83 static mstate free_list;
84 #endif
86 #if THREAD_STATS
87 static int stat_n_heaps;
88 #define THREAD_STAT(x) x
89 #else
90 #define THREAD_STAT(x) do ; while(0)
91 #endif
93 /* Mapped memory in non-main arenas (reliable only for NO_THREADS). */
94 static unsigned long arena_mem;
96 /* Already initialized? */
97 int __malloc_initialized = -1;
99 /**************************************************************************/
102 /* arena_get() acquires an arena and locks the corresponding mutex.
103 First, try the one last locked successfully by this thread. (This
104 is the common case and handled with a macro for speed.) Then, loop
105 once over the circularly linked list of arenas. If no arena is
106 readily available, create a new one. In this latter case, `size'
107 is just a hint as to how much memory will be required immediately
108 in the new arena. */
110 #define arena_get(ptr, size) do { \
111 arena_lookup(ptr); \
112 arena_lock(ptr, size); \
113 } while(0)
115 #define arena_lookup(ptr) do { \
116 void *vptr = NULL; \
117 ptr = (mstate)tsd_getspecific(arena_key, vptr); \
118 } while(0)
120 #ifdef PER_THREAD
121 # define arena_lock(ptr, size) do { \
122 if(ptr) \
123 (void)mutex_lock(&ptr->mutex); \
124 else \
125 ptr = arena_get2(ptr, (size), NULL); \
126 } while(0)
127 #else
128 # define arena_lock(ptr, size) do { \
129 if(ptr && !mutex_trylock(&ptr->mutex)) { \
130 THREAD_STAT(++(ptr->stat_lock_direct)); \
131 } else \
132 ptr = arena_get2(ptr, (size), NULL); \
133 } while(0)
134 #endif
136 /* find the heap and corresponding arena for a given ptr */
138 #define heap_for_ptr(ptr) \
139 ((heap_info *)((unsigned long)(ptr) & ~(HEAP_MAX_SIZE-1)))
140 #define arena_for_chunk(ptr) \
141 (chunk_non_main_arena(ptr) ? heap_for_ptr(ptr)->ar_ptr : &main_arena)
144 /**************************************************************************/
146 #ifndef NO_THREADS
148 /* atfork support. */
150 static __malloc_ptr_t (*save_malloc_hook) (size_t __size,
151 const __malloc_ptr_t);
152 static void (*save_free_hook) (__malloc_ptr_t __ptr,
153 const __malloc_ptr_t);
154 static void* save_arena;
156 #ifdef ATFORK_MEM
157 ATFORK_MEM;
158 #endif
160 /* Magic value for the thread-specific arena pointer when
161 malloc_atfork() is in use. */
163 #define ATFORK_ARENA_PTR ((void*)-1)
165 /* The following hooks are used while the `atfork' handling mechanism
166 is active. */
168 static void*
169 malloc_atfork(size_t sz, const void *caller)
171 void *vptr = NULL;
172 void *victim;
174 tsd_getspecific(arena_key, vptr);
175 if(vptr == ATFORK_ARENA_PTR) {
176 /* We are the only thread that may allocate at all. */
177 if(save_malloc_hook != malloc_check) {
178 return _int_malloc(&main_arena, sz);
179 } else {
180 if(top_check()<0)
181 return 0;
182 victim = _int_malloc(&main_arena, sz+1);
183 return mem2mem_check(victim, sz);
185 } else {
186 /* Suspend the thread until the `atfork' handlers have completed.
187 By that time, the hooks will have been reset as well, so that
188 mALLOc() can be used again. */
189 (void)mutex_lock(&list_lock);
190 (void)mutex_unlock(&list_lock);
191 return __libc_malloc(sz);
195 static void
196 free_atfork(void* mem, const void *caller)
198 void *vptr = NULL;
199 mstate ar_ptr;
200 mchunkptr p; /* chunk corresponding to mem */
202 if (mem == 0) /* free(0) has no effect */
203 return;
205 p = mem2chunk(mem); /* do not bother to replicate free_check here */
207 if (chunk_is_mmapped(p)) /* release mmapped memory. */
209 munmap_chunk(p);
210 return;
213 ar_ptr = arena_for_chunk(p);
214 tsd_getspecific(arena_key, vptr);
215 _int_free(ar_ptr, p, vptr == ATFORK_ARENA_PTR);
219 /* Counter for number of times the list is locked by the same thread. */
220 static unsigned int atfork_recursive_cntr;
222 /* The following two functions are registered via thread_atfork() to
223 make sure that the mutexes remain in a consistent state in the
224 fork()ed version of a thread. Also adapt the malloc and free hooks
225 temporarily, because the `atfork' handler mechanism may use
226 malloc/free internally (e.g. in LinuxThreads). */
228 static void
229 ptmalloc_lock_all (void)
231 mstate ar_ptr;
233 if(__malloc_initialized < 1)
234 return;
235 if (mutex_trylock(&list_lock))
237 void *my_arena;
238 tsd_getspecific(arena_key, my_arena);
239 if (my_arena == ATFORK_ARENA_PTR)
240 /* This is the same thread which already locks the global list.
241 Just bump the counter. */
242 goto out;
244 /* This thread has to wait its turn. */
245 (void)mutex_lock(&list_lock);
247 for(ar_ptr = &main_arena;;) {
248 (void)mutex_lock(&ar_ptr->mutex);
249 ar_ptr = ar_ptr->next;
250 if(ar_ptr == &main_arena) break;
252 save_malloc_hook = __malloc_hook;
253 save_free_hook = __free_hook;
254 __malloc_hook = malloc_atfork;
255 __free_hook = free_atfork;
256 /* Only the current thread may perform malloc/free calls now. */
257 tsd_getspecific(arena_key, save_arena);
258 tsd_setspecific(arena_key, ATFORK_ARENA_PTR);
259 out:
260 ++atfork_recursive_cntr;
263 static void
264 ptmalloc_unlock_all (void)
266 mstate ar_ptr;
268 if(__malloc_initialized < 1)
269 return;
270 if (--atfork_recursive_cntr != 0)
271 return;
272 tsd_setspecific(arena_key, save_arena);
273 __malloc_hook = save_malloc_hook;
274 __free_hook = save_free_hook;
275 for(ar_ptr = &main_arena;;) {
276 (void)mutex_unlock(&ar_ptr->mutex);
277 ar_ptr = ar_ptr->next;
278 if(ar_ptr == &main_arena) break;
280 (void)mutex_unlock(&list_lock);
283 # ifdef __linux__
285 /* In NPTL, unlocking a mutex in the child process after a
286 fork() is currently unsafe, whereas re-initializing it is safe and
287 does not leak resources. Therefore, a special atfork handler is
288 installed for the child. */
290 static void
291 ptmalloc_unlock_all2 (void)
293 mstate ar_ptr;
295 if(__malloc_initialized < 1)
296 return;
297 tsd_setspecific(arena_key, save_arena);
298 __malloc_hook = save_malloc_hook;
299 __free_hook = save_free_hook;
300 #ifdef PER_THREAD
301 free_list = NULL;
302 #endif
303 for(ar_ptr = &main_arena;;) {
304 mutex_init(&ar_ptr->mutex);
305 #ifdef PER_THREAD
306 if (ar_ptr != save_arena) {
307 ar_ptr->next_free = free_list;
308 free_list = ar_ptr;
310 #endif
311 ar_ptr = ar_ptr->next;
312 if(ar_ptr == &main_arena) break;
314 mutex_init(&list_lock);
315 atfork_recursive_cntr = 0;
318 # else
320 # define ptmalloc_unlock_all2 ptmalloc_unlock_all
322 # endif
324 #endif /* !NO_THREADS */
326 /* Initialization routine. */
327 #include <string.h>
328 extern char **_environ;
330 static char *
331 internal_function
332 next_env_entry (char ***position)
334 char **current = *position;
335 char *result = NULL;
337 while (*current != NULL)
339 if (__builtin_expect ((*current)[0] == 'M', 0)
340 && (*current)[1] == 'A'
341 && (*current)[2] == 'L'
342 && (*current)[3] == 'L'
343 && (*current)[4] == 'O'
344 && (*current)[5] == 'C'
345 && (*current)[6] == '_')
347 result = &(*current)[7];
349 /* Save current position for next visit. */
350 *position = ++current;
352 break;
355 ++current;
358 return result;
362 #ifdef SHARED
363 static void *
364 __failing_morecore (ptrdiff_t d)
366 return (void *) MORECORE_FAILURE;
369 extern struct dl_open_hook *_dl_open_hook;
370 libc_hidden_proto (_dl_open_hook);
371 #endif
373 static void
374 ptmalloc_init (void)
376 if(__malloc_initialized >= 0) return;
377 __malloc_initialized = 0;
379 #ifdef SHARED
380 /* In case this libc copy is in a non-default namespace, never use brk.
381 Likewise if dlopened from statically linked program. */
382 Dl_info di;
383 struct link_map *l;
385 if (_dl_open_hook != NULL
386 || (_dl_addr (ptmalloc_init, &di, &l, NULL) != 0
387 && l->l_ns != LM_ID_BASE))
388 __morecore = __failing_morecore;
389 #endif
391 tsd_key_create(&arena_key, NULL);
392 tsd_setspecific(arena_key, (void *)&main_arena);
393 thread_atfork(ptmalloc_lock_all, ptmalloc_unlock_all, ptmalloc_unlock_all2);
394 const char *s = NULL;
395 if (__builtin_expect (_environ != NULL, 1))
397 char **runp = _environ;
398 char *envline;
400 while (__builtin_expect ((envline = next_env_entry (&runp)) != NULL,
403 size_t len = strcspn (envline, "=");
405 if (envline[len] != '=')
406 /* This is a "MALLOC_" variable at the end of the string
407 without a '=' character. Ignore it since otherwise we
408 will access invalid memory below. */
409 continue;
411 switch (len)
413 case 6:
414 if (memcmp (envline, "CHECK_", 6) == 0)
415 s = &envline[7];
416 break;
417 case 8:
418 if (! __builtin_expect (__libc_enable_secure, 0))
420 if (memcmp (envline, "TOP_PAD_", 8) == 0)
421 __libc_mallopt(M_TOP_PAD, atoi(&envline[9]));
422 else if (memcmp (envline, "PERTURB_", 8) == 0)
423 __libc_mallopt(M_PERTURB, atoi(&envline[9]));
425 break;
426 case 9:
427 if (! __builtin_expect (__libc_enable_secure, 0))
429 if (memcmp (envline, "MMAP_MAX_", 9) == 0)
430 __libc_mallopt(M_MMAP_MAX, atoi(&envline[10]));
431 #ifdef PER_THREAD
432 else if (memcmp (envline, "ARENA_MAX", 9) == 0)
433 __libc_mallopt(M_ARENA_MAX, atoi(&envline[10]));
434 #endif
436 break;
437 #ifdef PER_THREAD
438 case 10:
439 if (! __builtin_expect (__libc_enable_secure, 0))
441 if (memcmp (envline, "ARENA_TEST", 10) == 0)
442 __libc_mallopt(M_ARENA_TEST, atoi(&envline[11]));
444 break;
445 #endif
446 case 15:
447 if (! __builtin_expect (__libc_enable_secure, 0))
449 if (memcmp (envline, "TRIM_THRESHOLD_", 15) == 0)
450 __libc_mallopt(M_TRIM_THRESHOLD, atoi(&envline[16]));
451 else if (memcmp (envline, "MMAP_THRESHOLD_", 15) == 0)
452 __libc_mallopt(M_MMAP_THRESHOLD, atoi(&envline[16]));
454 break;
455 default:
456 break;
460 if(s && s[0]) {
461 __libc_mallopt(M_CHECK_ACTION, (int)(s[0] - '0'));
462 if (check_action != 0)
463 __malloc_check_init();
465 void (*hook) (void) = force_reg (__malloc_initialize_hook);
466 if (hook != NULL)
467 (*hook)();
468 __malloc_initialized = 1;
471 /* There are platforms (e.g. Hurd) with a link-time hook mechanism. */
472 #ifdef thread_atfork_static
473 thread_atfork_static(ptmalloc_lock_all, ptmalloc_unlock_all, \
474 ptmalloc_unlock_all2)
475 #endif
479 /* Managing heaps and arenas (for concurrent threads) */
481 #if MALLOC_DEBUG > 1
483 /* Print the complete contents of a single heap to stderr. */
485 static void
486 dump_heap(heap_info *heap)
488 char *ptr;
489 mchunkptr p;
491 fprintf(stderr, "Heap %p, size %10lx:\n", heap, (long)heap->size);
492 ptr = (heap->ar_ptr != (mstate)(heap+1)) ?
493 (char*)(heap + 1) : (char*)(heap + 1) + sizeof(struct malloc_state);
494 p = (mchunkptr)(((unsigned long)ptr + MALLOC_ALIGN_MASK) &
495 ~MALLOC_ALIGN_MASK);
496 for(;;) {
497 fprintf(stderr, "chunk %p size %10lx", p, (long)p->size);
498 if(p == top(heap->ar_ptr)) {
499 fprintf(stderr, " (top)\n");
500 break;
501 } else if(p->size == (0|PREV_INUSE)) {
502 fprintf(stderr, " (fence)\n");
503 break;
505 fprintf(stderr, "\n");
506 p = next_chunk(p);
510 #endif /* MALLOC_DEBUG > 1 */
512 /* If consecutive mmap (0, HEAP_MAX_SIZE << 1, ...) calls return decreasing
513 addresses as opposed to increasing, new_heap would badly fragment the
514 address space. In that case remember the second HEAP_MAX_SIZE part
515 aligned to HEAP_MAX_SIZE from last mmap (0, HEAP_MAX_SIZE << 1, ...)
516 call (if it is already aligned) and try to reuse it next time. We need
517 no locking for it, as kernel ensures the atomicity for us - worst case
518 we'll call mmap (addr, HEAP_MAX_SIZE, ...) for some value of addr in
519 multiple threads, but only one will succeed. */
520 static char *aligned_heap_area;
522 /* Create a new heap. size is automatically rounded up to a multiple
523 of the page size. */
525 static heap_info *
526 internal_function
527 new_heap(size_t size, size_t top_pad)
529 size_t page_mask = GLRO(dl_pagesize) - 1;
530 char *p1, *p2;
531 unsigned long ul;
532 heap_info *h;
534 if(size+top_pad < HEAP_MIN_SIZE)
535 size = HEAP_MIN_SIZE;
536 else if(size+top_pad <= HEAP_MAX_SIZE)
537 size += top_pad;
538 else if(size > HEAP_MAX_SIZE)
539 return 0;
540 else
541 size = HEAP_MAX_SIZE;
542 size = (size + page_mask) & ~page_mask;
544 /* A memory region aligned to a multiple of HEAP_MAX_SIZE is needed.
545 No swap space needs to be reserved for the following large
546 mapping (on Linux, this is the case for all non-writable mappings
547 anyway). */
548 p2 = MAP_FAILED;
549 if(aligned_heap_area) {
550 p2 = (char *)MMAP(aligned_heap_area, HEAP_MAX_SIZE, PROT_NONE,
551 MAP_NORESERVE);
552 aligned_heap_area = NULL;
553 if (p2 != MAP_FAILED && ((unsigned long)p2 & (HEAP_MAX_SIZE-1))) {
554 __munmap(p2, HEAP_MAX_SIZE);
555 p2 = MAP_FAILED;
558 if(p2 == MAP_FAILED) {
559 p1 = (char *)MMAP(0, HEAP_MAX_SIZE<<1, PROT_NONE, MAP_NORESERVE);
560 if(p1 != MAP_FAILED) {
561 p2 = (char *)(((unsigned long)p1 + (HEAP_MAX_SIZE-1))
562 & ~(HEAP_MAX_SIZE-1));
563 ul = p2 - p1;
564 if (ul)
565 __munmap(p1, ul);
566 else
567 aligned_heap_area = p2 + HEAP_MAX_SIZE;
568 __munmap(p2 + HEAP_MAX_SIZE, HEAP_MAX_SIZE - ul);
569 } else {
570 /* Try to take the chance that an allocation of only HEAP_MAX_SIZE
571 is already aligned. */
572 p2 = (char *)MMAP(0, HEAP_MAX_SIZE, PROT_NONE, MAP_NORESERVE);
573 if(p2 == MAP_FAILED)
574 return 0;
575 if((unsigned long)p2 & (HEAP_MAX_SIZE-1)) {
576 __munmap(p2, HEAP_MAX_SIZE);
577 return 0;
581 if(__mprotect(p2, size, PROT_READ|PROT_WRITE) != 0) {
582 __munmap(p2, HEAP_MAX_SIZE);
583 return 0;
585 h = (heap_info *)p2;
586 h->size = size;
587 h->mprotect_size = size;
588 THREAD_STAT(stat_n_heaps++);
589 return h;
592 /* Grow a heap. size is automatically rounded up to a
593 multiple of the page size. */
595 static int
596 grow_heap(heap_info *h, long diff)
598 size_t page_mask = GLRO(dl_pagesize) - 1;
599 long new_size;
601 diff = (diff + page_mask) & ~page_mask;
602 new_size = (long)h->size + diff;
603 if((unsigned long) new_size > (unsigned long) HEAP_MAX_SIZE)
604 return -1;
605 if((unsigned long) new_size > h->mprotect_size) {
606 if (__mprotect((char *)h + h->mprotect_size,
607 (unsigned long) new_size - h->mprotect_size,
608 PROT_READ|PROT_WRITE) != 0)
609 return -2;
610 h->mprotect_size = new_size;
613 h->size = new_size;
614 return 0;
617 /* Shrink a heap. */
619 static int
620 shrink_heap(heap_info *h, long diff)
622 long new_size;
624 new_size = (long)h->size - diff;
625 if(new_size < (long)sizeof(*h))
626 return -1;
627 /* Try to re-map the extra heap space freshly to save memory, and make it
628 inaccessible. See malloc-sysdep.h to know when this is true. */
629 if (__builtin_expect (check_may_shrink_heap (), 0))
631 if((char *)MMAP((char *)h + new_size, diff, PROT_NONE,
632 MAP_FIXED) == (char *) MAP_FAILED)
633 return -2;
634 h->mprotect_size = new_size;
636 else
637 madvise ((char *)h + new_size, diff, MADV_DONTNEED);
638 /*fprintf(stderr, "shrink %p %08lx\n", h, new_size);*/
640 h->size = new_size;
641 return 0;
644 /* Delete a heap. */
646 #define delete_heap(heap) \
647 do { \
648 if ((char *)(heap) + HEAP_MAX_SIZE == aligned_heap_area) \
649 aligned_heap_area = NULL; \
650 __munmap((char*)(heap), HEAP_MAX_SIZE); \
651 } while (0)
653 static int
654 internal_function
655 heap_trim(heap_info *heap, size_t pad)
657 mstate ar_ptr = heap->ar_ptr;
658 unsigned long pagesz = GLRO(dl_pagesize);
659 mchunkptr top_chunk = top(ar_ptr), p, bck, fwd;
660 heap_info *prev_heap;
661 long new_size, top_size, extra, prev_size, misalign;
663 /* Can this heap go away completely? */
664 while(top_chunk == chunk_at_offset(heap, sizeof(*heap))) {
665 prev_heap = heap->prev;
666 prev_size = prev_heap->size - (MINSIZE-2*SIZE_SZ);
667 p = chunk_at_offset(prev_heap, prev_size);
668 /* fencepost must be properly aligned. */
669 misalign = ((long) p) & MALLOC_ALIGN_MASK;
670 p = chunk_at_offset(prev_heap, prev_size - misalign);
671 assert(p->size == (0|PREV_INUSE)); /* must be fencepost */
672 p = prev_chunk(p);
673 new_size = chunksize(p) + (MINSIZE-2*SIZE_SZ) + misalign;
674 assert(new_size>0 && new_size<(long)(2*MINSIZE));
675 if(!prev_inuse(p))
676 new_size += p->prev_size;
677 assert(new_size>0 && new_size<HEAP_MAX_SIZE);
678 if(new_size + (HEAP_MAX_SIZE - prev_heap->size) < pad + MINSIZE + pagesz)
679 break;
680 ar_ptr->system_mem -= heap->size;
681 arena_mem -= heap->size;
682 delete_heap(heap);
683 heap = prev_heap;
684 if(!prev_inuse(p)) { /* consolidate backward */
685 p = prev_chunk(p);
686 unlink(p, bck, fwd);
688 assert(((unsigned long)((char*)p + new_size) & (pagesz-1)) == 0);
689 assert( ((char*)p + new_size) == ((char*)heap + heap->size) );
690 top(ar_ptr) = top_chunk = p;
691 set_head(top_chunk, new_size | PREV_INUSE);
692 /*check_chunk(ar_ptr, top_chunk);*/
694 top_size = chunksize(top_chunk);
695 extra = (top_size - pad - MINSIZE - 1) & ~(pagesz - 1);
696 if(extra < (long)pagesz)
697 return 0;
698 /* Try to shrink. */
699 if(shrink_heap(heap, extra) != 0)
700 return 0;
701 ar_ptr->system_mem -= extra;
702 arena_mem -= extra;
704 /* Success. Adjust top accordingly. */
705 set_head(top_chunk, (top_size - extra) | PREV_INUSE);
706 /*check_chunk(ar_ptr, top_chunk);*/
707 return 1;
710 /* Create a new arena with initial size "size". */
712 static mstate
713 _int_new_arena(size_t size)
715 mstate a;
716 heap_info *h;
717 char *ptr;
718 unsigned long misalign;
720 h = new_heap(size + (sizeof(*h) + sizeof(*a) + MALLOC_ALIGNMENT),
721 mp_.top_pad);
722 if(!h) {
723 /* Maybe size is too large to fit in a single heap. So, just try
724 to create a minimally-sized arena and let _int_malloc() attempt
725 to deal with the large request via mmap_chunk(). */
726 h = new_heap(sizeof(*h) + sizeof(*a) + MALLOC_ALIGNMENT, mp_.top_pad);
727 if(!h)
728 return 0;
730 a = h->ar_ptr = (mstate)(h+1);
731 malloc_init_state(a);
732 /*a->next = NULL;*/
733 a->system_mem = a->max_system_mem = h->size;
734 arena_mem += h->size;
736 /* Set up the top chunk, with proper alignment. */
737 ptr = (char *)(a + 1);
738 misalign = (unsigned long)chunk2mem(ptr) & MALLOC_ALIGN_MASK;
739 if (misalign > 0)
740 ptr += MALLOC_ALIGNMENT - misalign;
741 top(a) = (mchunkptr)ptr;
742 set_head(top(a), (((char*)h + h->size) - ptr) | PREV_INUSE);
744 tsd_setspecific(arena_key, (void *)a);
745 mutex_init(&a->mutex);
746 (void)mutex_lock(&a->mutex);
748 #ifdef PER_THREAD
749 (void)mutex_lock(&list_lock);
750 #endif
752 /* Add the new arena to the global list. */
753 a->next = main_arena.next;
754 atomic_write_barrier ();
755 main_arena.next = a;
757 #ifdef PER_THREAD
758 (void)mutex_unlock(&list_lock);
759 #endif
761 THREAD_STAT(++(a->stat_lock_loop));
763 return a;
767 #ifdef PER_THREAD
768 static mstate
769 get_free_list (void)
771 mstate result = free_list;
772 if (result != NULL)
774 (void)mutex_lock(&list_lock);
775 result = free_list;
776 if (result != NULL)
777 free_list = result->next_free;
778 (void)mutex_unlock(&list_lock);
780 if (result != NULL)
782 (void)mutex_lock(&result->mutex);
783 tsd_setspecific(arena_key, (void *)result);
784 THREAD_STAT(++(result->stat_lock_loop));
788 return result;
791 /* Lock and return an arena that can be reused for memory allocation.
792 Avoid AVOID_ARENA as we have already failed to allocate memory in
793 it and it is currently locked. */
794 static mstate
795 reused_arena (mstate avoid_arena)
797 mstate result;
798 static mstate next_to_use;
799 if (next_to_use == NULL)
800 next_to_use = &main_arena;
802 result = next_to_use;
805 if (!mutex_trylock(&result->mutex))
806 goto out;
808 result = result->next;
810 while (result != next_to_use);
812 /* Avoid AVOID_ARENA as we have already failed to allocate memory
813 in that arena and it is currently locked. */
814 if (result == avoid_arena)
815 result = result->next;
817 /* No arena available. Wait for the next in line. */
818 (void)mutex_lock(&result->mutex);
820 out:
821 tsd_setspecific(arena_key, (void *)result);
822 THREAD_STAT(++(result->stat_lock_loop));
823 next_to_use = result->next;
825 return result;
827 #endif
829 static mstate
830 internal_function
831 arena_get2(mstate a_tsd, size_t size, mstate avoid_arena)
833 mstate a;
835 #ifdef PER_THREAD
836 static size_t narenas_limit;
838 a = get_free_list ();
839 if (a == NULL)
841 /* Nothing immediately available, so generate a new arena. */
842 if (narenas_limit == 0)
844 if (mp_.arena_max != 0)
845 narenas_limit = mp_.arena_max;
846 else if (narenas > mp_.arena_test)
848 int n = __get_nprocs ();
850 if (n >= 1)
851 narenas_limit = NARENAS_FROM_NCORES (n);
852 else
853 /* We have no information about the system. Assume two
854 cores. */
855 narenas_limit = NARENAS_FROM_NCORES (2);
858 repeat:;
859 size_t n = narenas;
860 /* NB: the following depends on the fact that (size_t)0 - 1 is a
861 very large number and that the underflow is OK. If arena_max
862 is set the value of arena_test is irrelevant. If arena_test
863 is set but narenas is not yet larger or equal to arena_test
864 narenas_limit is 0. There is no possibility for narenas to
865 be too big for the test to always fail since there is not
866 enough address space to create that many arenas. */
867 if (__builtin_expect (n <= narenas_limit - 1, 0))
869 if (catomic_compare_and_exchange_bool_acq (&narenas, n + 1, n))
870 goto repeat;
871 a = _int_new_arena (size);
872 if (__builtin_expect (a == NULL, 0))
873 catomic_decrement (&narenas);
875 else
876 a = reused_arena (avoid_arena);
878 #else
879 if(!a_tsd)
880 a = a_tsd = &main_arena;
881 else {
882 a = a_tsd->next;
883 if(!a) {
884 /* This can only happen while initializing the new arena. */
885 (void)mutex_lock(&main_arena.mutex);
886 THREAD_STAT(++(main_arena.stat_lock_wait));
887 return &main_arena;
891 /* Check the global, circularly linked list for available arenas. */
892 bool retried = false;
893 repeat:
894 do {
895 if(!mutex_trylock(&a->mutex)) {
896 if (retried)
897 (void)mutex_unlock(&list_lock);
898 THREAD_STAT(++(a->stat_lock_loop));
899 tsd_setspecific(arena_key, (void *)a);
900 return a;
902 a = a->next;
903 } while(a != a_tsd);
905 /* If not even the list_lock can be obtained, try again. This can
906 happen during `atfork', or for example on systems where thread
907 creation makes it temporarily impossible to obtain _any_
908 locks. */
909 if(!retried && mutex_trylock(&list_lock)) {
910 /* We will block to not run in a busy loop. */
911 (void)mutex_lock(&list_lock);
913 /* Since we blocked there might be an arena available now. */
914 retried = true;
915 a = a_tsd;
916 goto repeat;
919 /* Nothing immediately available, so generate a new arena. */
920 a = _int_new_arena(size);
921 (void)mutex_unlock(&list_lock);
922 #endif
924 return a;
927 /* If we don't have the main arena, then maybe the failure is due to running
928 out of mmapped areas, so we can try allocating on the main arena.
929 Otherwise, it is likely that sbrk() has failed and there is still a chance
930 to mmap(), so try one of the other arenas. */
931 static mstate
932 arena_get_retry (mstate ar_ptr, size_t bytes)
934 if(ar_ptr != &main_arena) {
935 (void)mutex_unlock(&ar_ptr->mutex);
936 ar_ptr = &main_arena;
937 (void)mutex_lock(&ar_ptr->mutex);
938 } else {
939 /* Grab ar_ptr->next prior to releasing its lock. */
940 mstate prev = ar_ptr->next ? ar_ptr : 0;
941 (void)mutex_unlock(&ar_ptr->mutex);
942 ar_ptr = arena_get2(prev, bytes, ar_ptr);
945 return ar_ptr;
948 #ifdef PER_THREAD
949 static void __attribute__ ((section ("__libc_thread_freeres_fn")))
950 arena_thread_freeres (void)
952 void *vptr = NULL;
953 mstate a = tsd_getspecific(arena_key, vptr);
954 tsd_setspecific(arena_key, NULL);
956 if (a != NULL)
958 (void)mutex_lock(&list_lock);
959 a->next_free = free_list;
960 free_list = a;
961 (void)mutex_unlock(&list_lock);
964 text_set_element (__libc_thread_subfreeres, arena_thread_freeres);
965 #endif
968 * Local variables:
969 * c-basic-offset: 2
970 * End: