Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
38815959
Commit
38815959
authored
Oct 09, 2015
by
k8s-merge-robot
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #15014 from ncdc/gh14995-fix-wait-goroutine-leaks
Auto commit by PR queue bot
parents
433c74b8
7999e726
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
36 additions
and
12 deletions
+36
-12
wait.go
pkg/util/wait/wait.go
+20
-7
wait_test.go
pkg/util/wait/wait_test.go
+16
-5
No files found.
pkg/util/wait/wait.go
View file @
38815959
...
@@ -48,13 +48,17 @@ type ConditionFunc func() (done bool, err error)
...
@@ -48,13 +48,17 @@ type ConditionFunc func() (done bool, err error)
func
Poll
(
interval
,
timeout
time
.
Duration
,
condition
ConditionFunc
)
error
{
func
Poll
(
interval
,
timeout
time
.
Duration
,
condition
ConditionFunc
)
error
{
return
pollInternal
(
poller
(
interval
,
timeout
),
condition
)
return
pollInternal
(
poller
(
interval
,
timeout
),
condition
)
}
}
func
pollInternal
(
wait
WaitFunc
,
condition
ConditionFunc
)
error
{
func
pollInternal
(
wait
WaitFunc
,
condition
ConditionFunc
)
error
{
return
WaitFor
(
wait
,
condition
)
done
:=
make
(
chan
struct
{})
defer
close
(
done
)
return
WaitFor
(
wait
,
condition
,
done
)
}
}
func
PollImmediate
(
interval
,
timeout
time
.
Duration
,
condition
ConditionFunc
)
error
{
func
PollImmediate
(
interval
,
timeout
time
.
Duration
,
condition
ConditionFunc
)
error
{
return
pollImmediateInternal
(
poller
(
interval
,
timeout
),
condition
)
return
pollImmediateInternal
(
poller
(
interval
,
timeout
),
condition
)
}
}
func
pollImmediateInternal
(
wait
WaitFunc
,
condition
ConditionFunc
)
error
{
func
pollImmediateInternal
(
wait
WaitFunc
,
condition
ConditionFunc
)
error
{
done
,
err
:=
condition
()
done
,
err
:=
condition
()
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -68,20 +72,22 @@ func pollImmediateInternal(wait WaitFunc, condition ConditionFunc) error {
...
@@ -68,20 +72,22 @@ func pollImmediateInternal(wait WaitFunc, condition ConditionFunc) error {
// PollInfinite polls forever.
// PollInfinite polls forever.
func
PollInfinite
(
interval
time
.
Duration
,
condition
ConditionFunc
)
error
{
func
PollInfinite
(
interval
time
.
Duration
,
condition
ConditionFunc
)
error
{
return
WaitFor
(
poller
(
interval
,
0
),
condition
)
done
:=
make
(
chan
struct
{})
defer
close
(
done
)
return
WaitFor
(
poller
(
interval
,
0
),
condition
,
done
)
}
}
// WaitFunc creates a channel that receives an item every time a test
// WaitFunc creates a channel that receives an item every time a test
// should be executed and is closed when the last test should be invoked.
// should be executed and is closed when the last test should be invoked.
type
WaitFunc
func
()
<-
chan
struct
{}
type
WaitFunc
func
(
done
<-
chan
struct
{}
)
<-
chan
struct
{}
// WaitFor gets a channel from wait(), and then invokes fn once for every value
// WaitFor gets a channel from wait(), and then invokes fn once for every value
// placed on the channel and once more when the channel is closed. If fn
// placed on the channel and once more when the channel is closed. If fn
// returns an error the loop ends and that error is returned, and if fn returns
// returns an error the loop ends and that error is returned, and if fn returns
// true the loop ends and nil is returned. ErrWaitTimeout will be returned if
// true the loop ends and nil is returned. ErrWaitTimeout will be returned if
// the channel is closed without fn ever returning true.
// the channel is closed without fn ever returning true.
func
WaitFor
(
wait
WaitFunc
,
fn
ConditionFunc
)
error
{
func
WaitFor
(
wait
WaitFunc
,
fn
ConditionFunc
,
done
<-
chan
struct
{}
)
error
{
c
:=
wait
()
c
:=
wait
(
done
)
for
{
for
{
_
,
open
:=
<-
c
_
,
open
:=
<-
c
ok
,
err
:=
fn
()
ok
,
err
:=
fn
()
...
@@ -104,11 +110,15 @@ func WaitFor(wait WaitFunc, fn ConditionFunc) error {
...
@@ -104,11 +110,15 @@ func WaitFor(wait WaitFunc, fn ConditionFunc) error {
// the channel is closed. If timeout is 0, the channel
// the channel is closed. If timeout is 0, the channel
// will never be closed.
// will never be closed.
func
poller
(
interval
,
timeout
time
.
Duration
)
WaitFunc
{
func
poller
(
interval
,
timeout
time
.
Duration
)
WaitFunc
{
return
WaitFunc
(
func
()
<-
chan
struct
{}
{
return
WaitFunc
(
func
(
done
<-
chan
struct
{}
)
<-
chan
struct
{}
{
ch
:=
make
(
chan
struct
{})
ch
:=
make
(
chan
struct
{})
go
func
()
{
go
func
()
{
defer
close
(
ch
)
tick
:=
time
.
NewTicker
(
interval
)
tick
:=
time
.
NewTicker
(
interval
)
defer
tick
.
Stop
()
defer
tick
.
Stop
()
var
after
<-
chan
time
.
Time
var
after
<-
chan
time
.
Time
if
timeout
!=
0
{
if
timeout
!=
0
{
// time.After is more convenient, but it
// time.After is more convenient, but it
...
@@ -118,16 +128,19 @@ func poller(interval, timeout time.Duration) WaitFunc {
...
@@ -118,16 +128,19 @@ func poller(interval, timeout time.Duration) WaitFunc {
after
=
timer
.
C
after
=
timer
.
C
defer
timer
.
Stop
()
defer
timer
.
Stop
()
}
}
for
{
for
{
select
{
select
{
case
<-
tick
.
C
:
case
<-
tick
.
C
:
ch
<-
struct
{}{}
ch
<-
struct
{}{}
case
<-
after
:
case
<-
after
:
close
(
ch
)
return
case
<-
done
:
return
return
}
}
}
}
}()
}()
return
ch
return
ch
})
})
}
}
pkg/util/wait/wait_test.go
View file @
38815959
...
@@ -26,8 +26,10 @@ import (
...
@@ -26,8 +26,10 @@ import (
)
)
func
TestPoller
(
t
*
testing
.
T
)
{
func
TestPoller
(
t
*
testing
.
T
)
{
done
:=
make
(
chan
struct
{})
defer
close
(
done
)
w
:=
poller
(
time
.
Millisecond
,
2
*
time
.
Millisecond
)
w
:=
poller
(
time
.
Millisecond
,
2
*
time
.
Millisecond
)
ch
:=
w
()
ch
:=
w
(
done
)
count
:=
0
count
:=
0
DRAIN
:
DRAIN
:
for
{
for
{
...
@@ -47,16 +49,20 @@ DRAIN:
...
@@ -47,16 +49,20 @@ DRAIN:
}
}
func
fakeTicker
(
max
int
,
used
*
int32
)
WaitFunc
{
func
fakeTicker
(
max
int
,
used
*
int32
)
WaitFunc
{
return
func
()
<-
chan
struct
{}
{
return
func
(
done
<-
chan
struct
{}
)
<-
chan
struct
{}
{
ch
:=
make
(
chan
struct
{})
ch
:=
make
(
chan
struct
{})
go
func
()
{
go
func
()
{
defer
close
(
ch
)
for
i
:=
0
;
i
<
max
;
i
++
{
for
i
:=
0
;
i
<
max
;
i
++
{
ch
<-
struct
{}{}
select
{
case
ch
<-
struct
{}{}
:
case
<-
done
:
return
}
if
used
!=
nil
{
if
used
!=
nil
{
atomic
.
AddInt32
(
used
,
1
)
atomic
.
AddInt32
(
used
,
1
)
}
}
}
}
close
(
ch
)
}()
}()
return
ch
return
ch
}
}
...
@@ -155,6 +161,7 @@ func TestPollForever(t *testing.T) {
...
@@ -155,6 +161,7 @@ func TestPollForever(t *testing.T) {
}
}
return
false
,
nil
return
false
,
nil
})
})
if
err
:=
PollInfinite
(
time
.
Microsecond
,
f
);
err
!=
nil
{
if
err
:=
PollInfinite
(
time
.
Microsecond
,
f
);
err
!=
nil
{
t
.
Fatalf
(
"unexpected error %v"
,
err
)
t
.
Fatalf
(
"unexpected error %v"
,
err
)
}
}
...
@@ -232,7 +239,11 @@ func TestWaitFor(t *testing.T) {
...
@@ -232,7 +239,11 @@ func TestWaitFor(t *testing.T) {
for
k
,
c
:=
range
testCases
{
for
k
,
c
:=
range
testCases
{
invocations
=
0
invocations
=
0
ticker
:=
fakeTicker
(
c
.
Ticks
,
nil
)
ticker
:=
fakeTicker
(
c
.
Ticks
,
nil
)
err
:=
WaitFor
(
ticker
,
c
.
F
)
err
:=
func
()
error
{
done
:=
make
(
chan
struct
{})
defer
close
(
done
)
return
WaitFor
(
ticker
,
c
.
F
,
done
)
}()
switch
{
switch
{
case
c
.
Err
&&
err
==
nil
:
case
c
.
Err
&&
err
==
nil
:
t
.
Errorf
(
"%s: Expected error, got nil"
,
k
)
t
.
Errorf
(
"%s: Expected error, got nil"
,
k
)
...
...
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