Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
p2p
go-p2p-swarm
Commits
6e49586c
Commit
6e49586c
authored
Oct 30, 2016
by
Jeromy Johnson
Committed by
GitHub
Oct 30, 2016
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #4 from libp2p/fix/lock-ordering
fix lock ordering race condition in dial sync code
parents
a636a14b
511d7a82
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
53 additions
and
13 deletions
+53
-13
dial_sync.go
dial_sync.go
+29
-13
dial_sync_test.go
dial_sync_test.go
+24
-0
No files found.
dial_sync.go
View file @
6e49586c
...
@@ -53,22 +53,38 @@ func (ad *activeDial) incref() {
...
@@ -53,22 +53,38 @@ func (ad *activeDial) incref() {
func
(
ad
*
activeDial
)
decref
()
{
func
(
ad
*
activeDial
)
decref
()
{
ad
.
refCntLk
.
Lock
()
ad
.
refCntLk
.
Lock
()
defer
ad
.
refCntLk
.
Unlock
()
ad
.
refCnt
--
ad
.
refCnt
--
if
ad
.
refCnt
<=
0
{
maybeZero
:=
(
ad
.
refCnt
<=
0
)
ad
.
cancel
()
ad
.
refCntLk
.
Unlock
()
// make sure to always take locks in correct order.
if
maybeZero
{
ad
.
ds
.
dialsLk
.
Lock
()
ad
.
ds
.
dialsLk
.
Lock
()
delete
(
ad
.
ds
.
dials
,
ad
.
id
)
ad
.
refCntLk
.
Lock
()
// check again after lock swap drop to make sure nobody else called incref
// in between locks
if
ad
.
refCnt
<=
0
{
ad
.
cancel
()
delete
(
ad
.
ds
.
dials
,
ad
.
id
)
}
ad
.
refCntLk
.
Unlock
()
ad
.
ds
.
dialsLk
.
Unlock
()
ad
.
ds
.
dialsLk
.
Unlock
()
}
}
}
}
func
(
ds
*
DialSync
)
DialLock
(
ctx
context
.
Context
,
p
peer
.
ID
)
(
*
Conn
,
error
)
{
func
(
ad
*
activeDial
)
start
(
ctx
context
.
Context
)
{
ad
.
conn
,
ad
.
err
=
ad
.
ds
.
dialFunc
(
ctx
,
ad
.
id
)
close
(
ad
.
waitch
)
ad
.
cancel
()
}
func
(
ds
*
DialSync
)
getActiveDial
(
p
peer
.
ID
)
*
activeDial
{
ds
.
dialsLk
.
Lock
()
ds
.
dialsLk
.
Lock
()
defer
ds
.
dialsLk
.
Unlock
()
actd
,
ok
:=
ds
.
dials
[
p
]
actd
,
ok
:=
ds
.
dials
[
p
]
if
!
ok
{
if
!
ok
{
ctx
,
cancel
:=
context
.
WithCancel
(
context
.
Background
())
ad
ctx
,
cancel
:=
context
.
WithCancel
(
context
.
Background
())
actd
=
&
activeDial
{
actd
=
&
activeDial
{
id
:
p
,
id
:
p
,
cancel
:
cancel
,
cancel
:
cancel
,
...
@@ -77,15 +93,15 @@ func (ds *DialSync) DialLock(ctx context.Context, p peer.ID) (*Conn, error) {
...
@@ -77,15 +93,15 @@ func (ds *DialSync) DialLock(ctx context.Context, p peer.ID) (*Conn, error) {
}
}
ds
.
dials
[
p
]
=
actd
ds
.
dials
[
p
]
=
actd
go
func
(
ctx
context
.
Context
,
p
peer
.
ID
,
ad
*
activeDial
)
{
go
actd
.
start
(
adctx
)
ad
.
conn
,
ad
.
err
=
ds
.
dialFunc
(
ctx
,
p
)
close
(
ad
.
waitch
)
ad
.
cancel
()
}(
ctx
,
p
,
actd
)
}
}
// increase ref count before dropping dialsLk
actd
.
incref
()
actd
.
incref
()
ds
.
dialsLk
.
Unlock
()
return
actd
.
wait
(
ctx
)
return
actd
}
func
(
ds
*
DialSync
)
DialLock
(
ctx
context
.
Context
,
p
peer
.
ID
)
(
*
Conn
,
error
)
{
return
ds
.
getActiveDial
(
p
)
.
wait
(
ctx
)
}
}
dial_sync_test.go
View file @
6e49586c
...
@@ -201,3 +201,27 @@ func TestFailFirst(t *testing.T) {
...
@@ -201,3 +201,27 @@ func TestFailFirst(t *testing.T) {
t
.
Fatal
(
"should have gotten a 'real' conn back"
)
t
.
Fatal
(
"should have gotten a 'real' conn back"
)
}
}
}
}
func
TestStressActiveDial
(
t
*
testing
.
T
)
{
ds
:=
NewDialSync
(
func
(
ctx
context
.
Context
,
p
peer
.
ID
)
(
*
Conn
,
error
)
{
return
nil
,
nil
})
wg
:=
sync
.
WaitGroup
{}
pid
:=
peer
.
ID
(
"foo"
)
makeDials
:=
func
()
{
for
i
:=
0
;
i
<
10000
;
i
++
{
ds
.
DialLock
(
context
.
Background
(),
pid
)
}
wg
.
Done
()
}
for
i
:=
0
;
i
<
100
;
i
++
{
wg
.
Add
(
1
)
go
makeDials
()
}
wg
.
Wait
()
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment