Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
X
xv6-public
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
问题
0
问题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
银宸时代
OS Lab Group
奖励实验
xv6-public
提交
4e6609e5
提交
4e6609e5
2月 13, 2012
创建
作者:
Nickolai Zeldovich
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
no memory allocation in gc.cc, but a bug somewhere
上级
7ff543f9
隐藏空白字符变更
内嵌
并排
正在显示
11 个修改的文件
包含
140 行增加
和
140 行删除
+140
-140
bio.cc
bio.cc
+2
-2
buf.hh
buf.hh
+3
-1
crange.cc
crange.cc
+27
-1
file.hh
file.hh
+5
-1
fs.cc
fs.cc
+36
-20
gc.cc
gc.cc
+25
-92
gc.hh
gc.hh
+2
-5
kernel.h
kernel.h
+6
-13
ns.hh
ns.hh
+2
-2
proc.cc
proc.cc
+14
-1
vm.cc
vm.cc
+18
-2
没有找到文件。
bio.cc
浏览文件 @
4e6609e5
...
...
@@ -104,7 +104,7 @@ bget(u32 dev, u64 sector, int *writer)
bufns
->
remove
(
mkpair
(
victim
->
dev
,
victim
->
sector
),
&
victim
);
release
(
&
victim
->
lock
);
destroylock
(
&
victim
->
lock
);
gc_delayed
(
victim
,
kmfree
);
gc_delayed
(
victim
);
b
=
(
buf
*
)
kmalloc
(
sizeof
(
*
b
));
b
->
dev
=
dev
;
...
...
@@ -117,7 +117,7 @@ bget(u32 dev, u64 sector, int *writer)
gc_begin_epoch
();
if
(
bufns
->
insert
(
mkpair
(
b
->
dev
,
b
->
sector
),
b
)
<
0
)
{
destroylock
(
&
b
->
lock
);
gc_delayed
(
b
,
kmfree
);
gc_delayed
(
b
);
goto
loop
;
}
// rcu_end_read() happens in brelse
...
...
buf.hh
浏览文件 @
4e6609e5
struct
buf
{
#include "gc.hh"
struct
buf
:
public
rcu_freed
{
int
flags
;
u32
dev
;
u64
sector
;
...
...
crange.cc
浏览文件 @
4e6609e5
...
...
@@ -9,6 +9,8 @@ extern "C" {
#include "cpu.h"
}
#include "gc.hh"
//
// Concurrent atomic range operations using skip lists. An insert may split an
// existing range in several ranges. A delete may remove a sequence of ranges
...
...
@@ -54,6 +56,17 @@ extern "C" {
enum
{
crange_debug
=
0
};
enum
{
crange_checking
=
0
};
struct
range
{
u64
key
;
u64
size
;
void
*
value
;
int
curlevel
;
// the current levels it appears on
int
nlevel
;
// the number of levels this range should appear
struct
crange
*
cr
;
// the crange this range is part of
struct
range
**
next
;
// one next pointer per level
struct
spinlock
*
lock
;
// on separate cache line?
}
__mpalign__
;
struct
crange
{
int
nlevel
;
// number of levels in the crange skip list
struct
range
crange_head
;
// a crange skip list starts with a sentinel range (key 0, sz 0)
...
...
@@ -108,6 +121,17 @@ range_free(void *p)
kmalignfree
(
e
);
}
class
range_delayed
:
public
rcu_freed
{
private
:
struct
range
*
_e
;
public
:
range_delayed
(
range
*
e
)
:
_e
(
e
)
{}
virtual
~
range_delayed
()
{
range_free
(
_e
);
}
};
static
void
range_free_delayed
(
struct
range
*
e
)
{
...
...
@@ -115,7 +139,9 @@ range_free_delayed(struct range *e)
cprintf
(
"%d: range_free_delayed: 0x%lx 0x%lx-0x%lx(%lu) %lu
\n
"
,
myproc
()
->
pid
,
(
long
)
e
,
e
->
key
,
e
->
key
+
(
e
)
->
size
,
e
->
size
,
myproc
()
->
epoch
);
crange_check
(
e
->
cr
,
e
);
assert
(
e
->
curlevel
==
-
1
);
gc_delayed
(
e
,
range_free
);
range_delayed
*
rd
=
new
range_delayed
(
e
);
gc_delayed
(
rd
);
}
static
void
...
...
file.hh
浏览文件 @
4e6609e5
#include "cpputil.hh"
#include "ns.hh"
#include "gc.hh"
u64
namehash
(
const
strbuf
<
DIRSIZ
>&
);
...
...
@@ -18,7 +19,7 @@ struct file {
// in-core file system types
struct
inode
{
struct
inode
:
public
rcu_freed
{
u32
dev
;
// Device number
u32
inum
;
// Inode number
u32
gen
;
// Generation number
...
...
@@ -36,6 +37,9 @@ struct inode {
short
nlink
;
u32
size
;
u32
addrs
[
NDIRECT
+
1
];
inode
();
virtual
~
inode
();
};
#define I_BUSYR 0x1
...
...
fs.cc
浏览文件 @
4e6609e5
...
...
@@ -220,20 +220,21 @@ iupdate(struct inode *ip)
// But it has a ref count, so it won't be freed or reused.
// Though unlocked, all fields will be present,
// so looking a ip->inum and ip->gen are OK even w/o lock.
static
void
ifree
(
void
*
arg
)
inode
::
inode
()
{
struct
inode
*
ip
=
(
inode
*
)
arg
;
dir
=
0
;
}
if
(
ip
->
dir
)
{
ip
->
dir
->
remove
(
strbuf
<
DIRSIZ
>
(
"."
));
ip
->
dir
->
remove
(
strbuf
<
DIRSIZ
>
(
".."
));
gc_delayed
(
ip
->
dir
,
del_rcu_freed
);
ip
->
dir
=
0
;
inode
::~
inode
()
{
if
(
dir
)
{
dir
->
remove
(
strbuf
<
DIRSIZ
>
(
"."
));
dir
->
remove
(
strbuf
<
DIRSIZ
>
(
".."
));
gc_delayed
(
dir
);
dir
=
0
;
}
destroylock
(
&
ip
->
lock
);
kmfree
(
ip
);
destroylock
(
&
lock
);
}
struct
inode
*
...
...
@@ -295,13 +296,13 @@ iget(u32 dev, u32 inum)
}
release
(
&
victim
->
lock
);
ins
->
remove
(
mkpair
(
victim
->
dev
,
victim
->
inum
),
&
victim
);
gc_delayed
(
victim
,
ifree
);
gc_delayed
(
victim
);
}
else
{
if
(
!
__sync_bool_compare_and_swap
(
&
icache_free
[
mycpu
()
->
id
].
x
,
cur_free
,
cur_free
-
1
))
goto
retry_evict
;
}
ip
=
(
inode
*
)
kmalloc
(
sizeof
(
*
ip
)
);
ip
=
new
inode
(
);
ip
->
dev
=
dev
;
ip
->
inum
=
inum
;
ip
->
ref
=
1
;
...
...
@@ -310,10 +311,8 @@ iget(u32 dev, u32 inum)
snprintf
(
ip
->
lockname
,
sizeof
(
ip
->
lockname
),
"cv:ino:%d"
,
ip
->
inum
);
initlock
(
&
ip
->
lock
,
ip
->
lockname
+
3
,
LOCKSTAT_FS
);
initcondvar
(
&
ip
->
cv
,
ip
->
lockname
);
ip
->
dir
=
0
;
if
(
ins
->
insert
(
mkpair
(
ip
->
dev
,
ip
->
inum
),
ip
)
<
0
)
{
destroylock
(
&
ip
->
lock
);
gc_delayed
(
ip
,
kmfree
);
gc_delayed
(
ip
);
goto
retry
;
}
...
...
@@ -419,7 +418,7 @@ iput(struct inode *ip)
iupdate
(
ip
);
ins
->
remove
(
mkpair
(
ip
->
dev
,
ip
->
inum
),
&
ip
);
gc_delayed
(
ip
,
ifree
);
gc_delayed
(
ip
);
__sync_fetch_and_add
(
&
icache_free
[
mycpu
()
->
id
].
x
,
1
);
return
;
}
...
...
@@ -478,6 +477,18 @@ bmap(struct inode *ip, u32 bn)
// Truncate inode (discard contents).
// Only called after the last dirent referring
// to this inode has been erased on disk.
class
diskblock
:
public
rcu_freed
{
private
:
int
_dev
;
u64
_block
;
public
:
diskblock
(
int
dev
,
u64
block
)
:
_dev
(
dev
),
_block
(
block
)
{}
virtual
~
diskblock
()
{
bfree
(
_dev
,
_block
);
}
};
static
void
itrunc
(
struct
inode
*
ip
)
{
...
...
@@ -487,7 +498,8 @@ itrunc(struct inode *ip)
for
(
i
=
0
;
i
<
NDIRECT
;
i
++
){
if
(
ip
->
addrs
[
i
]){
gc_delayed2
(
ip
->
dev
,
ip
->
addrs
[
i
],
bfree
);
diskblock
*
db
=
new
diskblock
(
ip
->
dev
,
ip
->
addrs
[
i
]);
gc_delayed
(
db
);
ip
->
addrs
[
i
]
=
0
;
}
}
...
...
@@ -496,11 +508,15 @@ itrunc(struct inode *ip)
bp
=
bread
(
ip
->
dev
,
ip
->
addrs
[
NDIRECT
],
0
);
a
=
(
u32
*
)
bp
->
data
;
for
(
j
=
0
;
j
<
NINDIRECT
;
j
++
){
if
(
a
[
j
])
gc_delayed2
(
ip
->
dev
,
a
[
j
],
bfree
);
if
(
a
[
j
])
{
diskblock
*
db
=
new
diskblock
(
ip
->
dev
,
a
[
j
]);
gc_delayed
(
db
);
}
}
brelse
(
bp
,
0
);
gc_delayed2
(
ip
->
dev
,
ip
->
addrs
[
NDIRECT
],
bfree
);
diskblock
*
db
=
new
diskblock
(
ip
->
dev
,
ip
->
addrs
[
NDIRECT
]);
gc_delayed
(
db
);
ip
->
addrs
[
NDIRECT
]
=
0
;
}
...
...
gc.cc
浏览文件 @
4e6609e5
...
...
@@ -32,28 +32,15 @@ enum { gc_debug = 0 };
#define NGC 10000
struct
gc
{
struct
headinfo
{
rcu_freed
*
head
;
u64
epoch
;
struct
gc
*
next
;
union
{
struct
{
void
(
*
dofree
)(
void
*
);
void
*
item
;
}
f1
;
struct
{
void
(
*
dofree
)(
int
,
u64
);
int
arg1
;
u64
arg2
;
}
f2
;
};
int
type
;
}
__mpalign__
;
};
static
struct
gc_state
{
struct
condvar
cv
;
struct
gc
delayed
[
NEPOCH
];
struct
gc
tofree
[
NEPOCH
];
headinfo
delayed
[
NEPOCH
];
headinfo
tofree
[
NEPOCH
];
int
ndelayed
;
int
min_epoch
;
int
nrun
;
...
...
@@ -64,44 +51,21 @@ static struct gc_state {
static
struct
{
struct
spinlock
l
__mpalign__
;
}
gc_lock
;
u64
global_epoch
__mpalign__
;
struct
gc
*
gc_alloc
()
{
struct
gc
*
r
=
(
gc
*
)
kmalloc
(
sizeof
(
struct
gc
));
assert
(
r
);
__sync_fetch_and_add
(
&
gc_state
[
mycpu
()
->
id
].
ndelayed
,
1
);
return
r
;
}
static
void
gc_free_elem
(
struct
gc
*
r
)
{
switch
(
r
->
type
)
{
case
1
:
r
->
f1
.
dofree
(
r
->
f1
.
item
);
break
;
case
2
:
r
->
f2
.
dofree
(
r
->
f2
.
arg1
,
r
->
f2
.
arg2
);
break
;
default:
panic
(
"rcu type"
);
}
kmfree
(
r
);
}
static
int
gc_free_tofreelist
(
struct
gc
**
head
,
u64
epoch
)
gc_free_tofreelist
(
rcu_freed
**
head
,
u64
epoch
)
{
int
nfree
=
0
;
struct
gc
*
r
,
*
nr
;
rcu_freed
*
r
,
*
nr
;
for
(
r
=
*
head
;
r
!=
NULL
;
r
=
nr
)
{
if
(
r
->
epoch
>
epoch
)
{
cprintf
(
"gc_free_tofreelist: r->epoch %ld > epoch %ld
\n
"
,
r
->
epoch
,
epoch
);
if
(
r
->
_rcu_
epoch
>
epoch
)
{
cprintf
(
"gc_free_tofreelist: r->epoch %ld > epoch %ld
\n
"
,
r
->
_rcu_
epoch
,
epoch
);
assert
(
0
);
}
nr
=
r
->
next
;
gc_free_elem
(
r
);
nr
=
r
->
_rcu_next
;
cprintf
(
"about to delete %p
\n
"
,
r
);
delete
r
;
cprintf
(
"delete done
\n
"
);
nfree
++
;
}
*
head
=
r
;
...
...
@@ -113,13 +77,13 @@ gc_free_tofreelist(struct gc **head, u64 epoch)
void
*
gc_move_to_tofree_cpu
(
int
c
,
u64
epoch
)
{
struct
gc
*
head
;
rcu_freed
*
head
;
u32
fe
=
(
epoch
-
(
NEPOCH
-
2
))
%
NEPOCH
;
int
cas
;
assert
(
gc_state
[
c
].
delayed
[
fe
].
epoch
==
epoch
-
(
NEPOCH
-
2
));
// XXX race with setting epoch = 0
// unhook list for fe epoch atomically; this shouldn't fail
head
=
gc_state
[
c
].
delayed
[
fe
].
next
;
cas
=
__sync_bool_compare_and_swap
(
&
(
gc_state
[
c
].
delayed
[
fe
].
next
),
head
,
0
);
head
=
gc_state
[
c
].
delayed
[
fe
].
head
;
cas
=
__sync_bool_compare_and_swap
(
&
(
gc_state
[
c
].
delayed
[
fe
].
head
),
head
,
0
);
assert
(
cas
);
// insert list into tofree list so that each core can free in parallel and free its elements
...
...
@@ -128,12 +92,12 @@ gc_move_to_tofree_cpu(int c, u64 epoch)
gc_state
[
c
].
delayed
[
fe
].
epoch
);
assert
(
0
);
}
cas
=
__sync_bool_compare_and_swap
(
&
(
gc_state
[
c
].
tofree
[
fe
].
next
),
0
,
head
);
cas
=
__sync_bool_compare_and_swap
(
&
(
gc_state
[
c
].
tofree
[
fe
].
head
),
0
,
head
);
assert
(
cas
);
// move delayed NEPOCH's adhead
gc_state
[
c
].
delayed
[
fe
].
epoch
+=
NEPOCH
;
assert
(
gc_state
[
c
].
delayed
[
fe
].
next
==
0
);
assert
(
gc_state
[
c
].
delayed
[
fe
].
head
==
0
);
return
0
;
}
...
...
@@ -191,9 +155,10 @@ gc_delayfreelist(void)
release
(
&
gc_lock
.
l
);
}
static
void
gc_delayed
_int
(
struct
gc
*
r
)
void
gc_delayed
(
rcu_freed
*
e
)
{
__sync_fetch_and_add
(
&
gc_state
[
mycpu
()
->
id
].
ndelayed
,
1
);
pushcli
();
int
c
=
mycpu
()
->
id
;
u64
myepoch
=
myproc
()
->
epoch
;
...
...
@@ -204,39 +169,14 @@ gc_delayed_int(struct gc *r)
cprintf
(
"%d: myepoch %lu minepoch %lu
\n
"
,
myproc
()
->
pid
,
myepoch
,
minepoch
);
panic
(
"gc_delayed_int"
);
}
r
->
epoch
=
myepoch
;
e
->
_rcu_
epoch
=
myepoch
;
do
{
r
->
next
=
gc_state
[
c
].
delayed
[
myepoch
%
NEPOCH
].
next
;
}
while
(
!
__sync_bool_compare_and_swap
(
&
(
gc_state
[
c
].
delayed
[
myepoch
%
NEPOCH
].
next
),
r
->
next
,
r
));
e
->
_rcu_next
=
gc_state
[
c
].
delayed
[
myepoch
%
NEPOCH
].
head
;
}
while
(
!
__sync_bool_compare_and_swap
(
&
(
gc_state
[
c
].
delayed
[
myepoch
%
NEPOCH
].
head
),
e
->
_rcu_next
,
e
));
popcli
();
}
void
gc_delayed
(
void
*
e
,
void
(
*
dofree
)(
void
*
))
{
struct
gc
*
r
=
gc_alloc
();
if
(
r
==
0
)
panic
(
"gc_delayed"
);
r
->
f1
.
dofree
=
dofree
;
r
->
f1
.
item
=
e
;
r
->
type
=
1
;
gc_delayed_int
(
r
);
}
void
gc_delayed2
(
int
a1
,
u64
a2
,
void
(
*
dofree
)(
int
,
u64
))
{
struct
gc
*
r
=
gc_alloc
();
if
(
r
==
0
)
panic
(
"gc_delayed2"
);
r
->
f2
.
dofree
=
dofree
;
r
->
f2
.
arg1
=
a1
;
r
->
f2
.
arg2
=
a2
;
r
->
type
=
2
;
gc_delayed_int
(
r
);
}
void
gc_begin_epoch
(
void
)
{
if
(
myproc
()
==
NULL
)
return
;
...
...
@@ -286,7 +226,7 @@ gc_worker(void *x)
u64
global
=
global_epoch
;
myproc
()
->
epoch
=
global_epoch
;
// move the gc thread to next epoch
for
(
i
=
gc_state
[
mycpu
()
->
id
].
min_epoch
;
i
<
global
-
2
;
i
++
)
{
int
nfree
=
gc_free_tofreelist
(
&
(
gc_state
[
mycpu
()
->
id
].
tofree
[
i
%
NEPOCH
].
next
),
i
);
int
nfree
=
gc_free_tofreelist
(
&
(
gc_state
[
mycpu
()
->
id
].
tofree
[
i
%
NEPOCH
].
head
),
i
);
gc_state
[
mycpu
()
->
id
].
tofree
[
i
%
NEPOCH
].
epoch
+=
NEPOCH
;
__sync_fetch_and_sub
(
&
gc_state
[
mycpu
()
->
id
].
ndelayed
,
nfree
);
if
(
0
&&
nfree
>
0
)
{
...
...
@@ -337,10 +277,3 @@ initgc(void)
release
(
&
gcp
->
lock
);
}
}
void
del_rcu_freed
(
void
*
arg
)
{
rcu_freed
*
rf
=
(
rcu_freed
*
)
arg
;
delete
rf
;
}
gc.hh
浏览文件 @
4e6609e5
#pragma once
class
rcu_freed
{
p
rivate
:
p
ublic
:
u64
_rcu_epoch
;
rcu_freed
*
_rcu_next
;
public
:
virtual
~
rcu_freed
()
{}
};
void
del_rcu_freed
(
void
*
);
}
__mpalign__
;
kernel.h
浏览文件 @
4e6609e5
...
...
@@ -56,17 +56,7 @@ void consoleintr(int(*)(void));
#define assert(c) if (!(c)) { cprintf("%s:%d: ", __FILE__, __LINE__); panic("assertion failure"); }
// crange.c
struct
range
{
u64
key
;
u64
size
;
void
*
value
;
int
curlevel
;
// the current levels it appears on
int
nlevel
;
// the number of levels this range should appear
struct
crange
*
cr
;
// the crange this range is part of
struct
range
**
next
;
// one next pointer per level
struct
spinlock
*
lock
;
// on separate cache line?
}
__mpalign__
;
struct
range
;
struct
crange
*
crange_alloc
(
int
nlevel
);
void
crange_free
(
struct
crange
*
cr
);
...
...
@@ -120,10 +110,13 @@ void initgc(void);
void
initprocgc
(
struct
proc
*
);
void
gc_begin_epoch
();
void
gc_end_epoch
();
void
gc_delayed
(
void
*
,
void
(
*
dofree
)(
void
*
));
void
gc_delayed2
(
int
,
u64
,
void
(
*
dofree
)(
int
,
u64
));
void
gc_start
(
void
);
#ifdef __cplusplus
class
rcu_freed
;
void
gc_delayed
(
rcu_freed
*
);
#endif
// hwvm.c
void
freevm
(
pml4e_t
*
);
pml4e_t
*
setupkvm
(
void
);
...
...
ns.hh
浏览文件 @
4e6609e5
...
...
@@ -76,7 +76,7 @@ class xns : public rcu_freed {
if
(
!
allowdup
)
{
for
(
auto
x
=
root
;
x
;
x
=
x
->
next
)
{
if
(
x
->
key
==
key
)
{
gc_delayed
(
e
,
del_rcu_freed
);
gc_delayed
(
e
);
return
-
1
;
}
}
...
...
@@ -131,7 +131,7 @@ class xns : public rcu_freed {
}
*
pelock
=
0
;
gc_delayed
(
e
,
del_rcu_freed
);
gc_delayed
(
e
);
return
true
;
}
...
...
proc.cc
浏览文件 @
4e6609e5
...
...
@@ -179,11 +179,24 @@ exit(void)
panic
(
"zombie exit"
);
}
class
delayedfree
:
public
rcu_freed
{
private
:
proc
*
_p
;
public
:
delayedfree
(
proc
*
p
)
:
_p
(
p
)
{}
virtual
~
delayedfree
()
{
kmfree
(
_p
);
}
};
static
void
freeproc
(
struct
proc
*
p
)
{
destroylock
(
&
p
->
lock
);
gc_delayed
(
p
,
kmfree
);
delayedfree
*
df
=
new
delayedfree
(
p
);
gc_delayed
(
df
);
}
// Look in the process table for an UNUSED proc.
...
...
vm.cc
浏览文件 @
4e6609e5
...
...
@@ -13,6 +13,8 @@ extern "C" {
#include "vm.h"
}
#include "gc.hh"
static
void
vmap_free
(
void
*
p
);
enum
{
vm_debug
=
0
};
...
...
@@ -47,6 +49,17 @@ vma_free(void *p)
kmfree
(
e
);
}
class
vma_delayed
:
public
rcu_freed
{
private
:
vma
*
_e
;
public
:
vma_delayed
(
vma
*
e
)
:
_e
(
e
)
{}
virtual
~
vma_delayed
()
{
vma_free
(
_e
);
}
};
static
int
vmn_doallocpg
(
struct
vmnode
*
n
)
{
...
...
@@ -469,7 +482,9 @@ vmap_remove(struct vmap *m, uptr va_start, u64 len)
return
-
1
;
}
crange_del
(
m
->
cr
,
va_start
,
len
);
gc_delayed
(
e
,
vma_free
);
vma_delayed
*
vd
=
new
vma_delayed
(
e
);
gc_delayed
(
vd
);
release
(
&
m
->
lock
);
return
0
;
}
...
...
@@ -601,7 +616,8 @@ vmap_remove(struct vmap *m, uptr va_start, u64 len)
cprintf
(
"vmap_remove: partial unmap unsupported
\n
"
);
return
-
1
;
}
gc_delayed
(
m
->
e
[
i
],
vma_free
);
vma_delayed
*
vd
=
new
vma_delayed
(
m
->
e
[
i
]);
gc_delayed
(
vd
);
m
->
e
[
i
]
=
0
;
}
}
...
...
编写
预览
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论