// Small-object allocation. // // `kalloc()` hands out one 4096-byte page and nothing smaller, so every // subsystem written on top of it has had to invent a fixed-size table to avoid // asking: NPROC, NSOCK, NDEVICE, NFILE, NINODE, NBUF. Each one is a compile- // time ceiling that fails as a refusal ("no more sockets") rather than as // memory pressure, each one is sized by guess, and each one costs its full // size in BSS whether the machine ever uses it or not. // // This is the thing they were all working around. Two interfaces over it: // // kmem_cache_create() a named cache of one object size, for a subsystem // with one kind of thing. Shows up in /proc/slab under // its own name, which is most of why it is worth // naming. // // kmalloc()/kmfree() the general case, for code that does not have a // type to build a cache around. Backed by power-of-two // caches; kmfree() finds the right one from the // object's own page. // // **Everything is backed by kalloc().** A slab is exactly one page with a // header at the front, so freeing needs no per-object header and no search: // the page's base address holds the slab, and the slab knows its cache. That // is the whole trick, and it is why an object may not be larger than a page. #ifndef KMEM_H #define KMEM_H // The host harness (tools/kmemtest.c) defines its own uint/uint64 before it // gets here, and types.h collides with glibc's -- same reason kernel/dev/ttf.c // guards its includes. #ifndef KMEM_HOST #include "core/types.h" #endif struct kmem_cache; struct sbuf; // The largest object a cache can hold: a page, less the slab header. Asking // for more returns 0 rather than silently falling back to kalloc(), because a // caller that wants whole pages should say so. uint kmem_max_obj(void); // A named cache. `size` is rounded up to the alignment; the name is kept by // pointer and must outlive the cache, which in practice means a literal. struct kmem_cache *kmem_cache_create(const char *name, uint size); void *kmem_cache_alloc(struct kmem_cache *c); void kmem_cache_free(struct kmem_cache *c, void *obj); // The general case. kmalloc(0) is a null return, not a zero-size object. void *kmalloc(uint n); void kmfree(void *p); // /proc/slab. void kmem_stats(struct sbuf *out); #endif /* KMEM_H */