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

enumerate name space

compiling, but unused, primitive rcu
上级 50d66311
...@@ -28,7 +28,8 @@ OBJS = \ ...@@ -28,7 +28,8 @@ OBJS = \
uart.o\ uart.o\
vectors.o\ vectors.o\
vm.o\ vm.o\
ns.o ns.o \
rcu.o
# Cross-compiling (e.g., on Mac OS X) # Cross-compiling (e.g., on Mac OS X)
TOOLPREFIX = x86_64-jos-elf- TOOLPREFIX = x86_64-jos-elf-
......
...@@ -102,6 +102,8 @@ int ns_allockey(struct ns*); ...@@ -102,6 +102,8 @@ int ns_allockey(struct ns*);
int ns_insert(struct ns*, int key, void*); int ns_insert(struct ns*, int key, void*);
void* ns_lookup(struct ns*, int); void* ns_lookup(struct ns*, int);
int ns_remove(struct ns *ns, int key); int ns_remove(struct ns *ns, int key);
void ns_enumerate(struct ns *ns, void (*f)(int, void *));
// picirq.c // picirq.c
void picenable(int); void picenable(int);
...@@ -122,7 +124,6 @@ int fork(int); ...@@ -122,7 +124,6 @@ int fork(int);
int growproc(int); int growproc(int);
int kill(int); int kill(int);
void pinit(void); void pinit(void);
void procdump(int);
void procdumpall(void); void procdumpall(void);
void scheduler(void) __attribute__((noreturn)); void scheduler(void) __attribute__((noreturn));
void sched(void); void sched(void);
...@@ -131,6 +132,9 @@ int wait(void); ...@@ -131,6 +132,9 @@ int wait(void);
void yield(void); void yield(void);
void migrate(void); void migrate(void);
// rcu.c
void rcuinit(void);
// swtch.S // swtch.S
void swtch(struct context**, struct context*); void swtch(struct context**, struct context*);
......
...@@ -51,6 +51,7 @@ mainc(void) ...@@ -51,6 +51,7 @@ mainc(void)
uartinit(); // serial port uartinit(); // serial port
kvmalloc(); // initialize the kernel page table kvmalloc(); // initialize the kernel page table
nsinit(); // initialize name space module nsinit(); // initialize name space module
rcuinit(); // initialize rcu module
pinit(); // process table pinit(); // process table
tvinit(); // trap vectors tvinit(); // trap vectors
binit(); // buffer cache binit(); // buffer cache
......
...@@ -124,3 +124,16 @@ ns_remove(struct ns *ns, int key) ...@@ -124,3 +124,16 @@ ns_remove(struct ns *ns, int key)
return r; return r;
} }
void
ns_enumerate(struct ns *ns, void (*f)(int, void *))
{
acquire(&ns->lock);
for (int i = 0; i < NHASH; i++) {
struct elem *e = TAILQ_FIRST(&(ns->table[i].chain));
while (e != NULL) {
(*f)(e->key, e->val);
e = TAILQ_NEXT(e, chain);
}
}
release(&ns->lock);
}
...@@ -12,3 +12,4 @@ ...@@ -12,3 +12,4 @@
#define MAXARG 32 // max exec arguments #define MAXARG 32 // max exec arguments
#define MAXNAME 16 // max string names #define MAXNAME 16 // max string names
#define MINCYCTHRESH 1000000 // min cycles a proc executes on a core before allowed to be stolen #define MINCYCTHRESH 1000000 // min cycles a proc executes on a core before allowed to be stolen
#define INF 0xFFFFFFFF
...@@ -11,8 +11,8 @@ ...@@ -11,8 +11,8 @@
struct runq runqs[NCPU]; struct runq runqs[NCPU];
int idle[NCPU]; int idle[NCPU];
struct ns *nspid;
static struct proc *initproc; static struct proc *initproc;
static struct ns *nspid;
extern void forkret(void); extern void forkret(void);
extern void trapret(void); extern void trapret(void);
...@@ -55,9 +55,11 @@ allocproc(void) ...@@ -55,9 +55,11 @@ allocproc(void)
p->state = EMBRYO; p->state = EMBRYO;
p->pid = ns_allockey(nspid); p->pid = ns_allockey(nspid);
p->epoch = INF;
p->cpuid = cpu->id;
if (ns_insert(nspid, p->pid, (void *) p) < 0) if (ns_insert(nspid, p->pid, (void *) p) < 0)
panic("allocproc: ns_insert"); panic("allocproc: ns_insert");
p->cpuid = cpu->id;
// Allocate kernel stack if possible. // Allocate kernel stack if possible.
if((p->kstack = kalloc()) == 0){ if((p->kstack = kalloc()) == 0){
...@@ -614,13 +616,10 @@ kill(int pid) ...@@ -614,13 +616,10 @@ kill(int pid)
return 0; return 0;
} }
//PAGEBREAK: 36 void procdump(int k, void *v)
// Print a process listing to console. For debugging.
// Runs when user types ^P on console.
// No lock to avoid wedging a stuck machine further.
void
procdump(int c)
{ {
struct proc *p = (struct proc *) v;
static char *states[] = { static char *states[] = {
[UNUSED] "unused", [UNUSED] "unused",
[EMBRYO] "embryo", [EMBRYO] "embryo",
...@@ -631,31 +630,27 @@ procdump(int c) ...@@ -631,31 +630,27 @@ procdump(int c)
}; };
char *state; char *state;
#if 0 if(p->state >= 0 && p->state < NELEM(states) && states[p->state])
state = states[p->state];
else
state = "???";
cprintf("%d %s %s %d, ", p->pid, state, p->name, p->cpuid);
uint pc[10]; uint pc[10];
if(p->state == SLEEPING){ if(p->state == SLEEPING){
getcallerpcs((uint*)p->context->ebp+2, pc); getcallerpcs((uint*)p->context->ebp+2, pc);
for(i=0; i<10 && pc[i] != 0; i++) for(int i=0; i<10 && pc[i] != 0; i++)
cprintf(" %p", pc[i]); cprintf(" %p", pc[i]);
} }
#endif
struct proc *q;
cprintf("runq: ");
STAILQ_FOREACH(q, &runqs[c].runq, run_next) {
if(q->state >= 0 && q->state < NELEM(states) && states[q->state])
state = states[q->state];
else
state = "???";
cprintf("%d %s %s, ", q->pid, state, q->name);
}
cprintf("\n"); cprintf("\n");
} }
//PAGEBREAK: 36
// Print a process listing to console. For debugging.
// Runs when user types ^P on console.
// No lock to avoid wedging a stuck machine further.
void void
procdumpall(void) procdumpall(void)
{ {
int c; ns_enumerate(nspid, procdump);
for (c = 0; c < NCPU; c++) {
procdump(c);
}
} }
...@@ -88,6 +88,7 @@ struct proc { ...@@ -88,6 +88,7 @@ struct proc {
SLIST_HEAD(childlist, proc) childq; SLIST_HEAD(childlist, proc) childq;
SLIST_ENTRY(proc) child_next; SLIST_ENTRY(proc) child_next;
struct condvar cv; struct condvar cv;
uint epoch;
}; };
// Process memory is laid out contiguously, low addresses first: // Process memory is laid out contiguously, low addresses first:
...@@ -129,6 +130,7 @@ extern struct cpu cpus[NCPU]; ...@@ -129,6 +130,7 @@ extern struct cpu cpus[NCPU];
extern struct runq runqs[NCPU]; extern struct runq runqs[NCPU];
extern struct condtab condtabs[NCPU]; extern struct condtab condtabs[NCPU];
extern int ncpu; extern int ncpu;
extern struct ns *nspid;
// Per-CPU variables, holding pointers to the // Per-CPU variables, holding pointers to the
// current cpu and to the current process. // current cpu and to the current process.
......
#include "types.h"
#include "defs.h"
#include "param.h"
#include "mmu.h"
#include "x86.h"
#include "spinlock.h"
#include "condvar.h"
#include "queue.h"
#include "proc.h"
#define NRCU 1000
#define NDELAY 500
struct rcu {
void *item;
unsigned long epoch;
struct rcu *rcu;
void (*dofree)(void *);
};
static struct rcu *rcu_delayed_head;
static struct rcu *rcu_delayed_tail;
static struct rcu *rcu_freelist;
static uint global_epoch;
static uint min_epoch;
static struct spinlock rcu_lock;
static int delayed_nfree;
static int ninuse;
void
rcuinit(void)
{
struct rcu *r;
int i;
initlock(&rcu_lock, "rcu");
for (i = 0; i < NRCU; i++) {
r = (struct rcu *) kmalloc(sizeof(struct rcu));
r->rcu = rcu_freelist;
rcu_freelist = r;
}
cprintf("rcu_init: allocated %ld bytes\n", sizeof(struct rcu) * NRCU);
}
struct rcu *
rcu_alloc()
{
struct rcu *r = rcu_freelist;
if (r == 0) {
panic("rcu_alloc");
}
rcu_freelist = r->rcu;
return r;
}
void
rcu_min(int key, void *v){
struct proc *p = (struct proc *) v;
if (min_epoch > p->epoch) {
min_epoch = p->epoch;
}
}
// XXX use atomic instruction to update list (instead of holding lock)
// lists of lists?
void
rcu_gc(void)
{
struct rcu *r, *nr;
int n = 0;
min_epoch = global_epoch;
ns_enumerate(nspid, rcu_min);
for (r = rcu_delayed_head; r != NULL; r = nr) {
if (r->epoch >= min_epoch)
break;
// printf("free: %ld\n", r->epoch);
if (r->dofree == 0)
panic("rcu_gc");
r->dofree(r->item);
delayed_nfree--;
n++;
rcu_delayed_head = r->rcu;
if (rcu_delayed_head == 0)
rcu_delayed_tail = 0;
nr = r->rcu;
r->rcu = rcu_freelist;
rcu_freelist = r;
}
// printf("rcu_gc: n=%d ndelayed_free=%d nfree=%d ninuse=%d\n", n, delayed_nfree,
// tree_nfree, tree_ninuse);
}
// XXX Use atomic instruction to update list (instead of holding lock)
void
rcu_delayed(void *e, void (*dofree)(void *))
{
struct rcu *r = rcu_alloc();
if (r == 0)
panic("rcu_delayed");
r->dofree = dofree;
r->item = e;
r->rcu = 0;
r->epoch = global_epoch;
// printf("rcu_delayed: %ld\n", global_epoch);
if (rcu_delayed_tail != 0)
rcu_delayed_tail->rcu = r;
rcu_delayed_tail = r;
if (rcu_delayed_head == 0) rcu_delayed_head = r;
delayed_nfree++;
ninuse--;
}
void
rcu_begin_read(int tid)
{
proc->epoch = global_epoch;
__sync_synchronize();
}
void
rcu_end_read(int tid)
{
proc->epoch = INF;
}
void
rcu_begin_write(int tid)
{
acquire(&rcu_lock);
}
void
rcu_end_write(int tid)
{
// for other data structures using rcu, use atomic add:
__sync_fetch_and_add(&global_epoch, 1);
rcu_gc();
release(&rcu_lock);
}
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论