HASHINIT(9)

πŸ’– HASHINIT πŸ’– β€” like, the kernel hash table manual, but make it make sense

okay bestie, welcome to HASHINIT(9) from the Kernel Developer's Manual 🧚 this is the page that teaches you how the kernel handles hash tables, and honestly? it's giving "small API, big feelings." let's get into it πŸ’…


✨ NAME ✨

hashinit, hashinit_flags, hashdestroy, phashinit, phashinit_flags β€” the whole girl group that manages kernel hash tables πŸŽ€


🌸 SYNOPSIS 🌸

so first you gotta pull in the headers, no cap:

#include <sys/malloc.h>
#include <sys/systm.h>
#include <sys/queue.h>

then here's the cast, line by line, exactly as written:

void *
hashinit(int nelements, struct malloc_type *type, u_long *hashmask);

void
hashinit_flags(int nelements, struct malloc_type *type,
    u_long *hashmask, int flags);

void
hashdestroy(void *hashtbl, struct malloc_type *type, u_long hashmask);

void *
phashinit(int nelements, struct malloc_type *type, u_long *nentries);

phashinit_flags(int nelements, struct malloc_type *type,
    u_long *nentries, int flags);

πŸ¦‹ DESCRIPTION πŸ¦‹

okay so hashinit(), hashinit_flags(), phashinit() and phashinit_flags() all do the same main-character thing: they allocate space for hash tables, and the size of that table is given by the argument nelements. periodt. πŸ’«

here's where the sisters diverge:

  • hashinit() allocates hash tables that are sized to the largest power of two less than or equal to the argument nelements. math queen behavior πŸ”₯
  • phashinit() allocates hash tables that are sized to the largest prime number less than or equal to the argument nelements. primes only, she's picky πŸ’…
  • hashinit_flags() operates like hashinit() but also accepts an additional argument flags, which controls various options during allocation.
  • phashinit_flags() operates like phashinit() but also accepts an additional argument flags, which controls various options during allocation.

and the tables themselves? allocated hash tables are contiguous arrays of LIST_HEAD(3) entries, allocated using malloc(9), and initialized using LIST_INIT(3). the malloc arena you're pulling from is pointed to by the argument type. iykyk 🫢

now, hashdestroy() is the one who cleans up: it frees the space occupied by the hash table pointed to by the argument hashtbl. the argument type determines the malloc arena to use when freeing space. and the argument hashmask should be the bit mask returned by the call to hashinit() that allocated the hash table. like, it has to match, bestie, don't be messy 😭

and the argument flags must be used with one of the following values:

  • HASH_NOWAIT β€” any malloc performed by the hashinit_flags() and phashinit_flags() function will not be allowed to wait, and therefore may fail. highkey risky, lowkey iconic πŸ’€
  • HASH_WAITOK β€” any malloc performed by hashinit_flags() and phashinit_flags() function is allowed to wait for memory. this is also the behavior of hashinit() and phashinit(). so that's the default vibe ✨

πŸ”₯ IMPLEMENTATION NOTES πŸ”₯

fun fact for the group chat: the largest prime hash value chosen by phashinit() is 32749. that's it, that's the number, write it down πŸ“


πŸ‘‘ RETURN VALUES πŸ‘‘

  • the hashinit() function returns a pointer to an allocated hash table and sets the location pointed to by hashmask to the bit mask to be used for computing the correct slot in the hash table. so you get the table and the mask, two gifts in one πŸ’
  • the phashinit() function returns a pointer to an allocated hash table and sets the location pointed to by nentries to the number of rows in the hash table. rows count, we love to see it 🧚

🌈 EXAMPLES 🌈

a typical example is shown below, and yes it's as cute as it looks:

...
static LIST_HEAD(foo, foo) *footable;
static u_long foomask;
...
footable = hashinit(32, M_FOO, &foomask);

here we allocate a hash table with 32 entries from the malloc arena pointed to by M_FOO. the mask for the allocated hash table is returned in foomask. a subsequent call to hashdestroy() uses the value in foomask:

...
hashdestroy(footable, M_FOO, foomask);

see how the mask comes back around? full circle moment 🫢


πŸ’€ DIAGNOSTICS πŸ’€

okay so here's where it gets serious. the hashinit() and phashinit() functions will panic if argument nelements is less than or equal to zero.
and the hashdestroy() function will panic if the hash table pointed to by hashtbl is not empty. so, like, empty it first, bestie, fr fr 😭

πŸŽ€ SEE ALSO πŸŽ€


πŸ™ˆ BUGS πŸ™ˆ

so, the tea: there is no phashdestroy() function, and using hashdestroy() to free a hash table allocated by phashinit() usually has grave consequences. not me finding out the hard way πŸ’€ consider yourself warned, gorgeous.


and that's the whole page, bestie!! πŸ’– this was the HASHINIT(9) manual, from the Debian crew, dated April 29, 2016 β€” mwah, iconic, no notes, go allocate something responsibly πŸŒΈπŸ¦‹βœ¨

πŸ“¦ where this page comes from