4 #define bcopy(s,d,n) memcpy ((d), (s), (n)) /* No overlap handling. */
6 #include "hurdmalloc.h" /* XXX see that file */
9 #define vm_allocate __vm_allocate
10 #define vm_page_size __vm_page_size
13 * Mach Operating System
14 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
15 * All Rights Reserved.
17 * Permission to use, copy, modify and distribute this software and its
18 * documentation is hereby granted, provided that both the copyright
19 * notice and this permission notice appear in all copies of the
20 * software, derivative works or modified versions, and any portions
21 * thereof, and that both notices appear in supporting documentation.
23 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
24 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
25 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
27 * Carnegie Mellon requests users of this software to return to
29 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
30 * School of Computer Science
31 * Carnegie Mellon University
32 * Pittsburgh PA 15213-3890
34 * any improvements or extensions that they make and grant Carnegie Mellon
35 * the rights to redistribute these changes.
40 * Revision 1.13 1996/12/20 01:32:01 drepper
41 * Update from main archive 961219
43 * Revision 1.12 1996/11/15 19:44:13 thomas
44 * Tue Nov 12 16:58:41 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
46 * * mach/msg-destroy.c (mach_msg_destroy_port,
47 * mach_msg_destroy_memory): Use prototype syntax.
48 * * hurd/hurdmalloc.c (more_memory, malloc_fork_prepare,
49 * malloc_fork_parent, malloc_fork_child): Likewise.
51 * Revision 1.11 1996/06/06 15:13:47 miles
52 * Changes to bring in line with the hurd libthreads/malloc.c:
53 * (more_memory): Use assert_perror instead of MACH_CALL.
54 * "cthread_internals.h": Include removed.
55 * (realloc): Use LOG2_MIN_SIZE.
56 * (LOG2_MIN_SIZE): New macro.
57 * (realloc): Don't bother allocating a new block if the
58 * new size request fits in the old one and doesn't waste any space.
59 * Only free the old block if we successfully got a new one.
60 * [MCHECK] (struct header): New type.
61 * (union header): Only define if !MCHECK.
62 * (HEADER_SIZE, HEADER_NEXT, HEADER_FREE, HEADER_CHECK): New macros.
63 * [MCHECK] (MIN_SIZE): Add correct definition for this case.
64 * (more_memory, malloc, free, realloc): Use above macros, and add
65 * appropriate checks & frobs in MCHECK case.
67 * Revision 1.6 1996/03/07 21:13:08 miles
70 * Don't bother allocating a new block if the new size request fits in the old
71 * one and doesn't waste any space.
72 * Only free the old block if we successfully got a new one.
73 * (LOG2_MIN_SIZE): New macro.
75 * Revision 1.5 1996/03/06 23:51:04 miles
76 * [MCHECK] (struct header): New type.
77 * (union header): Only define if !MCHECK.
78 * (HEADER_SIZE, HEADER_NEXT, HEADER_FREE, HEADER_CHECK): New macros.
79 * [MCHECK] (MIN_SIZE): Add correct definition for this case.
80 * (more_memory, malloc, free, realloc):
81 * Use above macros, and add appropriate checks & frobs in MCHECK case.
83 * Revision 1.4 1994/05/05 11:21:42 roland
86 * Revision 2.7 91/05/14 17:57:34 mrt
87 * Correcting copyright
89 * Revision 2.6 91/02/14 14:20:26 mrt
90 * Added new Mach copyright
91 * [91/02/13 12:41:21 mrt]
93 * Revision 2.5 90/11/05 14:37:33 rpd
94 * Added malloc_fork* code.
100 * Revision 2.4 90/08/07 14:31:28 rpd
101 * Removed RCS keyword nonsense.
103 * Revision 2.3 90/06/02 15:14:00 rpd
104 * Converted to new IPC.
105 * [90/03/20 20:56:57 rpd]
107 * Revision 2.2 89/12/08 19:53:59 rwd
108 * Removed conditionals.
111 * Revision 2.1 89/08/03 17:09:46 rwd
115 * 13-Sep-88 Eric Cooper (ecc) at Carnegie Mellon University
116 * Changed realloc() to copy min(old size, new size) bytes.
117 * Bug found by Mike Kupfer at Olivetti.
121 * Author: Eric Cooper, Carnegie Mellon University
124 * Memory allocator for use with multiple threads.
130 #include <cthreads.h>
135 * Structure of memory block header.
136 * When free, next points to next block on free list.
137 * When allocated, fl points to free list.
138 * Size of header is 4 bytes, so minimum usable block size is 8 bytes.
141 #define CHECK_BUSY 0x8a3c743e
142 #define CHECK_FREE 0x66688b92
146 typedef struct header
{
150 struct free_list
*fl
;
154 #define HEADER_SIZE sizeof (struct header)
155 #define HEADER_NEXT(h) ((h)->u.next)
156 #define HEADER_FREE(h) ((h)->u.fl)
157 #define HEADER_CHECK(h) ((h)->check)
159 #define LOG2_MIN_SIZE 4
163 typedef union header
{
165 struct free_list
*fl
;
168 #define HEADER_SIZE sizeof (union header)
169 #define HEADER_NEXT(h) ((h)->next)
170 #define HEADER_FREE(h) ((h)->fl)
171 #define MIN_SIZE 8 /* minimum block size */
172 #define LOG2_MIN_SIZE 3
176 typedef struct free_list
{
177 spin_lock_t lock
; /* spin lock for mutual exclusion */
178 header_t head
; /* head of free list for this size */
180 int in_use
; /* # mallocs - # frees */
185 * Free list with index i contains blocks of size 2 ^ (i + LOG2_MIN_SIZE)
186 * including header. Smallest block size is MIN_SIZE, with MIN_SIZE -
187 * HEADER_SIZE bytes available to user. Size argument to malloc is a signed
188 * integer for sanity checking, so largest block size is 2^31.
192 static struct free_list malloc_free_list
[NBUCKETS
];
194 /* Initialization just sets everything to zero, but might be necessary on a
195 machine where spin_lock_init does otherwise, and is necessary when
196 running an executable that was written by something like Emacs's unexec.
197 It preserves the values of data variables like malloc_free_list, but
198 does not save the vm_allocate'd space allocated by this malloc. */
204 for (i
= 0; i
< NBUCKETS
; ++i
)
206 spin_lock_init (&malloc_free_list
[i
].lock
);
207 malloc_free_list
[i
].head
= NULL
;
209 malloc_free_list
[i
].in_use
= 0;
213 /* This not only suppresses a `defined but not used' warning,
214 but it is ABSOLUTELY NECESSARY to avoid the hyperclever
215 compiler from "optimizing out" the entire function! */
220 more_memory(int size
, free_list_t fl
)
228 if (size
<= vm_page_size
) {
229 amount
= vm_page_size
;
230 n
= vm_page_size
/ size
;
231 /* We lose vm_page_size - n*size bytes here. */
237 r
= vm_allocate(mach_task_self(), &where
, (vm_size_t
) amount
, TRUE
);
240 h
= (header_t
) where
;
242 HEADER_NEXT (h
) = fl
->head
;
244 HEADER_CHECK (h
) = CHECK_FREE
;
247 h
= (header_t
) ((char *) h
+ size
);
251 /* Declaration changed to standard one for GNU. */
254 register size_t size
;
257 register free_list_t fl
;
260 if ((int) size
< 0) /* sanity check */
264 * Find smallest power-of-two block size
265 * big enough to hold requested size plus header.
273 ASSERT(i
< NBUCKETS
);
274 fl
= &malloc_free_list
[i
];
275 spin_lock(&fl
->lock
);
279 * Free list is empty;
280 * allocate more blocks.
288 spin_unlock(&fl
->lock
);
293 * Pop block from free list.
295 fl
->head
= HEADER_NEXT (h
);
298 assert (HEADER_CHECK (h
) == CHECK_FREE
);
299 HEADER_CHECK (h
) = CHECK_BUSY
;
305 spin_unlock(&fl
->lock
);
307 * Store free list pointer in block header
308 * so we can figure out where it goes
311 HEADER_FREE (h
) = fl
;
313 * Return pointer past the block header.
315 return ((char *) h
) + HEADER_SIZE
;
318 /* Declaration changed to standard one for GNU. */
324 register free_list_t fl
;
330 * Find free list for block.
332 h
= (header_t
) (base
- HEADER_SIZE
);
335 assert (HEADER_CHECK (h
) == CHECK_BUSY
);
338 fl
= HEADER_FREE (h
);
339 i
= fl
- malloc_free_list
;
343 if (i
< 0 || i
>= NBUCKETS
) {
344 ASSERT(0 <= i
&& i
< NBUCKETS
);
347 if (fl
!= &malloc_free_list
[i
]) {
348 ASSERT(fl
== &malloc_free_list
[i
]);
352 * Push block on free list.
354 spin_lock(&fl
->lock
);
355 HEADER_NEXT (h
) = fl
->head
;
357 HEADER_CHECK (h
) = CHECK_FREE
;
363 spin_unlock(&fl
->lock
);
367 /* Declaration changed to standard one for GNU. */
369 realloc(old_base
, new_size
)
374 register free_list_t fl
;
376 unsigned int old_size
;
380 return malloc (new_size
);
383 * Find size of old block.
385 h
= (header_t
) (old_base
- HEADER_SIZE
);
387 assert (HEADER_CHECK (h
) == CHECK_BUSY
);
389 fl
= HEADER_FREE (h
);
390 i
= fl
- malloc_free_list
;
394 if (i
< 0 || i
>= NBUCKETS
) {
395 ASSERT(0 <= i
&& i
< NBUCKETS
);
398 if (fl
!= &malloc_free_list
[i
]) {
399 ASSERT(fl
== &malloc_free_list
[i
]);
403 * Free list with index i contains blocks of size
404 * 2 ^ (i + * LOG2_MIN_SIZE) including header.
406 old_size
= (1 << (i
+ LOG2_MIN_SIZE
)) - HEADER_SIZE
;
408 if (new_size
<= old_size
409 && new_size
> (((old_size
+ HEADER_SIZE
) >> 1) - HEADER_SIZE
))
410 /* The new size still fits in the same block, and wouldn't fit in
411 the next smaller block! */
415 * Allocate new block, copy old bytes, and free old block.
417 new_base
= malloc(new_size
);
419 bcopy(old_base
, new_base
,
420 (int) (old_size
< new_size
? old_size
: new_size
));
422 if (new_base
|| new_size
== 0)
423 /* Free OLD_BASE, but only if the malloc didn't fail. */
431 print_malloc_free_list()
433 register int i
, size
;
434 register free_list_t fl
;
440 fprintf(stderr
, " Size In Use Free Total\n");
441 for (i
= 0, size
= MIN_SIZE
, fl
= malloc_free_list
;
443 i
+= 1, size
<<= 1, fl
+= 1) {
444 spin_lock(&fl
->lock
);
445 if (fl
->in_use
!= 0 || fl
->head
!= 0) {
446 total_used
+= fl
->in_use
* size
;
447 for (n
= 0, h
= fl
->head
; h
!= 0; h
= HEADER_NEXT (h
), n
+= 1)
449 total_free
+= n
* size
;
450 fprintf(stderr
, "%10d %10d %10d %10d\n",
451 size
, fl
->in_use
, n
, fl
->in_use
+ n
);
453 spin_unlock(&fl
->lock
);
455 fprintf(stderr
, " all sizes %10d %10d %10d\n",
456 total_used
, total_free
, total_used
+ total_free
);
461 malloc_fork_prepare(void)
463 * Prepare the malloc module for a fork by insuring that no thread is in a
464 * malloc critical section.
469 for (i
= 0; i
< NBUCKETS
; i
++) {
470 spin_lock(&malloc_free_list
[i
].lock
);
475 malloc_fork_parent(void)
477 * Called in the parent process after a fork() to resume normal operation.
482 for (i
= NBUCKETS
-1; i
>= 0; i
--) {
483 spin_unlock(&malloc_free_list
[i
].lock
);
488 malloc_fork_child(void)
490 * Called in the child process after a fork() to resume normal operation.
495 for (i
= NBUCKETS
-1; i
>= 0; i
--) {
496 spin_unlock(&malloc_free_list
[i
].lock
);
501 text_set_element (_hurd_fork_prepare_hook
, malloc_fork_prepare
);
502 text_set_element (_hurd_fork_parent_hook
, malloc_fork_parent
);
503 text_set_element (_hurd_fork_child_hook
, malloc_fork_child
);
504 text_set_element (_hurd_preinit_hook
, malloc_init
);