2 * Copyright (c) 1999-2001
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 /* Idea: clear on page alloc rather than individual alloc
31 Turns out not so good (on lcc at least, seems a wash on mudlle):
32 logically should be bad for small regions (less than a few pages)
40 #include "radix-tree.h"
41 #define RPAGESIZE (1 << RPAGELOG)
42 #define PAGE_GROUP_SIZE 32
44 #define MAXPAGE (1 << (32 - RPAGELOG))
46 #define PAGENB(x) ((__rcintptr)(x) >> RPAGELOG)
48 #define ALIGN(x, n) (((x) + ((n) - 1)) & ~((n) - 1))
49 #define PALIGN(x, n) ((void *)ALIGN((__rcintptr)(x), n))
51 #define RALIGNMENT __alignof(double)
52 #define PTRALIGNMENT __alignof(void *)
53 #define ALIGNMENT_LONG __alignof(unsigned long)
56 #define PTRALIGNMENT 4
57 #define ALIGNMENT_LONG 4
60 typedef unsigned long __rcintptr
;
63 char *base
, *allocfrom
;
68 struct ablock superpage
;
69 struct ablock hyperpage
;
71 struct page
*bigpages
;
75 struct allocator normal
;
76 struct Region
*parent
, *sibling
, *children
;
79 nomem_handler nomem_h
;
81 /* dummy region for NULL and malloc memory */
82 struct Region zeroregion
;
84 static void clear(void *start
, __rcintptr size
)
86 long *clear
, *clearend
;
88 clear
= (long *)start
;
89 clearend
= (long *)((char *)start
+ size
);
91 while (clear
< clearend
) ;
95 #define preclear clear
96 #define postclear(s, e)
98 #define preclear(s, e)
99 #define postclear clear
105 static void nochildren(region r
)
111 static void unlink_region(region r
)
115 scan
= &r
->parent
->children
;
117 scan
= &(*scan
)->sibling
;
118 *scan
= (*scan
)->sibling
;
121 static void link_region(region r
, region parent
)
123 r
->sibling
= parent
->children
;
125 parent
->children
= r
;
130 void initregion(region r
)
133 (char *)r
- rstart
- offsetof(struct page
, previous
);
135 /* Start using page with region header as a pointer-containing page */
136 r
->normal
.page
.base
= first
;
137 r
->normal
.page
.allocfrom
= (char *)(r
+ 1);
139 /* Guarantee failure for all other blocks */
140 r
->normal
.superpage
.allocfrom
= (char *)(K
* RPAGESIZE
+ 1);
141 r
->normal
.hyperpage
.allocfrom
= (char *)(K
* K
* RPAGESIZE
+ 1);
143 /* Remember that r owns this page. */
144 r
->normal
.pages
= (struct page
*)first
;
145 set_region(r
->normal
.pages
, 1, r
);
148 region
newregion(void)
150 return newsubregion(&zeroregion
);
153 region
newsubregion(region parent
)
158 first
= (char *)alloc_single_page(NULL
);
159 preclear(first
+ offsetof(struct page
, pagecount
), RPAGESIZE
- offsetof(struct page
, pagecount
));
161 /* stagger regions across cache lines a bit */
163 if (rstart
> RPAGESIZE
/ K
) rstart
= 0;
164 r
= (region
)(first
+ rstart
+ offsetof(struct page
, previous
));
165 postclear(r
, sizeof *r
);
168 link_region(r
, parent
);
173 void *typed_ralloc(region r
, size_t size
, type_t t
)
175 return rstralloc0(r
, size
);
178 void *typed_rarrayextend(region r
, void *old
, size_t n
, size_t size
, type_t t
)
180 return rstrextend0(r
, old
, n
* size
);
183 void *typed_rarrayalloc(region r
, size_t n
, size_t size
, type_t t
)
185 return typed_ralloc(r
, n
* size
, t
);
188 char *rstralloc(region r
, size_t size
)
192 qalloc(r
, &r
->normal
, &dummy
, 0, 1, &mem
, size
, RALIGNMENT
, 0);
197 char *rstralloc0(region r
, size_t size
)
201 mem
= rstralloc(r
, size
);
207 char *rstrdup(region r
, const char *s
)
209 char *news
= rstralloc(r
, strlen(s
) + 1);
216 static char *internal_rstrextend(region r
, const char *old
, size_t newsize
,
219 /* For now we don't attempt to extend the old storage area */
221 unsigned long *oldhdr
, oldsize
;
223 qalloc(r
, &r
->normal
, &hdr
, sizeof(unsigned long), ALIGNMENT_LONG
,
224 &newmem
, newsize
, RALIGNMENT
, 0);
226 /* If we don't do this we can't find the header: */
227 hdr
= (char *)newmem
- sizeof(unsigned long);
229 *(unsigned long *)hdr
= newsize
;
233 oldhdr
= (unsigned long *)(old
- ALIGNMENT_LONG
);
236 if (oldsize
> newsize
)
239 clear((char *) newmem
+ oldsize
, newsize
- oldsize
);
240 memcpy(newmem
, old
, oldsize
);
243 clear(newmem
, newsize
);
248 char *rstrextend(region r
, const char *old
, size_t newsize
)
250 return internal_rstrextend(r
, old
, newsize
, 0);
253 char *rstrextend0(region r
, const char *old
, size_t newsize
)
255 return internal_rstrextend(r
, old
, newsize
, 1);
258 void typed_rarraycopy(void *to
, void *from
, size_t n
, size_t size
, type_t type
)
260 memcpy(to
, from
, n
* size
);
263 static void delregion(region r
)
266 free_all_pages(r
, &r
->normal
);
269 void deleteregion(region r
)
275 void deleteregion_ptr(region
*r
)
283 void deleteregion_array(int n
, region
*regions
)
287 for (i
= 0; i
< n
; i
++)
288 unlink_region(regions
[i
]);
290 for (i
= 0; i
< n
; i
++)
292 delregion(regions
[i
]);
297 region
regionof(void *ptr
)
299 return radix_tree_lookup (&__rcregionmap
, (unsigned long)ptr
>> RPAGELOG
);
302 void region_init(void)
304 static int initialized
= 0;
310 rstart
= -64; /* Save 64 bytes of memory! (sometimes ;-)) */
317 nomem_handler
set_nomem_handler(nomem_handler newhandler
)
319 nomem_handler oldh
= nomem_h
;
321 nomem_h
= newhandler
;
327 int region_main(int argc, char **argv, char **envp);
329 int main(int argc, char **argv, char **envp)
332 return region_main(argc, argv, envp);
337 /* Debugging support */
341 static void printref(void *x
)
343 /* if (x >= (void *)__rcregionmap && x < (void *)&__rcregionmap[MAXPAGE])
347 if (x
>= (void *)__rcregions
&& x
< (void *)&__rcregions
[MAXREGIONS
])
352 fprintf(out
, "info symbol 0x%p\n", x
);
355 void findrefs(region r
, void *from
, void *to
)
360 out
= fopen("/dev/tty", "w");
362 for (f
= PALIGN(from
, PTRALIGNMENT
); f
< (char *)to
; f
+= PTRALIGNMENT
)
363 if (regionof(*(void **)f
) == r
)
370 extern void _DYNAMIC
, _end
;
372 void findgrefs(region r
)
374 findrefs(r
, &_DYNAMIC
, &_end
);
378 void findrrefs(region r
, region from
)
382 for (p
= from
->normal
.pages
; p
; p
= p
->next
)
383 findrefs(r
, (char *)&p
->previous
, (char *)p
+ RPAGESIZE
);
385 for (p
= r
->normal
.bigpages
; p
; p
= p
->next
)
386 findrefs(r
, (char *)&p
->previous
, (char *)p
+ p
->pagecount
* RPAGESIZE
);