Home | History | Annotate | Download | only in mi
      1 /* libunwind - a platform-independent unwind library
      2    Copyright (C) 2002-2003, 2005 Hewlett-Packard Co
      3 	Contributed by David Mosberger-Tang <davidm (at) hpl.hp.com>
      4    Copyright (C) 2012 Tommi Rantala <tt.rantala (at) gmail.com>
      5 
      6 This file is part of libunwind.
      7 
      8 Permission is hereby granted, free of charge, to any person obtaining
      9 a copy of this software and associated documentation files (the
     10 "Software"), to deal in the Software without restriction, including
     11 without limitation the rights to use, copy, modify, merge, publish,
     12 distribute, sublicense, and/or sell copies of the Software, and to
     13 permit persons to whom the Software is furnished to do so, subject to
     14 the following conditions:
     15 
     16 The above copyright notice and this permission notice shall be
     17 included in all copies or substantial portions of the Software.
     18 
     19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     20 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     21 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     22 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
     23 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
     24 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     25 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
     26 
     27 #include "libunwind_i.h"
     28 
     29 /* From GCC docs: ``Gcc also provides a target specific macro
     30  * __BIGGEST_ALIGNMENT__, which is the largest alignment ever used for any data
     31  * type on the target machine you are compiling for.'' */
     32 #ifdef __BIGGEST_ALIGNMENT__
     33 # define MAX_ALIGN	__BIGGEST_ALIGNMENT__
     34 #else
     35 /* Crude hack to check that MAX_ALIGN is power-of-two.
     36  * sizeof(long double) = 12 on i386. */
     37 # define MAX_ALIGN_(n)	(n < 8 ? 8 : \
     38 			 n < 16 ? 16 : n)
     39 # define MAX_ALIGN	MAX_ALIGN_(sizeof (long double))
     40 #endif
     41 
     42 static char sos_memory[SOS_MEMORY_SIZE] ALIGNED(MAX_ALIGN);
     43 static size_t sos_memory_freepos;
     44 static size_t pg_size;
     45 
     46 HIDDEN void *
     47 sos_alloc (size_t size)
     48 {
     49   size_t pos;
     50 
     51   size = UNW_ALIGN(size, MAX_ALIGN);
     52 
     53 #if defined(__GNUC__) && defined(HAVE_FETCH_AND_ADD)
     54   /* Assume `sos_memory' is suitably aligned. */
     55   assert(((uintptr_t) &sos_memory[0] & (MAX_ALIGN-1)) == 0);
     56 
     57   pos = fetch_and_add (&sos_memory_freepos, size);
     58 #else
     59   static define_lock (sos_lock);
     60   intrmask_t saved_mask;
     61 
     62   lock_acquire (&sos_lock, saved_mask);
     63   {
     64     /* No assumptions about `sos_memory' alignment. */
     65     if (sos_memory_freepos == 0)
     66       {
     67 	unsigned align = UNW_ALIGN((uintptr_t) &sos_memory[0], MAX_ALIGN)
     68 				- (uintptr_t) &sos_memory[0];
     69 	sos_memory_freepos = align;
     70       }
     71     pos = sos_memory_freepos;
     72     sos_memory_freepos += size;
     73   }
     74   lock_release (&sos_lock, saved_mask);
     75 #endif
     76 
     77   assert (((uintptr_t) &sos_memory[pos] & (MAX_ALIGN-1)) == 0);
     78   assert ((pos+size) <= SOS_MEMORY_SIZE);
     79 
     80   return &sos_memory[pos];
     81 }
     82 
     83 /* Must be called while holding the mempool lock. */
     84 
     85 static void
     86 free_object (struct mempool *pool, void *object)
     87 {
     88   struct object *obj = object;
     89 
     90   obj->next = pool->free_list;
     91   pool->free_list = obj;
     92   ++pool->num_free;
     93 }
     94 
     95 static void
     96 add_memory (struct mempool *pool, char *mem, size_t size, size_t obj_size)
     97 {
     98   char *obj;
     99 
    100   for (obj = mem; obj <= mem + size - obj_size; obj += obj_size)
    101     free_object (pool, obj);
    102 }
    103 
    104 static void
    105 expand (struct mempool *pool)
    106 {
    107   size_t size;
    108   char *mem;
    109 
    110   size = pool->chunk_size;
    111   GET_MEMORY (mem, size);
    112   if (!mem)
    113     {
    114       size = UNW_ALIGN(pool->obj_size, pg_size);
    115       GET_MEMORY (mem, size);
    116       if (!mem)
    117 	{
    118 	  /* last chance: try to allocate one object from the SOS memory */
    119 	  size = pool->obj_size;
    120 	  mem = sos_alloc (size);
    121 	}
    122     }
    123   add_memory (pool, mem, size, pool->obj_size);
    124 }
    125 
    126 HIDDEN void
    127 mempool_init (struct mempool *pool, size_t obj_size, size_t reserve)
    128 {
    129   if (pg_size == 0)
    130     pg_size = getpagesize ();
    131 
    132   memset (pool, 0, sizeof (*pool));
    133 
    134   lock_init (&pool->lock);
    135 
    136   /* round object-size up to integer multiple of MAX_ALIGN */
    137   obj_size = UNW_ALIGN(obj_size, MAX_ALIGN);
    138 
    139   if (!reserve)
    140     {
    141       reserve = pg_size / obj_size / 4;
    142       if (!reserve)
    143 	reserve = 16;
    144     }
    145 
    146   pool->obj_size = obj_size;
    147   pool->reserve = reserve;
    148   pool->chunk_size = UNW_ALIGN(2*reserve*obj_size, pg_size);
    149 
    150   expand (pool);
    151 }
    152 
    153 HIDDEN void *
    154 mempool_alloc (struct mempool *pool)
    155 {
    156   intrmask_t saved_mask;
    157   struct object *obj;
    158 
    159   lock_acquire (&pool->lock, saved_mask);
    160   {
    161     if (pool->num_free <= pool->reserve)
    162       expand (pool);
    163 
    164     assert (pool->num_free > 0);
    165 
    166     --pool->num_free;
    167     obj = pool->free_list;
    168     pool->free_list = obj->next;
    169   }
    170   lock_release (&pool->lock, saved_mask);
    171   return obj;
    172 }
    173 
    174 HIDDEN void
    175 mempool_free (struct mempool *pool, void *object)
    176 {
    177   intrmask_t saved_mask;
    178 
    179   lock_acquire (&pool->lock, saved_mask);
    180   {
    181     free_object (pool, object);
    182   }
    183   lock_release (&pool->lock, saved_mask);
    184 }
    185