* Copyright (c) 1987, 1991 The Regents of the University of California.
* %sccs.include.redist.c%
* @(#)kern_malloc.c 7.30 (Berkeley) %G%
struct kmembuckets bucket
[MINBUCKET
+ 16];
struct kmemstats kmemstats
[M_LAST
];
struct kmemusage
*kmemusage
;
char *memname
[] = INITKMEMNAMES
;
char *kmembase
, *kmemlimit
;
char *memname
[] = INITKMEMNAMES
;
#define IN { if (malloc_reentered) panic("malloc reentered");\
else malloc_reentered = 1;}
#define OUT (malloc_reentered = 0)
* This structure serves two purposes.
* The first is to provide a set of masks to catch unaligned frees.
* The second is to provide known text to copy into free objects so
* that modifications after frees can be detected.
#define WEIRD_ADDR 0xdeadbeef
long addrmask
[] = { WEIRD_ADDR
,
0x00000001, 0x00000003, 0x00000007, 0x0000000f,
0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
* Normally the first word of the structure is used to hold the list
* pointer for free objects. However, when running with diagnostics,
* we use the third and fourth fields, so as to catch modifications
* in the most commonly trashed first two words.
* Allocate a block of memory
malloc(size
, type
, flags
)
register struct kmembuckets
*kbp
;
register struct kmemusage
*kup
;
register struct freelist
*freep
;
long indx
, npg
, alloc
, allocsize
;
register struct kmemstats
*ksp
= &kmemstats
[type
];
if (((unsigned long)type
) > M_LAST
)
panic("malloc - bogus type");
while (ksp
->ks_memuse
>= ksp
->ks_limit
) {
if (ksp
->ks_limblocks
< 65535)
tsleep((caddr_t
)ksp
, PSWP
+2, memname
[type
], 0);
copysize
= 1 << indx
< sizeof addrmask
? 1 << indx
: sizeof addrmask
;
if (kbp
->kb_next
== NULL
) {
allocsize
= roundup(size
, CLBYTES
);
npg
= clrnd(btoc(allocsize
));
va
= (caddr_t
) kmem_malloc(kmem_map
, (vm_size_t
)ctob(npg
),
kbp
->kb_total
+= kbp
->kb_elmpercl
;
if (allocsize
> MAXALLOCSAVE
) {
panic("malloc: allocation too large");
ksp
->ks_memuse
+= allocsize
;
kup
->ku_freecnt
= kbp
->kb_elmpercl
;
kbp
->kb_totalfree
+= kbp
->kb_elmpercl
;
* Just in case we blocked while allocating memory,
* and someone else also allocated memory for this
* bucket, don't assume the list is still empty.
savedlist
= kbp
->kb_next
;
rp
= kbp
->kb_next
; /* returned while blocked in vmemall */
kbp
->kb_next
= va
+ (npg
* NBPG
) - allocsize
;
for (cp
= kbp
->kb_next
; cp
>= va
; cp
-= allocsize
) {
((caddr_t
*)cp
)[2] = (cp
> va
? cp
- allocsize
: rp
);
lp
[0] = lp
[1] = lp
[3] = lp
[4] = -1;
kbp
->kb_next
= ((caddr_t
*)va
)[2];
if (lp
[0] != -1 || lp
[1] != -1 || lp
[3] != -1 || lp
[4] != -1)
if (kup
->ku_indx
!= indx
)
panic("malloc: wrong bucket");
if (kup
->ku_freecnt
== 0)
panic("malloc: lost data");
ksp
->ks_memuse
+= 1 << indx
;
if (ksp
->ks_memuse
> ksp
->ks_maxused
)
ksp
->ks_maxused
= ksp
->ks_memuse
;
long addrmask
[] = { 0x00000000,
0x00000001, 0x00000003, 0x00000007, 0x0000000f,
0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
* Free a block of memory allocated by malloc.
register struct kmembuckets
*kbp
;
register struct kmemusage
*kup
;
register struct freelist
*freep
;
register struct kmemstats
*ksp
= &kmemstats
[type
];
size
= 1 << kup
->ku_indx
;
if (size
> NBPG
* CLSIZE
)
alloc
= addrmask
[BUCKETINDX(NBPG
* CLSIZE
)];
alloc
= addrmask
[kup
->ku_indx
];
if (((u_long
)addr
& alloc
) != 0) {
printf("free: unaligned addr 0x%x, size %d, type %d, mask %d\n",
addr
, size
, type
, alloc
);
panic("free: unaligned addr");
size
= 1 << kup
->ku_indx
;
kbp
= &bucket
[kup
->ku_indx
];
* Check for returns of data that do not point to the
* beginning of the allocation.
if (size
> NBPG
* CLSIZE
)
alloc
= addrmask
[BUCKETINDX(NBPG
* CLSIZE
)];
alloc
= addrmask
[kup
->ku_indx
];
if (((u_long
)addr
& alloc
) != 0)
panic("free: unaligned addr 0x%x, size %d, type %s, mask %d\n",
addr
, size
, memname
[type
], alloc
);
if (size
> MAXALLOCSAVE
) {
kmem_free(kmem_map
, (vm_offset_t
)addr
, ctob(kup
->ku_pagecnt
));
size
= kup
->ku_pagecnt
<< PGSHIFT
;
if (ksp
->ks_memuse
+ size
>= ksp
->ks_limit
&&
ksp
->ks_memuse
< ksp
->ks_limit
)
freep
= (struct freelist
*)addr
;
* Check for multiple frees. Use a quick check to see if
* it looks free before laboriously searching the freelist.
copysize
= size
< sizeof addrmask
? size
: sizeof addrmask
;
if (freep
->spare0
== WEIRD_ADDR
) {
freep
->type
= ((struct freelist
*)addrmask
)->type
;
freep
->next
= ((struct freelist
*)addrmask
)->next
;
if (!bcmp(addrmask
, addr
, copysize
)) {
for (cp
= kbp
->kb_next
; cp
; cp
= *(caddr_t
*)cp
) {
printf("multiply freed item 0x%x\n",
panic("free: duplicated free");
* Copy in known text to detect modification after freeing
* and to make it look free. Also, save the type being freed
* so we can list likely culprit if modification is detected
* when the object is reallocated.
bcopy(addrmask
, addr
, copysize
);
lp
[0] = lp
[1] = lp
[3] = lp
[4] = -1;
if (kup
->ku_freecnt
>= kbp
->kb_elmpercl
)
if (kup
->ku_freecnt
> kbp
->kb_elmpercl
)
panic("free: multiple frees");
else if (kbp
->kb_totalfree
> kbp
->kb_highwat
)
if (ksp
->ks_memuse
+ size
>= ksp
->ks_limit
&&
ksp
->ks_memuse
< ksp
->ks_limit
)
((caddr_t
*)addr
)[2] = kbp
->kb_next
;
* Initialize the kernel memory allocator
#if ((MAXALLOCSAVE & (MAXALLOCSAVE - 1)) != 0)
ERROR
!_kmeminit
:_MAXALLOCSAVE_not_power_of_2
#if (MAXALLOCSAVE > MINALLOCSIZE * 32768)
ERROR
!_kmeminit
:_MAXALLOCSAVE_too_big
#if (MAXALLOCSAVE < CLBYTES)
ERROR
!_kmeminit
:_MAXALLOCSAVE_too_small
npg
= VM_KMEM_SIZE
/ NBPG
;
kmemusage
= (struct kmemusage
*) kmem_alloc(kernel_map
,
(vm_size_t
)(npg
* sizeof(struct kmemusage
)));
kmem_map
= kmem_suballoc(kernel_map
, (vm_offset_t
*)&kmembase
,
(vm_offset_t
*)&kmemlimit
, (vm_size_t
)(npg
* NBPG
), FALSE
);
for (indx
= 0; indx
< MINBUCKET
+ 16; indx
++) {
if (1 << indx
>= CLBYTES
)
bucket
[indx
].kb_elmpercl
= 1;
bucket
[indx
].kb_elmpercl
= CLBYTES
/ (1 << indx
);
bucket
[indx
].kb_highwat
= 5 * bucket
[indx
].kb_elmpercl
;
for (indx
= 0; indx
< M_LAST
; indx
++)
kmemstats
[indx
].ks_limit
= npg
* NBPG
* 6 / 10;