提交 d57e7faf 创建 作者: Frans Kaashoek's avatar Frans Kaashoek

One RCU usage

Run rcu_gc periodically in a separate kernel thread?
上级 0e1ee117
...@@ -75,8 +75,6 @@ void kfree(char*); ...@@ -75,8 +75,6 @@ void kfree(char*);
void* kmalloc(uint); void* kmalloc(uint);
void kmfree(void*); void kmfree(void*);
// kbd.c // kbd.c
void kbdintr(void); void kbdintr(void);
...@@ -136,6 +134,9 @@ void migrate(void); ...@@ -136,6 +134,9 @@ void migrate(void);
void rcuinit(void); void rcuinit(void);
void rcu_begin_write(struct spinlock *); void rcu_begin_write(struct spinlock *);
void rcu_end_write(struct spinlock *); void rcu_end_write(struct spinlock *);
void rcu_begin_read(void);
void rcu_end_read(void);
void rcu_delayed(void*, void (*dofree)(void*));
// swtch.S // swtch.S
void swtch(struct context**, struct context*); void swtch(struct context**, struct context*);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
// XXX maybe use open hash table, no chain, better cache locality // XXX maybe use open hash table, no chain, better cache locality
#define NHASH 100 #define NHASH 100
static int rcu = 0; static int rcu = 1;
#define ACQUIRE(l) (rcu) ? rcu_begin_write(l) : acquire(l) #define ACQUIRE(l) (rcu) ? rcu_begin_write(l) : acquire(l)
#define RELEASE(l) (rcu) ? rcu_end_write(l) : release(l) #define RELEASE(l) (rcu) ? rcu_end_write(l) : release(l)
...@@ -109,9 +109,14 @@ ns_dolookup(struct ns *ns, int key) ...@@ -109,9 +109,14 @@ ns_dolookup(struct ns *ns, int key)
void* void*
ns_lookup(struct ns *ns, int key) ns_lookup(struct ns *ns, int key)
{ {
ACQUIRE(&ns->lock); if (rcu) rcu_begin_read();
else acquire(&ns->lock);
struct elem *e = ns_dolookup(ns, key); struct elem *e = ns_dolookup(ns, key);
RELEASE(&ns->lock);
if (rcu) rcu_begin_read();
else release(&ns->lock);
return (e == 0)? 0 : e->val; return (e == 0)? 0 : e->val;
} }
...@@ -123,7 +128,8 @@ ns_remove(struct ns *ns, int key) ...@@ -123,7 +128,8 @@ ns_remove(struct ns *ns, int key)
struct elem *e = ns_dolookup(ns, key); struct elem *e = ns_dolookup(ns, key);
if (e) { if (e) {
TAILQ_REMOVE(&(ns->table[key % NHASH].chain), e, chain); TAILQ_REMOVE(&(ns->table[key % NHASH].chain), e, chain);
kmfree(e); if (rcu) rcu_delayed(e, kmfree);
else kmfree(e);
r = 0; r = 0;
} }
RELEASE(&ns->lock); RELEASE(&ns->lock);
......
...@@ -22,9 +22,7 @@ static struct rcu *rcu_freelist; ...@@ -22,9 +22,7 @@ static struct rcu *rcu_freelist;
static uint global_epoch; static uint global_epoch;
static uint min_epoch; static uint min_epoch;
static struct spinlock rcu_lock; static struct spinlock rcu_lock;
static int delayed_nfree; static int delayed_nfree;
static int ninuse;
void void
rcuinit(void) rcuinit(void)
...@@ -39,7 +37,7 @@ rcuinit(void) ...@@ -39,7 +37,7 @@ rcuinit(void)
r->rcu = rcu_freelist; r->rcu = rcu_freelist;
rcu_freelist = r; rcu_freelist = r;
} }
cprintf("rcu_init: allocated %d bytes\n", sizeof(struct rcu) * NRCU); // cprintf("rcu_init: allocated %d bytes\n", sizeof(struct rcu) * NRCU);
} }
struct rcu * struct rcu *
...@@ -70,35 +68,27 @@ rcu_gc(void) ...@@ -70,35 +68,27 @@ rcu_gc(void)
int n = 0; int n = 0;
min_epoch = global_epoch; min_epoch = global_epoch;
acquire(&rcu_lock); acquire(&rcu_lock);
ns_enumerate(nspid, rcu_min); ns_enumerate(nspid, rcu_min);
for (r = rcu_delayed_head; r != NULL; r = nr) { for (r = rcu_delayed_head; r != NULL; r = nr) {
if (r->epoch >= min_epoch) if (r->epoch >= min_epoch)
break; break;
// cprintf("free: %d\n", r->epoch);
// printf("free: %ld\n", r->epoch);
if (r->dofree == 0) if (r->dofree == 0)
panic("rcu_gc"); panic("rcu_gc");
r->dofree(r->item); r->dofree(r->item);
delayed_nfree--; delayed_nfree--;
n++; n++;
rcu_delayed_head = r->rcu; rcu_delayed_head = r->rcu;
if (rcu_delayed_head == 0) if (rcu_delayed_head == 0)
rcu_delayed_tail = 0; rcu_delayed_tail = 0;
nr = r->rcu; nr = r->rcu;
r->rcu = rcu_freelist; r->rcu = rcu_freelist;
rcu_freelist = r; rcu_freelist = r;
} }
release(&rcu_lock); release(&rcu_lock);
// printf("rcu_gc: n=%d ndelayed_free=%d nfree=%d ninuse=%d\n", n, delayed_nfree, // cprintf("rcu_gc: n %d ndelayed_free=%d\n", n, delayed_nfree);
// tree_nfree, tree_ninuse);
} }
// XXX Use atomic instruction to update list (instead of holding lock) // XXX Use atomic instruction to update list (instead of holding lock)
...@@ -113,25 +103,24 @@ rcu_delayed(void *e, void (*dofree)(void *)) ...@@ -113,25 +103,24 @@ rcu_delayed(void *e, void (*dofree)(void *))
r->rcu = 0; r->rcu = 0;
r->epoch = global_epoch; r->epoch = global_epoch;
acquire(&rcu_lock); acquire(&rcu_lock);
// printf("rcu_delayed: %ld\n", global_epoch); // cprintf("rcu_delayed: %d\n", global_epoch);
if (rcu_delayed_tail != 0) if (rcu_delayed_tail != 0)
rcu_delayed_tail->rcu = r; rcu_delayed_tail->rcu = r;
rcu_delayed_tail = r; rcu_delayed_tail = r;
if (rcu_delayed_head == 0) rcu_delayed_head = r; if (rcu_delayed_head == 0) rcu_delayed_head = r;
release(&rcu_lock); release(&rcu_lock);
delayed_nfree++; delayed_nfree++;
ninuse--;
} }
void void
rcu_begin_read() rcu_begin_read(void)
{ {
proc->epoch = global_epoch; proc->epoch = global_epoch;
__sync_synchronize(); __sync_synchronize();
} }
void void
rcu_end_read() rcu_end_read(void)
{ {
proc->epoch = INF; proc->epoch = INF;
} }
...@@ -142,6 +131,8 @@ rcu_begin_write(struct spinlock *l) ...@@ -142,6 +131,8 @@ rcu_begin_write(struct spinlock *l)
acquire(l); acquire(l);
} }
// XXX if a process never rcu_end_write() infrequently we have a problem; run
// rcu_gc from a kernel thread periodically?
void void
rcu_end_write(struct spinlock *l) rcu_end_write(struct spinlock *l)
{ {
......
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论