arena.c revision 232809
174131Sjlemon/*
274131SjlemonCopyright (c) 2001 Wolfram Gloger
374131SjlemonCopyright (c) 2006 Cavium networks
474131Sjlemon
574131SjlemonPermission to use, copy, modify, distribute, and sell this software
674131Sjlemonand its documentation for any purpose is hereby granted without fee,
774131Sjlemonprovided that (i) the above copyright notices and this permission
874131Sjlemonnotice appear in all copies of the software and related documentation,
974131Sjlemonand (ii) the name of Wolfram Gloger may not be used in any advertising
1074131Sjlemonor publicity relating to the software.
1174131Sjlemon
1274131SjlemonTHE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
1374131SjlemonEXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
1474131SjlemonWARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
1574131Sjlemon
1674131SjlemonIN NO EVENT SHALL WOLFRAM GLOGER BE LIABLE FOR ANY SPECIAL,
1774131SjlemonINCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY
1874131SjlemonDAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1974131SjlemonWHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY
2074131SjlemonOF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
2174131SjlemonPERFORMANCE OF THIS SOFTWARE.
2274131Sjlemon*/
2374131Sjlemon
2474131Sjlemon/* $Id: arena.c 30481 2007-12-05 21:46:59Z rfranz $ */
2574131Sjlemon
2674131Sjlemon/* Compile-time constants.  */
2774131Sjlemon
2874131Sjlemon#define HEAP_MIN_SIZE (4096)   /* Must leave room for struct malloc_state, arena ptrs, etc., totals about 2400 bytes */
2974131Sjlemon
3074131Sjlemon#ifndef THREAD_STATS
3174131Sjlemon#define THREAD_STATS 0
32226154Smarius#endif
33226154Smarius
34226154Smarius/* If THREAD_STATS is non-zero, some statistics on mutex locking are
35226154Smarius   computed.  */
36226154Smarius
37226154Smarius/***************************************************************************/
38226154Smarius
39226154Smarius// made static to avoid conflicts with newlib
40226154Smariusstatic mstate         _int_new_arena __MALLOC_P ((size_t __ini_size));
41
42/***************************************************************************/
43
44#define top(ar_ptr) ((ar_ptr)->top)
45
46/* A heap is a single contiguous memory region holding (coalesceable)
47   malloc_chunks.    Not used unless compiling with
48   USE_ARENAS. */
49
50typedef struct _heap_info {
51  mstate ar_ptr; /* Arena for this heap. */
52  struct _heap_info *prev; /* Previous heap. */
53  size_t size;   /* Current size in bytes. */
54  size_t pad;    /* Make sure the following data is properly aligned. */
55} heap_info;
56
57/* Thread specific data */
58
59static tsd_key_t arena_key;  // one per PP (thread)
60static CVMX_SHARED mutex_t list_lock;  // shared...
61
62#if THREAD_STATS
63static int stat_n_heaps;
64#define THREAD_STAT(x) x
65#else
66#define THREAD_STAT(x) do ; while(0)
67#endif
68
69/* Mapped memory in non-main arenas (reliable only for NO_THREADS). */
70static unsigned long arena_mem;
71
72/* Already initialized? */
73int CVMX_SHARED cvmx__malloc_initialized = -1;
74
75/**************************************************************************/
76
77#if USE_ARENAS
78
79/* find the heap and corresponding arena for a given ptr */
80
81#define arena_for_chunk(ptr) ((ptr)->arena_ptr)
82#define set_arena_for_chunk(ptr, arena) (ptr)->arena_ptr = (arena)
83
84
85#endif /* USE_ARENAS */
86
87/**************************************************************************/
88
89#ifndef NO_THREADS
90
91/* atfork support.  */
92
93static __malloc_ptr_t (*save_malloc_hook) __MALLOC_P ((size_t __size,
94						       __const __malloc_ptr_t));
95static void           (*save_free_hook) __MALLOC_P ((__malloc_ptr_t __ptr,
96						     __const __malloc_ptr_t));
97static Void_t*        save_arena;
98
99/* Magic value for the thread-specific arena pointer when
100   malloc_atfork() is in use.  */
101
102#define ATFORK_ARENA_PTR ((Void_t*)-1)
103
104/* The following hooks are used while the `atfork' handling mechanism
105   is active. */
106
107static Void_t*
108malloc_atfork(size_t sz, const Void_t *caller)
109{
110return(NULL);
111}
112
113static void
114free_atfork(Void_t* mem, const Void_t *caller)
115{
116  Void_t *vptr = NULL;
117  mstate ar_ptr;
118  mchunkptr p;                          /* chunk corresponding to mem */
119
120  if (mem == 0)                              /* free(0) has no effect */
121    return;
122
123  p = mem2chunk(mem);         /* do not bother to replicate free_check here */
124
125#if HAVE_MMAP
126  if (chunk_is_mmapped(p))                       /* release mmapped memory. */
127  {
128    munmap_chunk(p);
129    return;
130  }
131#endif
132
133  ar_ptr = arena_for_chunk(p);
134  tsd_getspecific(arena_key, vptr);
135  if(vptr != ATFORK_ARENA_PTR)
136    (void)mutex_lock(&ar_ptr->mutex);
137  _int_free(ar_ptr, mem);
138  if(vptr != ATFORK_ARENA_PTR)
139    (void)mutex_unlock(&ar_ptr->mutex);
140}
141
142
143
144#ifdef __linux__
145#error   __linux__defined!
146#endif
147
148#endif /* !defined NO_THREADS */
149
150
151
152/* Initialization routine. */
153#ifdef _LIBC
154#error  _LIBC is defined, and should not be
155#endif /* _LIBC */
156
157static CVMX_SHARED cvmx_spinlock_t malloc_init_spin_lock;
158
159
160
161
162/* Managing heaps and arenas (for concurrent threads) */
163
164#if USE_ARENAS
165
166#if MALLOC_DEBUG > 1
167
168/* Print the complete contents of a single heap to stderr. */
169
170static void
171#if __STD_C
172dump_heap(heap_info *heap)
173#else
174dump_heap(heap) heap_info *heap;
175#endif
176{
177  char *ptr;
178  mchunkptr p;
179
180  fprintf(stderr, "Heap %p, size %10lx:\n", heap, (long)heap->size);
181  ptr = (heap->ar_ptr != (mstate)(heap+1)) ?
182    (char*)(heap + 1) : (char*)(heap + 1) + sizeof(struct malloc_state);
183  p = (mchunkptr)(((unsigned long)ptr + MALLOC_ALIGN_MASK) &
184                  ~MALLOC_ALIGN_MASK);
185  for(;;) {
186    fprintf(stderr, "chunk %p size %10lx", p, (long)p->size);
187    if(p == top(heap->ar_ptr)) {
188      fprintf(stderr, " (top)\n");
189      break;
190    } else if(p->size == (0|PREV_INUSE)) {
191      fprintf(stderr, " (fence)\n");
192      break;
193    }
194    fprintf(stderr, "\n");
195    p = next_chunk(p);
196  }
197}
198
199#endif /* MALLOC_DEBUG > 1 */
200/* Delete a heap. */
201
202
203static mstate cvmx_new_arena(void *addr, size_t size)
204{
205  mstate a;
206  heap_info *h;
207  char *ptr;
208  unsigned long misalign;
209  int page_mask = malloc_getpagesize - 1;
210
211  debug_printf("cvmx_new_arena called, addr: %p, size %ld\n", addr, size);
212  debug_printf("heapinfo size: %ld, mstate size: %d\n", sizeof(heap_info), sizeof(struct malloc_state));
213
214  if (!addr || (size < HEAP_MIN_SIZE))
215  {
216      return(NULL);
217  }
218  /* We must zero out the arena as the malloc code assumes this. */
219  memset(addr, 0, size);
220
221  h = (heap_info *)addr;
222  h->size = size;
223
224  a = h->ar_ptr = (mstate)(h+1);
225  malloc_init_state(a);
226  /*a->next = NULL;*/
227  a->system_mem = a->max_system_mem = h->size;
228  arena_mem += h->size;
229  a->next = a;
230
231  /* Set up the top chunk, with proper alignment. */
232  ptr = (char *)(a + 1);
233  misalign = (unsigned long)chunk2mem(ptr) & MALLOC_ALIGN_MASK;
234  if (misalign > 0)
235    ptr += MALLOC_ALIGNMENT - misalign;
236  top(a) = (mchunkptr)ptr;
237  set_head(top(a), (((char*)h + h->size) - ptr) | PREV_INUSE);
238
239  return a;
240}
241
242
243int cvmx_add_arena(cvmx_arena_list_t *arena_list, void *ptr, size_t size)
244{
245  mstate a;
246
247  /* Enforce required alignement, and adjust size */
248  int misaligned = ((size_t)ptr) & (MALLOC_ALIGNMENT - 1);
249  if (misaligned)
250  {
251      ptr = (char*)ptr + MALLOC_ALIGNMENT - misaligned;
252      size -= MALLOC_ALIGNMENT - misaligned;
253  }
254
255  debug_printf("Adding arena at addr: %p, size %d\n", ptr, size);
256
257  a = cvmx_new_arena(ptr, size);  /* checks ptr and size */
258  if (!a)
259  {
260      return(-1);
261  }
262
263  debug_printf("cmvx_add_arena - arena_list: %p, *arena_list: %p\n", arena_list, *arena_list);
264  debug_printf("cmvx_add_arena - list: %p, new: %p\n", *arena_list, a);
265  mutex_init(&a->mutex);
266  mutex_lock(&a->mutex);
267
268
269  if (*arena_list)
270  {
271      mstate ar_ptr = *arena_list;
272      (void)mutex_lock(&ar_ptr->mutex);
273      a->next = ar_ptr->next;  // lock held on a and ar_ptr
274      ar_ptr->next = a;
275      (void)mutex_unlock(&ar_ptr->mutex);
276  }
277  else
278  {
279      *arena_list = a;
280//      a->next = a;
281  }
282
283  debug_printf("cvmx_add_arena - list: %p, list->next: %p\n", *arena_list, ((mstate)*arena_list)->next);
284
285  // unlock, since it is not going to be used immediately
286  (void)mutex_unlock(&a->mutex);
287
288  return(0);
289}
290
291
292
293#endif /* USE_ARENAS */
294