mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-15 11:20:03 +00:00
2277c5d7bb
Lots of new code imported.
166 lines
2.3 KiB
C
166 lines
2.3 KiB
C
#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;
|
|
}
|