4 #include "hurdmalloc.h" /* XXX see that file */
7 #define vm_allocate __vm_allocate
8 #define vm_page_size __vm_page_size
11 * Mach Operating System
12 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
13 * All Rights Reserved.
15 * Permission to use, copy, modify and distribute this software and its
16 * documentation is hereby granted, provided that both the copyright
17 * notice and this permission notice appear in all copies of the
18 * software, derivative works or modified versions, and any portions
19 * thereof, and that both notices appear in supporting documentation.
21 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
22 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
23 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
25 * Carnegie Mellon requests users of this software to return to
27 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
28 * School of Computer Science
29 * Carnegie Mellon University
30 * Pittsburgh PA 15213-3890
32 * any improvements or extensions that they make and grant Carnegie Mellon
33 * the rights to redistribute these changes.
38 * Revision 2.7 91/05/14 17:57:34 mrt
39 * Correcting copyright
41 * Revision 2.6 91/02/14 14:20:26 mrt
42 * Added new Mach copyright
43 * [91/02/13 12:41:21 mrt]
45 * Revision 2.5 90/11/05 14:37:33 rpd
46 * Added malloc_fork* code.
52 * Revision 2.4 90/08/07 14:31:28 rpd
53 * Removed RCS keyword nonsense.
55 * Revision 2.3 90/06/02 15:14:00 rpd
56 * Converted to new IPC.
57 * [90/03/20 20:56:57 rpd]
59 * Revision 2.2 89/12/08 19:53:59 rwd
60 * Removed conditionals.
63 * Revision 2.1 89/08/03 17:09:46 rwd
67 * 13-Sep-88 Eric Cooper (ecc) at Carnegie Mellon University
68 * Changed realloc() to copy min(old size, new size) bytes.
69 * Bug found by Mike Kupfer at Olivetti.
73 * Author: Eric Cooper, Carnegie Mellon University
76 * Memory allocator for use with multiple threads.
87 * Structure of memory block header.
88 * When free, next points to next block on free list.
89 * When allocated, fl points to free list.
90 * Size of header is 4 bytes, so minimum usable block size is 8 bytes.
93 #define CHECK_BUSY 0x8a3c743e
94 #define CHECK_FREE 0x66688b92
98 typedef struct header
{
102 struct free_list
*fl
;
106 #define HEADER_SIZE sizeof (struct header)
107 #define HEADER_NEXT(h) ((h)->u.next)
108 #define HEADER_FREE(h) ((h)->u.fl)
109 #define HEADER_CHECK(h) ((h)->check)
111 #define LOG2_MIN_SIZE 4
115 typedef union header
{
117 struct free_list
*fl
;
120 #define HEADER_SIZE sizeof (union header)
121 #define HEADER_NEXT(h) ((h)->next)
122 #define HEADER_FREE(h) ((h)->fl)
123 #define MIN_SIZE 8 /* minimum block size */
124 #define LOG2_MIN_SIZE 3
128 typedef struct free_list
{
129 spin_lock_t lock
; /* spin lock for mutual exclusion */
130 header_t head
; /* head of free list for this size */
132 int in_use
; /* # mallocs - # frees */
137 * Free list with index i contains blocks of size 2 ^ (i + LOG2_MIN_SIZE)
138 * including header. Smallest block size is MIN_SIZE, with MIN_SIZE -
139 * HEADER_SIZE bytes available to user. Size argument to malloc is a signed
140 * integer for sanity checking, so largest block size is 2^31.
144 static struct free_list malloc_free_list
[NBUCKETS
];
146 /* Initialization just sets everything to zero, but might be necessary on a
147 machine where spin_lock_init does otherwise, and is necessary when
148 running an executable that was written by something like Emacs's unexec.
149 It preserves the values of data variables like malloc_free_list, but
150 does not save the vm_allocate'd space allocated by this malloc. */
156 for (i
= 0; i
< NBUCKETS
; ++i
)
158 spin_lock_init (&malloc_free_list
[i
].lock
);
159 malloc_free_list
[i
].head
= NULL
;
161 malloc_free_list
[i
].in_use
= 0;
165 /* This not only suppresses a `defined but not used' warning,
166 but it is ABSOLUTELY NECESSARY to avoid the hyperclever
167 compiler from "optimizing out" the entire function! */
172 more_memory(int size
, free_list_t fl
)
180 if (size
<= vm_page_size
) {
181 amount
= vm_page_size
;
182 n
= vm_page_size
/ size
;
183 /* We lose vm_page_size - n*size bytes here. */
189 r
= vm_allocate(mach_task_self(), &where
, (vm_size_t
) amount
, TRUE
);
192 h
= (header_t
) where
;
194 HEADER_NEXT (h
) = fl
->head
;
196 HEADER_CHECK (h
) = CHECK_FREE
;
199 h
= (header_t
) ((char *) h
+ size
);
203 /* Declaration changed to standard one for GNU. */
211 if ((int) size
< 0) /* sanity check */
215 * Find smallest power-of-two block size
216 * big enough to hold requested size plus header.
224 ASSERT(i
< NBUCKETS
);
225 fl
= &malloc_free_list
[i
];
226 spin_lock(&fl
->lock
);
230 * Free list is empty;
231 * allocate more blocks.
239 spin_unlock(&fl
->lock
);
244 * Pop block from free list.
246 fl
->head
= HEADER_NEXT (h
);
249 assert (HEADER_CHECK (h
) == CHECK_FREE
);
250 HEADER_CHECK (h
) = CHECK_BUSY
;
256 spin_unlock(&fl
->lock
);
258 * Store free list pointer in block header
259 * so we can figure out where it goes
262 HEADER_FREE (h
) = fl
;
264 * Return pointer past the block header.
266 return ((char *) h
) + HEADER_SIZE
;
269 /* Declaration changed to standard one for GNU. */
280 * Find free list for block.
282 h
= (header_t
) (base
- HEADER_SIZE
);
285 assert (HEADER_CHECK (h
) == CHECK_BUSY
);
288 fl
= HEADER_FREE (h
);
289 i
= fl
- malloc_free_list
;
293 if (i
< 0 || i
>= NBUCKETS
) {
294 ASSERT(0 <= i
&& i
< NBUCKETS
);
297 if (fl
!= &malloc_free_list
[i
]) {
298 ASSERT(fl
== &malloc_free_list
[i
]);
302 * Push block on free list.
304 spin_lock(&fl
->lock
);
305 HEADER_NEXT (h
) = fl
->head
;
307 HEADER_CHECK (h
) = CHECK_FREE
;
313 spin_unlock(&fl
->lock
);
317 /* Declaration changed to standard one for GNU. */
319 realloc (void *old_base
, size_t new_size
)
324 unsigned int old_size
;
328 return malloc (new_size
);
331 * Find size of old block.
333 h
= (header_t
) (old_base
- HEADER_SIZE
);
335 assert (HEADER_CHECK (h
) == CHECK_BUSY
);
337 fl
= HEADER_FREE (h
);
338 i
= fl
- malloc_free_list
;
342 if (i
< 0 || i
>= NBUCKETS
) {
343 ASSERT(0 <= i
&& i
< NBUCKETS
);
346 if (fl
!= &malloc_free_list
[i
]) {
347 ASSERT(fl
== &malloc_free_list
[i
]);
351 * Free list with index i contains blocks of size
352 * 2 ^ (i + * LOG2_MIN_SIZE) including header.
354 old_size
= (1 << (i
+ LOG2_MIN_SIZE
)) - HEADER_SIZE
;
356 if (new_size
<= old_size
357 && new_size
> (((old_size
+ HEADER_SIZE
) >> 1) - HEADER_SIZE
))
358 /* The new size still fits in the same block, and wouldn't fit in
359 the next smaller block! */
363 * Allocate new block, copy old bytes, and free old block.
365 new_base
= malloc(new_size
);
367 memcpy (new_base
, old_base
,
368 (int) (old_size
< new_size
? old_size
: new_size
));
370 if (new_base
|| new_size
== 0)
371 /* Free OLD_BASE, but only if the malloc didn't fail. */
379 print_malloc_free_list (void)
388 fprintf(stderr
, " Size In Use Free Total\n");
389 for (i
= 0, size
= MIN_SIZE
, fl
= malloc_free_list
;
391 i
+= 1, size
<<= 1, fl
+= 1) {
392 spin_lock(&fl
->lock
);
393 if (fl
->in_use
!= 0 || fl
->head
!= 0) {
394 total_used
+= fl
->in_use
* size
;
395 for (n
= 0, h
= fl
->head
; h
!= 0; h
= HEADER_NEXT (h
), n
+= 1)
397 total_free
+= n
* size
;
398 fprintf(stderr
, "%10d %10d %10d %10d\n",
399 size
, fl
->in_use
, n
, fl
->in_use
+ n
);
401 spin_unlock(&fl
->lock
);
403 fprintf(stderr
, " all sizes %10d %10d %10d\n",
404 total_used
, total_free
, total_used
+ total_free
);
409 _hurd_malloc_fork_prepare(void)
411 * Prepare the malloc module for a fork by insuring that no thread is in a
412 * malloc critical section.
417 for (i
= 0; i
< NBUCKETS
; i
++) {
418 spin_lock(&malloc_free_list
[i
].lock
);
423 _hurd_malloc_fork_parent(void)
425 * Called in the parent process after a fork() to resume normal operation.
430 for (i
= NBUCKETS
-1; i
>= 0; i
--) {
431 spin_unlock(&malloc_free_list
[i
].lock
);
436 _hurd_malloc_fork_child(void)
438 * Called in the child process after a fork() to resume normal operation.
443 for (i
= NBUCKETS
-1; i
>= 0; i
--) {
444 spin_unlock(&malloc_free_list
[i
].lock
);
449 text_set_element (_hurd_preinit_hook
, malloc_init
);