• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* libunwind - a platform-independent unwind library
2    Copyright (C) 2002-2003, 2005 Hewlett-Packard Co
3         Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
4    Copyright (C) 2012 Tommi Rantala <tt.rantala@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 #include <stdalign.h>
29 #include <stdatomic.h>
30 
31 /* From GCC docs: ``Gcc also provides a target specific macro
32  * __BIGGEST_ALIGNMENT__, which is the largest alignment ever used for any data
33  * type on the target machine you are compiling for.'' */
34 #ifdef __BIGGEST_ALIGNMENT__
35 # define MAX_ALIGN      __BIGGEST_ALIGNMENT__
36 #else
37 /* Crude hack to check that MAX_ALIGN is power-of-two.
38  * sizeof(long double) = 12 on i386. */
39 # define MAX_ALIGN_(n)  (n < 8 ? 8 : \
40                          n < 16 ? 16 : n)
41 # define MAX_ALIGN      MAX_ALIGN_(sizeof (long double))
42 #endif
43 #ifndef NO_RESERVE_CACHE
44 static alignas(MAX_ALIGN) char sos_memory[SOS_MEMORY_SIZE];
45 static _Atomic size_t sos_memory_freepos = 0;
46 #endif
47 static size_t pg_size;
48 
49 HIDDEN void *
sos_alloc(size_t size)50 sos_alloc (size_t size)
51 {
52   Dprintf("sos_alloc %zu\n", size);
53 #ifndef NO_RESERVE_CACHE
54   size_t pos;
55 
56   size = UNW_ALIGN(size, MAX_ALIGN);
57 
58   /* Assume `sos_memory' is suitably aligned. */
59   assert(((uintptr_t) &sos_memory[0] & (MAX_ALIGN-1)) == 0);
60 
61   pos = atomic_fetch_add (&sos_memory_freepos, size);
62 
63   assert (((uintptr_t) &sos_memory[pos] & (MAX_ALIGN-1)) == 0);
64   assert ((pos+size) <= SOS_MEMORY_SIZE);
65 
66   return &sos_memory[pos];
67 #else
68   return NULL;
69 #endif
70 }
71 
72 /* Must be called while holding the mempool lock. */
73 
74 static void
free_object(struct mempool * pool,void * object)75 free_object (struct mempool *pool, void *object)
76 {
77   struct object *obj = object;
78 
79   obj->next = pool->free_list;
80   pool->free_list = obj;
81   ++pool->num_free;
82 }
83 
84 static void
add_memory(struct mempool * pool,char * mem,size_t size,size_t obj_size)85 add_memory (struct mempool *pool, char *mem, size_t size, size_t obj_size)
86 {
87   char *obj;
88 
89   for (obj = mem; obj <= mem + size - obj_size; obj += obj_size)
90     free_object (pool, obj);
91 }
92 
93 static void
expand(struct mempool * pool)94 expand (struct mempool *pool)
95 {
96   size_t size;
97   char *mem;
98 
99   size = pool->chunk_size;
100   GET_MEMORY (mem, size);
101   if (!mem)
102     {
103       size = UNW_ALIGN(pool->obj_size, pg_size);
104       GET_MEMORY (mem, size);
105       if (!mem)
106         {
107           /* last chance: try to allocate one object from the SOS memory */
108           size = pool->obj_size;
109           mem = sos_alloc (size);
110         }
111     }
112   add_memory (pool, mem, size, pool->obj_size);
113 }
114 
115 HIDDEN void
mempool_init(struct mempool * pool,size_t obj_size,size_t reserve)116 mempool_init (struct mempool *pool, size_t obj_size, size_t reserve)
117 {
118   if (pg_size == 0)
119     pg_size = getpagesize ();
120 
121   memset (pool, 0, sizeof (*pool));
122 
123   lock_init (&pool->lock);
124 
125   /* round object-size up to integer multiple of MAX_ALIGN */
126   obj_size = UNW_ALIGN(obj_size, MAX_ALIGN);
127 
128   if (!reserve)
129     {
130       reserve = pg_size / obj_size / 4;
131       if (!reserve)
132         reserve = 16;
133     }
134 
135   pool->obj_size = obj_size;
136   pool->reserve = reserve;
137   pool->chunk_size = UNW_ALIGN(2*reserve*obj_size, pg_size);
138 
139   expand (pool);
140 }
141 
142 HIDDEN void *
mempool_alloc(struct mempool * pool)143 mempool_alloc (struct mempool *pool)
144 {
145   intrmask_t saved_mask;
146   struct object *obj;
147 
148   lock_acquire (&pool->lock, saved_mask);
149   {
150     if (pool->num_free <= pool->reserve)
151       expand (pool);
152 
153     assert (pool->num_free > 0);
154 
155     --pool->num_free;
156     obj = pool->free_list;
157     pool->free_list = obj->next;
158   }
159   lock_release (&pool->lock, saved_mask);
160   return obj;
161 }
162 
163 HIDDEN void
mempool_free(struct mempool * pool,void * object)164 mempool_free (struct mempool *pool, void *object)
165 {
166   intrmask_t saved_mask;
167 
168   lock_acquire (&pool->lock, saved_mask);
169   {
170     free_object (pool, object);
171   }
172   lock_release (&pool->lock, saved_mask);
173 }
174