Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
X
xv6-public
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
问题
0
问题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
银宸时代
OS Lab Group
奖励实验
xv6-public
提交
c79b80a7
提交
c79b80a7
4月 08, 2012
创建
作者:
Silas Boyd-Wickizer
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
More scalable futex and some hacks to get ok performance.
The only locking is "point-to-point" between condvar sleep in one proc and condvar wakeup in another.
上级
39064a18
隐藏空白字符变更
内嵌
并排
正在显示
3 个修改的文件
包含
135 行增加
和
24 行删除
+135
-24
proc.hh
include/proc.hh
+3
-1
futex.cc
kernel/futex.cc
+128
-20
proc.cc
kernel/proc.cc
+4
-3
没有找到文件。
include/proc.hh
浏览文件 @
c79b80a7
...
...
@@ -77,7 +77,7 @@ struct proc : public rcu_freed, public sched_link {
u64
cv_wakeup
;
// Wakeup time for this process
LIST_ENTRY
(
proc
)
cv_waiters
;
// Linked list of processes waiting for oncv
LIST_ENTRY
(
proc
)
cv_sleep
;
// Linked list of processes sleeping on a cv
LIST_ENTRY
(
proc
)
futex_lin
k
;
struct
spinlock
futex_loc
k
;
u64
user_fs_
;
u64
unmap_tlbreq_
;
int
exec_cpuid_
;
...
...
@@ -97,6 +97,8 @@ struct proc : public rcu_freed, public sched_link {
static
int
kill
(
int
pid
);
int
kill
();
static
u64
hash
(
const
u32
&
p
);
virtual
void
do_gc
(
void
)
{
delete
this
;
}
private
:
...
...
kernel/futex.cc
浏览文件 @
c79b80a7
...
...
@@ -7,6 +7,7 @@
#include "condvar.h"
#include "proc.hh"
#include "cpu.hh"
#include "percpu.hh"
//
// futexkey
...
...
@@ -45,11 +46,68 @@ futexkey(const u64* useraddr, vmap* vmap, futexkey_t* key)
}
//
// nscache
//
struct
nscache
{
struct
spinlock
lock_
;
volatile
u64
head_
;
volatile
u64
tail_
;
xns
<
u32
,
proc
*
,
proc
::
hash
>*
ns_
[
16
];
nscache
();
xns
<
u32
,
proc
*
,
proc
::
hash
>*
alloc
();
bool
cache
(
xns
<
u32
,
proc
*
,
proc
::
hash
>*
ns
);
NEW_DELETE_OPS
(
nscache
);
};
percpu
<
nscache
>
nscache_
;
nscache
::
nscache
(
void
)
{
initlock
(
&
lock_
,
"nscache::lock_"
,
LOCKSTAT_FUTEX
);
head_
=
0
;
tail_
=
0
;
}
xns
<
u32
,
proc
*
,
proc
::
hash
>*
nscache
::
alloc
(
void
)
{
xns
<
u32
,
proc
*
,
proc
::
hash
>*
ns
=
nullptr
;
acquire
(
&
lock_
);
if
(
head_
-
tail_
>
0
)
{
u64
i
=
tail_
%
NELEM
(
ns_
);
++
tail_
;
ns
=
ns_
[
i
];
}
release
(
&
lock_
);
return
ns
;
}
bool
nscache
::
cache
(
xns
<
u32
,
proc
*
,
proc
::
hash
>*
ns
)
{
bool
cached
=
false
;
acquire
(
&
lock_
);
if
(
head_
-
tail_
<
NELEM
(
ns_
))
{
u64
i
=
head_
%
NELEM
(
ns_
);
++
head_
;
ns_
[
i
]
=
ns
;
cached
=
true
;
}
release
(
&
lock_
);
return
cached
;
}
//
// futexaddr
//
struct
futexaddr
:
public
referenced
,
public
rcu_freed
{
futexaddr
(
futexkey_t
key
);
static
futexaddr
*
alloc
(
futexkey_t
key
);
virtual
void
do_gc
();
virtual
void
onzero
()
const
;
...
...
@@ -57,18 +115,40 @@ struct futexaddr : public referenced, public rcu_freed
bool
inserted_
;
struct
spinlock
lock_
;
LIST_HEAD
(
proclist
,
proc
)
list
_
;
xns
<
u32
,
proc
*
,
proc
::
hash
>*
const
nspid
_
;
private
:
futexaddr
(
futexkey_t
key
,
xns
<
u32
,
proc
*
,
proc
::
hash
>*
nspid
);
NEW_DELETE_OPS
(
futexaddr
);
};
xns
<
futexkey_t
,
futexaddr
*
,
futexkey_hash
>
*
nsfutex
__mpalign__
;
futexaddr
::
futexaddr
(
futexkey_t
key
)
:
rcu_freed
(
"futexaddr"
),
key_
(
key
),
inserted_
(
false
)
futexaddr
*
futexaddr
::
alloc
(
futexkey_t
key
)
{
xns
<
u32
,
proc
*
,
proc
::
hash
>*
nspid
;
futexaddr
*
fa
;
nspid
=
nscache_
->
alloc
();
if
(
nspid
==
nullptr
)
nspid
=
new
xns
<
u32
,
proc
*
,
proc
::
hash
>
(
false
);
if
(
nspid
==
nullptr
)
return
nullptr
;
fa
=
new
futexaddr
(
key
,
nspid
);
if
(
fa
==
nullptr
)
{
delete
nspid
;
return
nullptr
;
}
return
fa
;
}
futexaddr
::
futexaddr
(
futexkey_t
key
,
xns
<
u32
,
proc
*
,
proc
::
hash
>*
nspid
)
:
rcu_freed
(
"futexaddr"
),
key_
(
key
),
inserted_
(
false
),
nspid_
(
nspid
)
{
initlock
(
&
lock_
,
"futexaddr::lock_"
,
LOCKSTAT_FUTEX
);
LIST_INIT
(
&
list_
);
}
void
...
...
@@ -82,6 +162,10 @@ futexaddr::onzero(void) const
{
if
(
inserted_
)
assert
(
nsfutex
->
remove
(
key_
,
nullptr
));
// Normally deallocate members in the destructor, but in this case
// we don't want to wait for the gc to fill the cache
if
(
!
nscache_
->
cache
(
nspid_
))
delete
nspid_
;
gc_delayed
((
futexaddr
*
)
this
);
}
...
...
@@ -95,7 +179,11 @@ futexwait(futexkey_t key, u64 val, u64 timer)
again
:
fa
=
nsfutex
->
lookup
(
key
);
if
(
fa
==
nullptr
)
{
fa
=
new
futexaddr
(
key
);
fa
=
futexaddr
::
alloc
(
key
);
if
(
fa
==
nullptr
)
{
cprintf
(
"futexwait futexaddr::alloc failed
\n
"
);
return
-
1
;
}
if
(
nsfutex
->
insert
(
key
,
fa
)
<
0
)
{
fa
->
dec
();
goto
again
;
...
...
@@ -109,20 +197,28 @@ futexwait(futexkey_t key, u64 val, u64 timer)
}
assert
(
fa
->
key_
==
key
);
acquire
(
&
fa
->
lock_
);
acquire
(
&
myproc
()
->
futex_lock
);
auto
cleanup
=
scoped_cleanup
([
&
fa
](){
release
(
&
fa
->
lock_
);
release
(
&
myproc
()
->
futex_lock
);
fa
->
dec
();
});
// This first check is an optimization
if
(
futexkey_val
(
fa
->
key_
)
!=
val
)
return
-
EWOULDBLOCK
;
LIST_INSERT_HEAD
(
&
fa
->
list_
,
myproc
(),
futex_link
);
if
(
fa
->
nspid_
->
insert
(
myproc
()
->
pid
,
myproc
())
<
0
)
return
-
1
;
if
(
futexkey_val
(
fa
->
key_
)
!=
val
)
{
fa
->
nspid_
->
remove
(
myproc
()
->
pid
,
nullptr
);
return
-
EWOULDBLOCK
;
}
u64
nsecto
=
timer
==
0
?
0
:
timer
+
nsectime
();
cv_sleepto
(
&
myproc
()
->
cv
,
&
fa
->
lock_
,
nsecto
);
cv_sleepto
(
&
myproc
()
->
cv
,
&
myproc
()
->
futex_lock
,
nsecto
);
LIST_REMOVE
(
myproc
(),
futex_link
);
assert
(
fa
->
nspid_
->
remove
(
myproc
()
->
pid
,
nullptr
)
);
return
0
;
}
...
...
@@ -131,20 +227,29 @@ futexwake(futexkey_t key, u64 nwake)
{
futexaddr
*
fa
;
u64
nwoke
=
0
;
proc
*
p
;
if
(
nwake
==
0
)
return
-
1
;
scoped_gc_epoch
gc
;
fa
=
nsfutex
->
lookup
(
key
);
if
(
fa
==
nullptr
)
if
(
fa
==
nullptr
||
!
fa
->
tryinc
()
)
return
0
;
acquire
(
&
fa
->
lock_
);
LIST_FOREACH
(
p
,
&
fa
->
list_
,
futex_link
)
{
if
(
nwoke
>=
nwake
)
break
;
auto
cleanup
=
scoped_cleanup
([
&
fa
](){
fa
->
dec
();
});
fa
->
nspid_
->
enumerate
([
&
nwoke
,
&
nwake
](
u32
pid
,
proc
*
p
)
{
acquire
(
&
p
->
futex_lock
);
cv_wakeup
(
&
p
->
cv
);
nwoke
++
;
}
release
(
&
fa
->
lock_
);
release
(
&
p
->
futex_lock
);
++
nwoke
;
if
(
nwoke
>=
nwake
)
return
1
;
return
0
;
});
return
0
;
}
...
...
@@ -154,4 +259,7 @@ initfutex(void)
nsfutex
=
new
xns
<
futexkey_t
,
futexaddr
*
,
futexkey_hash
>
(
false
);
if
(
nsfutex
==
0
)
panic
(
"initfutex"
);
for
(
int
i
=
0
;
i
<
NCPU
;
i
++
)
new
(
&
nscache_
[
i
])
nscache
();
}
kernel/proc.cc
浏览文件 @
c79b80a7
...
...
@@ -16,7 +16,7 @@
#include "wq.hh"
u64
proc
_
hash
(
const
u32
&
p
)
proc
::
hash
(
const
u32
&
p
)
{
return
p
;
}
...
...
@@ -27,7 +27,7 @@ mycpuid(void)
return
mycpu
()
->
id
;
}
xns
<
u32
,
proc
*
,
proc
_
hash
>
*
xnspid
__mpalign__
;
xns
<
u32
,
proc
*
,
proc
::
hash
>
*
xnspid
__mpalign__
;
struct
proc
*
bootproc
__mpalign__
;
#if MTRACE
...
...
@@ -46,6 +46,7 @@ proc::proc(int npid) :
{
snprintf
(
lockname
,
sizeof
(
lockname
),
"cv:proc:%d"
,
pid
);
initlock
(
&
lock
,
lockname
+
3
,
LOCKSTAT_PROC
);
initlock
(
&
futex_lock
,
"proc::futex_lock"
,
LOCKSTAT_PROC
);
initcondvar
(
&
cv
,
lockname
);
memset
(
&
childq
,
0
,
sizeof
(
childq
));
...
...
@@ -257,7 +258,7 @@ proc::alloc(void)
void
initproc
(
void
)
{
xnspid
=
new
xns
<
u32
,
proc
*
,
proc
_
hash
>
(
false
);
xnspid
=
new
xns
<
u32
,
proc
*
,
proc
::
hash
>
(
false
);
if
(
xnspid
==
0
)
panic
(
"pinit"
);
}
...
...
编写
预览
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论