165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm/* libunwind - a platform-independent unwind library
2b38691980f4e0c1cf0e2309aa6cc35decc6b9cb7hp.com!davidm   Copyright (C) 2002-2003, 2005 Hewlett-Packard Co
365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm	Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
426fc1563fba945d0356e4a7dd935a6a57b3c03dbTommi Rantala   Copyright (C) 2012 Tommi Rantala <tt.rantala@gmail.com>
565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmThis file is part of libunwind.
765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmPermission is hereby granted, free of charge, to any person obtaining
965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidma copy of this software and associated documentation files (the
1065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm"Software"), to deal in the Software without restriction, including
1165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmwithout limitation the rights to use, copy, modify, merge, publish,
1265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmdistribute, sublicense, and/or sell copies of the Software, and to
1365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmpermit persons to whom the Software is furnished to do so, subject to
1465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmthe following conditions:
1565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
1665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmThe above copyright notice and this permission notice shall be
1765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmincluded in all copies or substantial portions of the Software.
1865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
1965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
2365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
2465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
2565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
2665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
27670dd57e827a3583a9284634cf1244eb8cab4795hp.com!davidm#include "libunwind_i.h"
2865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
29e6edad069c95127383a8122608a6bd3785413204Tommi Rantala/* From GCC docs: ``Gcc also provides a target specific macro
30e6edad069c95127383a8122608a6bd3785413204Tommi Rantala * __BIGGEST_ALIGNMENT__, which is the largest alignment ever used for any data
31e6edad069c95127383a8122608a6bd3785413204Tommi Rantala * type on the target machine you are compiling for.'' */
32e6edad069c95127383a8122608a6bd3785413204Tommi Rantala#ifdef __BIGGEST_ALIGNMENT__
33e6edad069c95127383a8122608a6bd3785413204Tommi Rantala# define MAX_ALIGN	__BIGGEST_ALIGNMENT__
34e6edad069c95127383a8122608a6bd3785413204Tommi Rantala#else
35c36a14f24507a3fd988430eba872ded895ed6913Tommi Rantala/* Crude hack to check that MAX_ALIGN is power-of-two.
36c36a14f24507a3fd988430eba872ded895ed6913Tommi Rantala * sizeof(long double) = 12 on i386. */
37c36a14f24507a3fd988430eba872ded895ed6913Tommi Rantala# define MAX_ALIGN_(n)	(n < 8 ? 8 : \
38c36a14f24507a3fd988430eba872ded895ed6913Tommi Rantala			 n < 16 ? 16 : n)
39c36a14f24507a3fd988430eba872ded895ed6913Tommi Rantala# define MAX_ALIGN	MAX_ALIGN_(sizeof (long double))
40e6edad069c95127383a8122608a6bd3785413204Tommi Rantala#endif
4165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
4226fc1563fba945d0356e4a7dd935a6a57b3c03dbTommi Rantalastatic char sos_memory[SOS_MEMORY_SIZE] ALIGNED(MAX_ALIGN);
439a3565ddc1e956ef1f52806093e949c7809f6e79Tommi Rantalastatic size_t sos_memory_freepos;
4465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmstatic size_t pg_size;
4565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
4665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmHIDDEN void *
4765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmsos_alloc (size_t size)
4865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm{
499a3565ddc1e956ef1f52806093e949c7809f6e79Tommi Rantala  size_t pos;
5065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
51c2f7574187cfbb36dbcdc85bc61a027a4025f394Tommi Rantala  size = UNW_ALIGN(size, MAX_ALIGN);
5265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
53cb3fbbb1729254e9a49e3f8fbe1cadbd519ece52Arun Sharma#if defined(__GNUC__) && defined(HAVE_FETCH_AND_ADD)
549a3565ddc1e956ef1f52806093e949c7809f6e79Tommi Rantala  /* Assume `sos_memory' is suitably aligned. */
559a3565ddc1e956ef1f52806093e949c7809f6e79Tommi Rantala  assert(((uintptr_t) &sos_memory[0] & (MAX_ALIGN-1)) == 0);
569a3565ddc1e956ef1f52806093e949c7809f6e79Tommi Rantala
579a3565ddc1e956ef1f52806093e949c7809f6e79Tommi Rantala  pos = fetch_and_add (&sos_memory_freepos, size);
5865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm#else
59b38691980f4e0c1cf0e2309aa6cc35decc6b9cb7hp.com!davidm  static define_lock (sos_lock);
60b38691980f4e0c1cf0e2309aa6cc35decc6b9cb7hp.com!davidm  intrmask_t saved_mask;
6165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
62b38691980f4e0c1cf0e2309aa6cc35decc6b9cb7hp.com!davidm  lock_acquire (&sos_lock, saved_mask);
6365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm  {
649a3565ddc1e956ef1f52806093e949c7809f6e79Tommi Rantala    /* No assumptions about `sos_memory' alignment. */
659a3565ddc1e956ef1f52806093e949c7809f6e79Tommi Rantala    if (sos_memory_freepos == 0)
669a3565ddc1e956ef1f52806093e949c7809f6e79Tommi Rantala      {
679a3565ddc1e956ef1f52806093e949c7809f6e79Tommi Rantala	unsigned align = UNW_ALIGN((uintptr_t) &sos_memory[0], MAX_ALIGN)
689a3565ddc1e956ef1f52806093e949c7809f6e79Tommi Rantala				- (uintptr_t) &sos_memory[0];
699a3565ddc1e956ef1f52806093e949c7809f6e79Tommi Rantala	sos_memory_freepos = align;
709a3565ddc1e956ef1f52806093e949c7809f6e79Tommi Rantala      }
719a3565ddc1e956ef1f52806093e949c7809f6e79Tommi Rantala    pos = sos_memory_freepos;
729a3565ddc1e956ef1f52806093e949c7809f6e79Tommi Rantala    sos_memory_freepos += size;
7365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm  }
74670dd57e827a3583a9284634cf1244eb8cab4795hp.com!davidm  lock_release (&sos_lock, saved_mask);
7565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm#endif
769a3565ddc1e956ef1f52806093e949c7809f6e79Tommi Rantala
779a3565ddc1e956ef1f52806093e949c7809f6e79Tommi Rantala  assert (((uintptr_t) &sos_memory[pos] & (MAX_ALIGN-1)) == 0);
789a3565ddc1e956ef1f52806093e949c7809f6e79Tommi Rantala  assert ((pos+size) <= SOS_MEMORY_SIZE);
799a3565ddc1e956ef1f52806093e949c7809f6e79Tommi Rantala
809a3565ddc1e956ef1f52806093e949c7809f6e79Tommi Rantala  return &sos_memory[pos];
8165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm}
8265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
8365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm/* Must be called while holding the mempool lock. */
8465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
8565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmstatic void
8665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmfree_object (struct mempool *pool, void *object)
8765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm{
8865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm  struct object *obj = object;
8965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
9065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm  obj->next = pool->free_list;
9165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm  pool->free_list = obj;
9265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm  ++pool->num_free;
9365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm}
9465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
9565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmstatic void
9665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmadd_memory (struct mempool *pool, char *mem, size_t size, size_t obj_size)
9765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm{
9865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm  char *obj;
9965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
10058badbb3393efc20f87a0ca462c5ba463eb3e8bamostang.com!davidm  for (obj = mem; obj <= mem + size - obj_size; obj += obj_size)
10165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm    free_object (pool, obj);
10265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm}
10365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
10465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmstatic void
10565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmexpand (struct mempool *pool)
10665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm{
10765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm  size_t size;
10865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm  char *mem;
10965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
11065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm  size = pool->chunk_size;
111b38691980f4e0c1cf0e2309aa6cc35decc6b9cb7hp.com!davidm  GET_MEMORY (mem, size);
11265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm  if (!mem)
11365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm    {
114b4bde18112016cb720f3df2c0f23f5897f85f7b3Tommi Rantala      size = UNW_ALIGN(pool->obj_size, pg_size);
115b38691980f4e0c1cf0e2309aa6cc35decc6b9cb7hp.com!davidm      GET_MEMORY (mem, size);
11665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm      if (!mem)
11765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm	{
11865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm	  /* last chance: try to allocate one object from the SOS memory */
11965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm	  size = pool->obj_size;
12065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm	  mem = sos_alloc (size);
12165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm	}
12265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm    }
12365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm  add_memory (pool, mem, size, pool->obj_size);
12465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm}
12565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
12665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmHIDDEN void
12765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmmempool_init (struct mempool *pool, size_t obj_size, size_t reserve)
12865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm{
12965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm  if (pg_size == 0)
13065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm    pg_size = getpagesize ();
13165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
13265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm  memset (pool, 0, sizeof (*pool));
13365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
134b38691980f4e0c1cf0e2309aa6cc35decc6b9cb7hp.com!davidm  lock_init (&pool->lock);
13565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
13665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm  /* round object-size up to integer multiple of MAX_ALIGN */
137c2f7574187cfbb36dbcdc85bc61a027a4025f394Tommi Rantala  obj_size = UNW_ALIGN(obj_size, MAX_ALIGN);
13865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
13965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm  if (!reserve)
14065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm    {
141b38691980f4e0c1cf0e2309aa6cc35decc6b9cb7hp.com!davidm      reserve = pg_size / obj_size / 4;
14265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm      if (!reserve)
14365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm	reserve = 16;
14465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm    }
14565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
14665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm  pool->obj_size = obj_size;
14765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm  pool->reserve = reserve;
148b4bde18112016cb720f3df2c0f23f5897f85f7b3Tommi Rantala  pool->chunk_size = UNW_ALIGN(2*reserve*obj_size, pg_size);
14965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
15065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm  expand (pool);
15165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm}
15265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
15365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmHIDDEN void *
15465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmmempool_alloc (struct mempool *pool)
15565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm{
156b38691980f4e0c1cf0e2309aa6cc35decc6b9cb7hp.com!davidm  intrmask_t saved_mask;
15765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm  struct object *obj;
15865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
159b38691980f4e0c1cf0e2309aa6cc35decc6b9cb7hp.com!davidm  lock_acquire (&pool->lock, saved_mask);
16065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm  {
16165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm    if (pool->num_free <= pool->reserve)
16265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm      expand (pool);
16365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
16465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm    assert (pool->num_free > 0);
16565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
16665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm    --pool->num_free;
16765a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm    obj = pool->free_list;
16865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm    pool->free_list = obj->next;
16965a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm  }
170670dd57e827a3583a9284634cf1244eb8cab4795hp.com!davidm  lock_release (&pool->lock, saved_mask);
17165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm  return obj;
17265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm}
17365a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
17465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmHIDDEN void
17565a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidmmempool_free (struct mempool *pool, void *object)
17665a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm{
177b38691980f4e0c1cf0e2309aa6cc35decc6b9cb7hp.com!davidm  intrmask_t saved_mask;
17865a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm
179b38691980f4e0c1cf0e2309aa6cc35decc6b9cb7hp.com!davidm  lock_acquire (&pool->lock, saved_mask);
18065a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm  {
18165a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm    free_object (pool, object);
18265a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm  }
183b38691980f4e0c1cf0e2309aa6cc35decc6b9cb7hp.com!davidm  lock_release (&pool->lock, saved_mask);
18465a70e7f88f0bc0b428605a68f21e6eeb5c28804hp.com!davidm}
185