|  | #include <u.h> | 
|  | #include <libc.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; | 
|  | } |