Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
X
xv6-public
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
问题
0
问题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
银宸时代
OS Lab Group
奖励实验
xv6-public
提交
dc16e760
提交
dc16e760
10月 23, 2011
创建
作者:
Silas Boyd-Wickizer
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Start 64-biting proc.c, rcu.c, condvar.c, and ns.c
上级
3514d335
显示空白字符变更
内嵌
并排
正在显示
9 个修改的文件
包含
345 行增加
和
198 行删除
+345
-198
Makefile
Makefile
+4
-0
condvar.c
condvar.c
+10
-9
kalloc.c
kalloc.c
+157
-0
kernel.h
kernel.h
+91
-17
main.c
main.c
+2
-0
ns.c
ns.c
+11
-1
proc.c
proc.c
+18
-6
proc.h
proc.h
+5
-119
rcu.c
rcu.c
+47
-46
没有找到文件。
Makefile
浏览文件 @
dc16e760
...
...
@@ -3,11 +3,15 @@
OBJS
=
\
asm.o
\
cga.o
\
condvar.o
\
console.o
\
lapic.o
\
kalloc.o
\
main.o
\
mp.o
\
ns.o
\
proc.o
\
rcu.o
\
spinlock.o
\
string.o
\
uart.o
\
...
...
condvar.c
浏览文件 @
dc16e760
#include "types.h"
#include "defs.h"
#include "param.h"
#include "x86.h"
#include "mmu.h"
...
...
@@ -7,6 +6,8 @@
#include "condvar.h"
#include "queue.h"
#include "proc.h"
#include "kernel.h"
#include "cpu.h"
void
initcondvar
(
struct
condvar
*
cv
,
char
*
n
)
...
...
@@ -18,7 +19,7 @@ initcondvar(struct condvar *cv, char *n)
void
cv_sleep
(
struct
condvar
*
cv
,
struct
spinlock
*
lk
)
{
if
(
proc
==
0
)
if
(
myproc
()
==
0
)
panic
(
"sleep"
);
if
(
lk
==
0
)
...
...
@@ -29,20 +30,20 @@ cv_sleep(struct condvar *cv, struct spinlock *lk)
release
(
lk
);
acquire
(
&
proc
->
lock
);
acquire
(
&
myproc
()
->
lock
);
if
(
proc
->
cv_next
||
proc
->
oncv
)
if
(
myproc
()
->
cv_next
||
myproc
()
->
oncv
)
panic
(
"cv_sleep cv_next"
);
proc
->
cv_next
=
cv
->
waiters
;
cv
->
waiters
=
proc
;
proc
->
state
=
SLEEPING
;
proc
->
oncv
=
cv
;
myproc
()
->
cv_next
=
cv
->
waiters
;
cv
->
waiters
=
myproc
()
;
myproc
()
->
state
=
SLEEPING
;
myproc
()
->
oncv
=
cv
;
release
(
&
cv
->
lock
);
sched
();
release
(
&
proc
->
lock
);
release
(
&
myproc
()
->
lock
);
// Reacquire original lock.
acquire
(
lk
);
...
...
kalloc.c
浏览文件 @
dc16e760
...
...
@@ -9,6 +9,7 @@
#include "spinlock.h"
#include "kalloc.h"
#include "xv6-mtrace.h"
#include "cpu.h"
struct
kmem
kmems
[
NCPU
];
...
...
@@ -62,6 +63,59 @@ kfree_pool(struct kmem *m, char *v)
release
(
&
m
->
lock
);
}
static
void
__attribute__
((
unused
))
kmemprint
(
void
)
{
cprintf
(
"free pages: [ "
);
for
(
u32
i
=
0
;
i
<
NCPU
;
i
++
)
if
(
i
==
mycpu
()
->
id
)
cprintf
(
"<%d> "
,
kmems
[
i
].
nfree
);
else
cprintf
(
"%d "
,
kmems
[
i
].
nfree
);
cprintf
(
"]
\n
"
);
}
// Allocate one 4096-byte page of physical memory.
// Returns a pointer that the kernel can use.
// Returns 0 if the memory cannot be allocated.
char
*
kalloc
(
void
)
{
struct
run
*
r
=
0
;
// cprintf("%d: kalloc 0x%x 0x%x 0x%x 0x%x 0%x\n", cpu->id, kmem, &kmems[cpu->id], kmem->freelist, PHYSTOP, kmems[1].freelist);
u32
startcpu
=
mycpu
()
->
id
;
for
(
u32
i
=
0
;
r
==
0
&&
i
<
NCPU
;
i
++
)
{
int
cn
=
(
i
+
startcpu
)
%
NCPU
;
struct
kmem
*
m
=
&
kmems
[
cn
];
acquire
(
&
m
->
lock
);
r
=
m
->
freelist
;
if
(
r
)
{
m
->
freelist
=
r
->
next
;
m
->
nfree
--
;
}
release
(
&
m
->
lock
);
}
if
(
r
==
0
)
{
cprintf
(
"kalloc: out of memory
\n
"
);
kmemprint
();
return
0
;
}
mtrace_label_register
(
mtrace_label_block
,
r
,
4096
,
"kalloc"
,
sizeof
(
"kalloc"
),
RET_EIP
());
if
(
kalloc_memset
)
memset
(
r
,
2
,
PGSIZE
);
return
(
char
*
)
r
;
}
// Memory allocator by Kernighan and Ritchie,
// The C programming Language, 2nd ed. Section 8.7.
...
...
@@ -106,6 +160,109 @@ initkalloc(void)
kinited
=
1
;
}
static
void
domfree
(
void
*
ap
)
{
Header
*
bp
,
*
p
;
bp
=
(
Header
*
)
ap
-
1
;
if
(
kalloc_memset
)
memset
(
ap
,
3
,
(
bp
->
size
-
1
)
*
sizeof
(
*
bp
));
for
(
p
=
freelists
[
mycpu
()
->
id
].
freep
;
!
(
bp
>
p
&&
bp
<
p
->
ptr
);
p
=
p
->
ptr
)
if
(
p
>=
p
->
ptr
&&
(
bp
>
p
||
bp
<
p
->
ptr
))
break
;
if
(
bp
+
bp
->
size
==
p
->
ptr
){
bp
->
size
+=
p
->
ptr
->
size
;
bp
->
ptr
=
p
->
ptr
->
ptr
;
}
else
bp
->
ptr
=
p
->
ptr
;
if
(
p
+
p
->
size
==
bp
){
p
->
size
+=
bp
->
size
;
p
->
ptr
=
bp
->
ptr
;
}
else
p
->
ptr
=
bp
;
freelists
[
mycpu
()
->
id
].
freep
=
p
;
}
void
kmfree
(
void
*
ap
)
{
acquire
(
&
freelists
[
mycpu
()
->
id
].
lock
);
domfree
(
ap
);
mtrace_label_register
(
mtrace_label_heap
,
ap
,
0
,
0
,
0
,
RET_EIP
());
release
(
&
freelists
[
mycpu
()
->
id
].
lock
);
}
// Caller should hold free_locky
static
Header
*
morecore
(
u64
nu
)
{
static
u64
units_per_page
=
PGSIZE
/
sizeof
(
Header
);
char
*
p
;
Header
*
hp
;
if
(
nu
!=
units_per_page
)
{
if
(
nu
>
units_per_page
)
panic
(
"morecore"
);
nu
=
units_per_page
;
// we allocate nu * sizeof(Header)
}
p
=
kalloc
();
if
(
p
==
0
)
return
0
;
hp
=
(
Header
*
)
p
;
hp
->
size
=
nu
;
domfree
((
void
*
)(
hp
+
1
));
return
freelists
[
mycpu
()
->
id
].
freep
;
}
void
*
kmalloc
(
u64
nbytes
)
{
Header
*
p
,
*
prevp
;
u64
nunits
;
void
*
r
=
0
;
acquire
(
&
freelists
[
mycpu
()
->
id
].
lock
);
nunits
=
(
nbytes
+
sizeof
(
Header
)
-
1
)
/
sizeof
(
Header
)
+
1
;
if
((
prevp
=
freelists
[
mycpu
()
->
id
].
freep
)
==
0
){
freelists
[
mycpu
()
->
id
].
base
.
ptr
=
freelists
[
mycpu
()
->
id
].
freep
=
prevp
=
&
freelists
[
mycpu
()
->
id
].
base
;
freelists
[
mycpu
()
->
id
].
base
.
size
=
0
;
}
for
(
p
=
prevp
->
ptr
;
;
prevp
=
p
,
p
=
p
->
ptr
){
if
(
p
->
size
>=
nunits
){
if
(
p
->
size
==
nunits
)
prevp
->
ptr
=
p
->
ptr
;
else
{
p
->
size
-=
nunits
;
p
+=
p
->
size
;
p
->
size
=
nunits
;
}
freelists
[
mycpu
()
->
id
].
freep
=
prevp
;
r
=
(
void
*
)(
p
+
1
);
break
;
}
if
(
p
==
freelists
[
mycpu
()
->
id
].
freep
)
if
((
p
=
morecore
(
nunits
))
==
0
)
break
;
}
release
(
&
freelists
[
mycpu
()
->
id
].
lock
);
if
(
r
)
mtrace_label_register
(
mtrace_label_heap
,
r
,
nbytes
,
"kmalloc'ed"
,
sizeof
(
"kmalloc'ed"
),
RET_EIP
());
return
r
;
}
...
...
kernel.h
浏览文件 @
dc16e760
...
...
@@ -10,20 +10,93 @@ static inline uptr v2p(void *a) { return (uptr) a - KBASE; }
static
inline
void
*
p2v
(
uptr
a
)
{
return
(
void
*
)
a
+
KBASE
;
}
struct
spinlock
;
struct
condvar
;
struct
proc
;
// cga.c
void
cgaputc
(
char
c
);
// condvar.c
void
initcondvar
(
struct
condvar
*
,
char
*
);
void
cv_sleep
(
struct
condvar
*
cv
,
struct
spinlock
*
);
void
cv_wakeup
(
struct
condvar
*
cv
);
// console.c
void
cprintf
(
const
char
*
,
...);
void
panic
(
const
char
*
)
__attribute__
((
noreturn
));
// string.c
int
memcmp
(
const
void
*
,
const
void
*
,
u32
);
void
*
memmove
(
void
*
,
const
void
*
,
u32
);
void
*
memset
(
void
*
,
int
,
u32
);
char
*
safestrcpy
(
char
*
,
const
char
*
,
int
);
int
strlen
(
const
char
*
);
int
strncmp
(
const
char
*
,
const
char
*
,
u32
);
char
*
strncpy
(
char
*
,
const
char
*
,
int
);
int
strcmp
(
const
char
*
p
,
const
char
*
q
);
// kalloc.c
char
*
kalloc
(
void
);
void
kfree
(
void
*
);
void
*
kmalloc
(
u64
);
void
kmfree
(
void
*
);
// lapic.c
int
cpunum
(
void
);
// mp.c
extern
int
ncpu
;
// ns.c
enum
{
nskey_int
=
1
,
nskey_ii
,
nskey_str
,
nskey_dirname
,
nskey_iis
};
struct
nskey
{
int
type
;
union
{
u64
i
;
struct
{
u64
a
;
u64
b
;
}
ii
;
char
*
s
;
char
*
dirname
;
struct
{
u64
a
;
u64
b
;
char
*
s
;
}
iis
;
}
u
;
};
#define KI(v) (struct nskey){.type=nskey_int,.u.i=v}
#define KII(x,y) (struct nskey){.type=nskey_ii,.u.ii.a=x,.u.ii.b=y}
#define KS(v) (struct nskey){.type=nskey_str,.u.s=v}
#define KD(v) (struct nskey){.type=nskey_dirname,.u.dirname=v}
#define KIIS(x,y,z) (struct nskey){.type=nskey_iis,.u.iis.a=x, \
.u.iis.b=y, \
.u.iis.s=z}
void
nsinit
(
void
);
struct
ns
*
nsalloc
(
int
allowdup
);
void
nsfree
(
struct
ns
*
);
int
ns_allockey
(
struct
ns
*
);
int
ns_insert
(
struct
ns
*
,
struct
nskey
key
,
void
*
);
void
*
ns_lookup
(
struct
ns
*
,
struct
nskey
key
);
void
*
ns_remove
(
struct
ns
*
ns
,
struct
nskey
key
,
void
*
val
);
// removed val
void
*
ns_enumerate
(
struct
ns
*
ns
,
void
*
(
*
f
)(
void
*
,
void
*
,
void
*
),
void
*
arg
);
void
*
ns_enumerate_key
(
struct
ns
*
ns
,
struct
nskey
key
,
void
*
(
*
f
)(
void
*
,
void
*
),
void
*
arg
);
// proc.c
void
addrun
(
struct
proc
*
);
struct
proc
*
copyproc
(
struct
proc
*
);
void
exit
(
void
);
int
fork
(
int
);
int
growproc
(
int
);
int
kill
(
int
);
void
pinit
(
void
);
void
procdumpall
(
void
);
void
scheduler
(
void
)
__attribute__
((
noreturn
));
void
sched
(
void
);
void
userinit
(
void
);
int
wait
(
void
);
void
yield
(
void
);
void
migrate
(
struct
proc
*
);
// spinlock.c
void
acquire
(
struct
spinlock
*
);
...
...
@@ -34,14 +107,15 @@ void release(struct spinlock*);
void
pushcli
(
void
);
void
popcli
(
void
);
// cga.c
void
cgaputc
(
char
c
);
// string.c
int
memcmp
(
const
void
*
,
const
void
*
,
u32
);
void
*
memmove
(
void
*
,
const
void
*
,
u32
);
void
*
memset
(
void
*
,
int
,
u32
);
char
*
safestrcpy
(
char
*
,
const
char
*
,
int
);
int
strlen
(
const
char
*
);
int
strncmp
(
const
char
*
,
const
char
*
,
u32
);
char
*
strncpy
(
char
*
,
const
char
*
,
int
);
int
strcmp
(
const
char
*
p
,
const
char
*
q
);
// uart.c
void
uartputc
(
char
c
);
// mp.c
extern
int
ncpu
;
// lapic.c
int
cpunum
(
void
);
main.c
浏览文件 @
dc16e760
...
...
@@ -11,6 +11,7 @@ extern void initlapic(void);
extern
void
initseg
(
void
);
extern
void
inittrap
(
void
);
extern
void
initkalloc
(
void
);
extern
void
initrcu
(
void
);
void
cmain
(
void
)
...
...
@@ -26,6 +27,7 @@ cmain(void)
initseg
();
initkalloc
();
initrcu
();
// initialize rcu module
cprintf
(
"ncpu %d
\n
"
,
ncpu
);
panic
(
"end"
);
...
...
ns.c
浏览文件 @
dc16e760
#include "types.h"
#include "kernel.h"
void
*
ns_enumerate
(
struct
ns
*
ns
,
void
*
(
*
f
)(
void
*
,
void
*
,
void
*
),
void
*
arg
)
{
panic
(
"ns_enumerate"
);
}
#if 0
#include "types.h"
#include "defs.h"
#include "spinlock.h"
#include "param.h"
...
...
@@ -321,4 +331,4 @@ ns_enumerate_key(struct ns *ns, struct nskey key, void *(*f)(void *, void *), vo
rcu_end_read
();
return
0
;
}
#endif
proc.c
浏览文件 @
dc16e760
#include "types.h"
#include "
defs
.h"
#include "
kernel
.h"
#include "param.h"
#include "memlayout.h"
#include "mmu.h"
...
...
@@ -8,13 +8,24 @@
#include "condvar.h"
#include "queue.h"
#include "proc.h"
#include "xv6-kmtrace.h"
int
__attribute__
((
aligned
(
CACHELINE
)))
idle
[
NCPU
];
struct
ns
*
nspid
__attribute__
((
aligned
(
CACHELINE
)));
struct
ns
*
nsrunq
__attribute__
((
aligned
(
CACHELINE
)));
static
struct
proc
*
initproc
__attribute__
((
aligned
(
CACHELINE
)));
int
__mpalign__
idle
[
NCPU
];
struct
ns
*
nspid
__mpalign__
;
struct
ns
*
nsrunq
__mpalign__
;
void
sched
(
void
)
{
panic
(
"sched"
);
}
void
addrun
(
struct
proc
*
p
)
{
panic
(
"addrun"
);
}
#if 0
extern void forkret(void);
extern void trapret(void);
...
...
@@ -720,3 +731,4 @@ procdumpall(void)
{
ns_enumerate(nspid, procdump, 0);
}
#endif
proc.h
浏览文件 @
dc16e760
#include "spinlock.h"
// Segments in proc->gdt.
// Also known to bootasm.S and trapasm.S
#define SEG_KCODE 1 // kernel code
#define SEG_KDATA 2 // kernel data+stack
#define SEG_KCPU 3 // kernel per-cpu data
#define SEG_UCODE 4 // user code
#define SEG_UDATA 5 // user data+stack
#define SEG_TSS 6 // this process's task state
#define NSEGS 7
//PAGEBREAK: 17
// Saved registers for kernel context switches.
// Don't need to save all the segment registers (%cs, etc),
// because they are constant across kernel contexts.
// Don't need to save %eax, %ecx, %edx, because the
// x86 convention is that the caller has saved them.
// Contexts are stored at the bottom of the stack they
// describe; the stack pointer is the address of the context.
// The layout of the context matches the layout of the stack in swtch.S
// at the "Switch stacks" comment. Switch doesn't save eip explicitly,
// but it is on the stack and allocproc() manipulates it.
struct
context
{
uint
edi
;
uint
esi
;
uint
ebx
;
uint
ebp
;
uint
eip
;
};
enum
procstate
{
UNUSED
,
EMBRYO
,
SLEEPING
,
RUNNABLE
,
RUNNING
,
ZOMBIE
};
// A memory object (physical pages or inode).
enum
vmntype
{
EAGER
,
ONDEMAND
};
struct
vmnode
{
uint
npages
;
char
*
page
[
128
];
uint
ref
;
enum
vmntype
type
;
struct
inode
*
ip
;
uint
offset
;
uint
sz
;
};
// A mapping of a chunk of an address space to
// a specific memory object.
enum
vmatype
{
PRIVATE
,
COW
};
struct
vma
{
uint
va_start
;
// start of mapping
uint
va_end
;
// one past the last byte
enum
vmatype
va_type
;
struct
vmnode
*
n
;
struct
spinlock
lock
;
// serialize fault/unmap
char
lockname
[
16
];
};
#define TREE
// An address space: a set of vmas plus h/w page table.
// The elements of e[] are not ordered by address.
struct
vmap
{
#ifdef TREE
struct
node
*
root
;
#else
struct
vma
*
e
[
16
];
#endif
struct
spinlock
lock
;
// serialize map/lookup/unmap
uint
ref
;
uint
alloc
;
pde_t
*
pgdir
;
// Page table
char
lockname
[
16
];
};
// Per-process, per-stack meta data for mtrace
#define MTRACE_NSTACKS 16
#define MTRACE_TAGSHIFT 28
...
...
@@ -84,10 +12,12 @@ struct mtrace_stacks {
unsigned
long
tag
[
MTRACE_NSTACKS
];
};
enum
procstate
{
UNUSED
,
EMBRYO
,
SLEEPING
,
RUNNABLE
,
RUNNING
,
ZOMBIE
};
// Per-process state
struct
proc
{
struct
vmap
*
vmap
;
// va -> vma
u
int
brk
;
// Top of heap
u
ptr
brk
;
// Top of heap
char
*
kstack
;
// Bottom of kernel stack for this process
enum
procstate
state
;
// Process state
volatile
int
pid
;
// Process ID
...
...
@@ -107,56 +37,12 @@ struct proc {
SLIST_HEAD
(
childlist
,
proc
)
childq
;
SLIST_ENTRY
(
proc
)
child_next
;
struct
condvar
cv
;
u
int
epoch
;
u
int
rcu_read_depth
;
u
64
epoch
;
u
64
rcu_read_depth
;
char
lockname
[
16
];
int
on_runq
;
int
cpu_pin
;
struct
mtrace_stacks
mtrace_stacks
;
};
// Process memory is laid out contiguously, low addresses first:
// text
// original data and bss
// fixed-size stack
// expandable heap
// Per-CPU state
struct
cpu
{
uchar
id
;
// Local APIC ID; index into cpus[] below
struct
context
*
scheduler
;
// swtch() here to enter scheduler
struct
taskstate
ts
;
// Used by x86 to find stack for interrupt
struct
segdesc
gdt
[
NSEGS
];
// x86 global descriptor table
volatile
uint
booted
;
// Has the CPU started?
int
ncli
;
// Depth of pushcli nesting.
int
intena
;
// Were interrupts enabled before pushcli?
int
last_rcu_gc_ticks
;
// Cpu-local storage variables; see below
struct
cpu
*
cpu
;
struct
proc
*
proc
;
// The currently-running process.
struct
kmem
*
kmem
;
// The per-core memory table
}
__attribute__
((
aligned
(
CACHELINE
)));
struct
condtab
{
char
name
[
MAXNAME
];
struct
spinlock
lock
;
struct
condvar
condtab
[
NPROC
];
}
__attribute__
((
aligned
(
CACHELINE
)));
extern
struct
cpu
cpus
[
NCPU
];
extern
struct
condtab
condtabs
[
NCPU
];
extern
int
ncpu
;
extern
struct
ns
*
nspid
;
// Per-CPU variables, holding pointers to the
// current cpu and to the current process.
// The asm suffix tells gcc to use "%gs:0" to refer to cpu
// and "%gs:4" to refer to proc. seginit sets up the
// %gs segment register so that %gs refers to the memory
// holding those two variables in the local cpu's struct cpu.
// This is similar to how thread-local variables are implemented
// in thread libraries such as Linux pthreads.
extern
struct
cpu
*
cpu
__asm
(
"%gs:0"
);
// &cpus[cpunum()].cpu
extern
struct
proc
*
proc
__asm
(
"%gs:4"
);
// cpus[cpunum()].proc
extern
struct
kmem
*
kmem
__asm
(
"%gs:8"
);
// &cpu[cpunum()].kmem
rcu.c
浏览文件 @
dc16e760
#include "types.h"
#include "defs.h"
#include "param.h"
#include "kernel.h"
#include "mmu.h"
#include "x86.h"
#include "spinlock.h"
#include "condvar.h"
#include "queue.h"
#include "proc.h"
#include "xv6-kmtrace.h"
#include "cpu.h"
#include "xv6-mtrace.h"
struct
rcu
{
unsigned
long
epoch
;
...
...
@@ -19,9 +20,9 @@ struct rcu {
}
f1
;
struct
{
void
(
*
dofree
)(
int
,
u
int
);
void
(
*
dofree
)(
int
,
u
64
);
int
arg1
;
u
int
arg2
;
u
64
arg2
;
}
f2
;
};
int
type
;
...
...
@@ -29,24 +30,14 @@ struct rcu {
TAILQ_HEAD
(
rcu_head
,
rcu
);
static
struct
{
struct
rcu_head
x
__
attribute__
((
aligned
(
CACHELINE
)))
;
}
rcu_q
[
NCPU
];
static
u
int
global_epoch
__attribute__
((
aligned
(
CACHELINE
)))
;
static
struct
{
struct
spinlock
l
__
attribute__
((
aligned
(
CACHELINE
)))
;
}
rcu_lock
[
NCPU
];
static
struct
{
int
v
__
attribute__
((
aligned
(
CACHELINE
)))
;
}
delayed_nfree
[
NCPU
];
static
struct
{
struct
condvar
cv
__
attribute__
((
aligned
(
CACHELINE
)))
;
}
rcu_cv
[
NCPU
];
static
struct
{
struct
rcu_head
x
__
mpalign__
;
}
rcu_q
[
NCPU
];
static
u
64
global_epoch
__mpalign__
;
static
struct
{
struct
spinlock
l
__
mpalign__
;
}
rcu_lock
[
NCPU
];
static
struct
{
int
v
__
mpalign__
;
}
delayed_nfree
[
NCPU
];
static
struct
{
struct
condvar
cv
__
mpalign__
;
}
rcu_cv
[
NCPU
];
enum
{
rcu_debug
=
0
};
void
rcuinit
(
void
)
{
for
(
int
i
=
0
;
i
<
NCPU
;
i
++
)
{
initlock
(
&
rcu_lock
[
i
].
l
,
"rcu"
);
TAILQ_INIT
(
&
rcu_q
[
i
].
x
);
initcondvar
(
&
rcu_cv
[
i
].
cv
,
"rcu_gc_cv"
);
}
}
struct
rcu
*
rcu_alloc
()
{
...
...
@@ -55,7 +46,7 @@ rcu_alloc()
void
*
rcu_min
(
void
*
vkey
,
void
*
v
,
void
*
arg
){
u
int
*
min_epoch_p
=
arg
;
u
64
*
min_epoch_p
=
arg
;
struct
proc
*
p
=
(
struct
proc
*
)
v
;
if
(
*
min_epoch_p
>
p
->
epoch
)
{
*
min_epoch_p
=
p
->
epoch
;
...
...
@@ -69,18 +60,18 @@ void
rcu_gc_work
(
void
)
{
struct
rcu
*
r
,
*
nr
;
u
int
min_epoch
=
global_epoch
;
u
64
min_epoch
=
global_epoch
;
int
n
=
0
;
ns_enumerate
(
nspid
,
rcu_min
,
&
min_epoch
);
// pushcli(); // not necessary: rcup->cpu_pin==1
acquire
(
&
rcu_lock
[
cpu
->
id
].
l
);
acquire
(
&
rcu_lock
[
mycpu
()
->
id
].
l
);
for
(
r
=
TAILQ_FIRST
(
&
rcu_q
[
cpu
->
id
].
x
);
r
!=
NULL
;
r
=
nr
)
{
for
(
r
=
TAILQ_FIRST
(
&
rcu_q
[
mycpu
()
->
id
].
x
);
r
!=
NULL
;
r
=
nr
)
{
if
(
r
->
epoch
>=
min_epoch
)
break
;
release
(
&
rcu_lock
[
cpu
->
id
].
l
);
release
(
&
rcu_lock
[
mycpu
()
->
id
].
l
);
// cprintf("free: %d (%x %x)\n", r->epoch, r->dofree, r->item);
switch
(
r
->
type
)
{
...
...
@@ -94,17 +85,17 @@ rcu_gc_work(void)
panic
(
"rcu type"
);
}
acquire
(
&
rcu_lock
[
cpu
->
id
].
l
);
delayed_nfree
[
cpu
->
id
].
v
--
;
acquire
(
&
rcu_lock
[
mycpu
()
->
id
].
l
);
delayed_nfree
[
mycpu
()
->
id
].
v
--
;
n
++
;
nr
=
TAILQ_NEXT
(
r
,
link
);
TAILQ_REMOVE
(
&
rcu_q
[
cpu
->
id
].
x
,
r
,
link
);
TAILQ_REMOVE
(
&
rcu_q
[
mycpu
()
->
id
].
x
,
r
,
link
);
kmfree
(
r
);
}
release
(
&
rcu_lock
[
cpu
->
id
].
l
);
release
(
&
rcu_lock
[
mycpu
()
->
id
].
l
);
if
(
rcu_debug
)
cprintf
(
"rcu_gc: cpu %d n %d delayed_nfree=%d min_epoch=%d
\n
"
,
cpu
->
id
,
n
,
delayed_nfree
[
cpu
->
id
],
min_epoch
);
mycpu
()
->
id
,
n
,
delayed_nfree
[
mycpu
()
->
id
],
min_epoch
);
// popcli(); // not necessary: rcup->cpu_pin==1
// global_epoch can be bumped anywhere; this seems as good a place as any
...
...
@@ -114,9 +105,9 @@ rcu_gc_work(void)
void
rcu_gc_worker
(
void
)
{
release
(
&
proc
->
lock
);
// initially held by scheduler
release
(
&
myproc
()
->
lock
);
// initially held by scheduler
mtrace_kstack_start
(
rcu_gc_worker
,
proc
);
mtrace_kstack_start
(
rcu_gc_worker
,
myproc
()
);
struct
spinlock
wl
;
initlock
(
&
wl
,
"rcu_gc_worker"
);
// dummy lock
...
...
@@ -125,7 +116,7 @@ rcu_gc_worker(void)
rcu_gc_work
();
acquire
(
&
wl
);
cv_sleep
(
&
rcu_cv
[
cpu
->
id
].
cv
,
&
wl
);
cv_sleep
(
&
rcu_cv
[
mycpu
()
->
id
].
cv
,
&
wl
);
release
(
&
wl
);
}
}
...
...
@@ -133,7 +124,7 @@ rcu_gc_worker(void)
void
rcu_gc
(
void
)
{
cv_wakeup
(
&
rcu_cv
[
cpu
->
id
].
cv
);
cv_wakeup
(
&
rcu_cv
[
mycpu
()
->
id
].
cv
);
}
// XXX Use atomic instruction to update list (instead of holding lock)
...
...
@@ -141,11 +132,11 @@ static void
rcu_delayed_int
(
struct
rcu
*
r
)
{
pushcli
();
acquire
(
&
rcu_lock
[
cpu
->
id
].
l
);
acquire
(
&
rcu_lock
[
mycpu
()
->
id
].
l
);
// cprintf("rcu_delayed: %d\n", global_epoch);
TAILQ_INSERT_TAIL
(
&
rcu_q
[
cpu
->
id
].
x
,
r
,
link
);
delayed_nfree
[
cpu
->
id
].
v
++
;
release
(
&
rcu_lock
[
cpu
->
id
].
l
);
TAILQ_INSERT_TAIL
(
&
rcu_q
[
mycpu
()
->
id
].
x
,
r
,
link
);
delayed_nfree
[
mycpu
()
->
id
].
v
++
;
release
(
&
rcu_lock
[
mycpu
()
->
id
].
l
);
popcli
();
}
...
...
@@ -166,7 +157,7 @@ rcu_delayed(void *e, void (*dofree)(void *))
}
void
rcu_delayed2
(
int
a1
,
u
int
a2
,
void
(
*
dofree
)(
int
,
uint
))
rcu_delayed2
(
int
a1
,
u
64
a2
,
void
(
*
dofree
)(
int
,
u64
))
{
struct
rcu
*
r
=
rcu_alloc
();
if
(
r
==
0
)
...
...
@@ -182,24 +173,25 @@ rcu_delayed2(int a1, uint a2, void (*dofree)(int,uint))
void
rcu_begin_read
(
void
)
{
if
(
proc
&&
proc
->
rcu_read_depth
++
==
0
)
proc
->
epoch
=
global_epoch
;
if
(
myproc
()
&&
myproc
()
->
rcu_read_depth
++
==
0
)
myproc
()
->
epoch
=
global_epoch
;
__sync_synchronize
();
}
void
rcu_end_read
(
void
)
{
if
(
proc
&&
proc
->
rcu_read_depth
>
0
&&
--
proc
->
rcu_read_depth
==
0
)
proc
->
epoch
=
INF
;
if
(
myproc
()
&&
myproc
()
->
rcu_read_depth
>
0
&&
--
myproc
()
->
rcu_read_depth
==
0
)
myproc
()
->
epoch
=
INF
;
}
void
rcu_begin_write
(
struct
spinlock
*
l
)
{
if
(
l
)
acquire
(
l
);
if
(
l
)
acquire
(
l
);
__sync_synchronize
();
rcu_begin_read
();
}
...
...
@@ -207,7 +199,16 @@ void
rcu_end_write
(
struct
spinlock
*
l
)
{
rcu_end_read
();
if
(
l
)
release
(
l
);
if
(
l
)
release
(
l
);
}
void
initrcu
(
void
)
{
for
(
int
i
=
0
;
i
<
NCPU
;
i
++
)
{
initlock
(
&
rcu_lock
[
i
].
l
,
"rcu"
);
TAILQ_INIT
(
&
rcu_q
[
i
].
x
);
initcondvar
(
&
rcu_cv
[
i
].
cv
,
"rcu_gc_cv"
);
}
}
编写
预览
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论