#include #include #include #include #include #include #include #define SCMIN 6 /* 1<<6 == 64 */ #define SCMAX 12 /* 1<<11 == 2048 */ static const char *tagnames[] = { "Invalid", /* TagInvalid */ "KernelFs", /* TagKernelFs */ "ProcFs", /* TagProcFs */ "UserFs", /* TagUserFs */ "OpenPath", /* TagOpenPath */ "MountPath", /* TagMountPath */ "MountUser", /* TagMountUser */ "MountRoot", /* TagMountRoot */ "Execbuf", /* TagExecbuf */ "VfsReq", /* TagVfsReq */ "Handleset", /* TagHandleset */ "Handle", /* TagHandle */ "Process", /* TagProcess */ "ProcessHandle", /* TagProcessHandle */ "DevTime", /* TagDevTime */ "RootCache", /* TagRootCache */ "PageRefcount", /* TagPageRefcount */ }; static_assert(sizeof(tagnames) == sizeof(const char *) * TagLast); typedef struct Slab Slab; struct Slab { /* The slab is divided up into 1<next) { kprintf( "%08p %016llx %s %db \n", al, al->bitmap, full ? "full" : "part", 1ull<sizeclass ); assert(al->sizeclass == sizeclass); assert(al->bitmap & 1); assert(al->slot && *al->slot == al); assert(isfull(al->bitmap, sizeclass) == full); tally++; for (int i = 1; i * regsize < PAGE_SIZE; i++) { char *p = ((char*)al) + i * regsize; AllocHdr *hdr = (void*)p + regsize - sizeof(AllocHdr); if (al->bitmap & (1ull<tag != TagInvalid && hdr->tag < TagLast); kprintf("%08p %4db %s\n", p, hdr->len, tagnames[hdr->tag]); } } } return tally; } void kmalloc_debugprint(void) { uint64_t tally = 0; for (int i = 0; i < SCMAX; i++) { tally += crawllist(freeslabs[i], i, false); tally += crawllist(fullslabs[i], i, true); } assert(tally == curslabs); // TODO count waste } static int getsizeclass(size_t len) { int i; for (i = SCMIN; i < SCMAX-1; i++) { /* last iteration can be skipped */ if (len <= (1ull<sizeclass && hdr->sizeclass < SCMAX); assert(hdr->bitmap & 1); return hdr; } void * kmalloc(size_t len, enum MallocTag tag) { Slab *al; void *ret; int sizeclass, regsize; uint64_t idx; assert(tag != TagInvalid && tag < TagLast); assert(len <= KMALLOC_MAX); len += sizeof(AllocHdr); sizeclass = getsizeclass(len); regsize = 1ull << sizeclass; if (freeslabs[sizeclass] == NULL) { al = page_alloc(1); al->sizeclass = sizeclass; al->bitmap = 1; /* mark header as allocated */ al->slot = &freeslabs[sizeclass]; al->next = NULL; freeslabs[sizeclass] = al; curslabs++; } al = freeslabs[sizeclass]; idx = findfreebit(al->bitmap); assert(1 <= idx && idx < 64); assert((al->bitmap & (1ull<bitmap |= 1ull<len = len - sizeof(AllocHdr); hdr->tag = tag; /* if this was the last free region, move to fullslabs */ if (isfull(al->bitmap, sizeclass)) { *al->slot = al->next; al->next->slot = al->slot; al->next = fullslabs[sizeclass]; al->next->slot = &al->next; fullslabs[sizeclass] = al; al->slot = &fullslabs[sizeclass]; } return ret; } void kfree(void *ptr) { assert(ptr); Slab *al = getheader(ptr); int sizeclass = al->sizeclass; int regsize = 1ull << sizeclass; uint64_t off = ((uint64_t)ptr) & PAGE_MASK; uint64_t idx = off >> sizeclass; bool full = isfull(al->bitmap, sizeclass); assert(((char*)al) + idx * regsize == ptr); /* aligned? */ assert(1 <= idx); /* not the header? */ assert(al->bitmap & (1ull<bitmap &= ~(1ull<bitmap == 1) { /* we're empty */ *al->slot = al->next; al->next->slot = al->slot; page_free(al, 1); curslabs--; } else if (full) { /* we're no longer full */ *al->slot = al->next; al->next->slot = al->slot; al->next = freeslabs[sizeclass]; al->next->slot = &al->next; freeslabs[sizeclass] = al; al->slot = &freeslabs[sizeclass]; assert(fullslabs[sizeclass] != al); } }