diff options
Diffstat (limited to 'src/lib9p/intmap.c')
-rw-r--r-- | src/lib9p/intmap.c | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/src/lib9p/intmap.c b/src/lib9p/intmap.c new file mode 100644 index 00000000..48695675 --- /dev/null +++ b/src/lib9p/intmap.c @@ -0,0 +1,166 @@ +#include <u.h> +#include <libc.h> +#include <auth.h> +#include <fcall.h> +#include <thread.h> +#include <9p.h> + +enum { + NHASH = 128 +}; + +typedef struct Intlist Intlist; +struct Intlist +{ + ulong id; + void* aux; + Intlist* link; +}; + +struct Intmap +{ + RWLock rwlock; + Intlist* hash[NHASH]; + void (*inc)(void*); +}; + +static ulong +hashid(ulong id) +{ + return id%NHASH; +} + +static void +nop(void *v) +{ + USED(v); +} + +Intmap* +allocmap(void (*inc)(void*)) +{ + Intmap *m; + + m = emalloc9p(sizeof(*m)); + if(inc == nil) + inc = nop; + m->inc = inc; + return m; +} + +void +freemap(Intmap *map, void (*destroy)(void*)) +{ + int i; + Intlist *p, *nlink; + + if(destroy == nil) + destroy = nop; + for(i=0; i<NHASH; i++){ + for(p=map->hash[i]; p; p=nlink){ + nlink = p->link; + destroy(p->aux); + free(p); + } + } + + free(map); +} + +static Intlist** +llookup(Intmap *map, ulong id) +{ + Intlist **lf; + + for(lf=&map->hash[hashid(id)]; *lf; lf=&(*lf)->link) + if((*lf)->id == id) + break; + return lf; +} + +/* + * The RWlock is used as expected except that we allow + * inc() to be called while holding it. This is because we're + * locking changes to the tree structure, not to the references. + * Inc() is expected to have its own locking. + */ +void* +lookupkey(Intmap *map, ulong id) +{ + Intlist *f; + void *v; + + rlock(&map->rwlock); + if(f = *llookup(map, id)){ + v = f->aux; + map->inc(v); + }else + v = nil; + runlock(&map->rwlock); + return v; +} + +void* +insertkey(Intmap *map, ulong id, void *v) +{ + Intlist *f; + void *ov; + ulong h; + + wlock(&map->rwlock); + if(f = *llookup(map, id)){ + /* no decrement for ov because we're returning it */ + ov = f->aux; + f->aux = v; + }else{ + f = emalloc9p(sizeof(*f)); + f->id = id; + f->aux = v; + h = hashid(id); + f->link = map->hash[h]; + map->hash[h] = f; + ov = nil; + } + wunlock(&map->rwlock); + return ov; +} + +int +caninsertkey(Intmap *map, ulong id, void *v) +{ + Intlist *f; + int rv; + ulong h; + + wlock(&map->rwlock); + if(*llookup(map, id)) + rv = 0; + else{ + f = emalloc9p(sizeof *f); + f->id = id; + f->aux = v; + h = hashid(id); + f->link = map->hash[h]; + map->hash[h] = f; + rv = 1; + } + wunlock(&map->rwlock); + return rv; +} + +void* +deletekey(Intmap *map, ulong id) +{ + Intlist **lf, *f; + void *ov; + + wlock(&map->rwlock); + if(f = *(lf = llookup(map, id))){ + ov = f->aux; + *lf = f->link; + free(f); + }else + ov = nil; + wunlock(&map->rwlock); + return ov; +} |