xv6, line by line
user/umalloc.c

user/umalloc.c

C · 90 lines · annotated 100% · user program / library · upstream

About this file

malloc and free for user programs: the classic allocator from Kernighan and Ritchie’s The C Programming Language (2nd edition, section 8.7), almost unchanged. It is a free-list allocator that manages the process’s heap.

The kernel provides only one way to get memory: sbrk, which extends the process’s memory by a number of bytes. That is too coarse to use for every small request, and it cannot return a block from the middle. This file sits between the two:

  • Memory is handled in units of one Header, 16 bytes. Every block, free or in use, starts with a header that records its size in units.
  • Free blocks are kept on a circular list sorted by address, linked through their headers. freep points into the list, at the place where the last search ended.
  • malloc walks the list from there and takes the first block that is large enough; if it is larger than needed, it cuts the request off the block’s tail.
  • free puts a block back in address order and merges it with the free block directly before or after it, when they touch.
  • When no block is large enough, morecore gets at least 64 KiB more from the kernel with sbrk and adds it to the list by calling free.

Memory is never returned to the kernel; a process’s heap only grows.

The kernel’s allocator for physical pages, kernel/kalloc.c, uses the same free-list idea in its simplest form, with fixed-size blocks.

Read before: user/ulib.c (for sbrk). user/sh.c is the main user.

6// Memory allocator by Kernighan and Ritchie,
7// The C programming Language, 2nd ed. Section 8.7.
9typedef long Align;
11union header {
12 struct {
13 union header *ptr;
15 } s;
17};
19typedef union header Header;
21static Header base;
22static Header *freep;
24void
25free(void *ap)
29 bp = (Header *)ap - 1;
30 for (p = freep; !(bp > p && bp < p->s.ptr); p = p->s.ptr)
31 if (p >= p->s.ptr && (bp > p || bp < p->s.ptr))
32 break;
33 if (bp + bp->s.size == p->s.ptr) {
34 bp->s.size += p->s.ptr->s.size;
35 bp->s.ptr = p->s.ptr->s.ptr;
36 } else
37 bp->s.ptr = p->s.ptr;
38 if (p + p->s.size == bp) {
39 p->s.size += bp->s.size;
40 p->s.ptr = bp->s.ptr;
41 } else
42 p->s.ptr = bp;
46static Header *
49 char *p;
52 if (nu < 4096)
53 nu = 4096;
54 p = sbrk(nu * sizeof(Header));
55 if (p == SBRK_ERROR)
56 return 0;
57 hp = (Header *)p;
58 hp->s.size = nu;
59 free((void *)(hp + 1));
60 return freep;
63void *
69 nunits = (nbytes + sizeof(Header) - 1) / sizeof(Header) + 1;
70 if ((prevp = freep) == 0) {
72 base.s.size = 0;
73 }
74 for (p = prevp->s.ptr;; prevp = p, p = p->s.ptr) {
75 if (p->s.size >= nunits) {
76 if (p->s.size == nunits)
77 prevp->s.ptr = p->s.ptr;
78 else {
80 p += p->s.size;
82 }
84 return (void *)(p + 1);
85 }
86 if (p == freep)
87 if ((p = morecore(nunits)) == 0)
88 return 0;
89 }