From 917356f8e043c582529b0da742544f130e9bd291 Mon Sep 17 00:00:00 2001 From: Joel Smith Date: Fri, 13 Apr 2018 21:19:39 -0600 Subject: [PATCH] Prevent virtual infinite loop in volume controller In WatchPod(), if one of the two channels being watched (pod updates and events) is closed, the for/select loop turns into a tight infinite loop because the select immediately falls through due to the channel being closed. Watch them independently instead. --- .../util/recyclerclient/recycler_client.go | 41 +++++++++++++------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/pkg/volume/util/recyclerclient/recycler_client.go b/pkg/volume/util/recyclerclient/recycler_client.go index b3b75acf849..275f55bbe33 100644 --- a/pkg/volume/util/recyclerclient/recycler_client.go +++ b/pkg/volume/util/recyclerclient/recycler_client.go @@ -18,6 +18,7 @@ package recyclerclient import ( "fmt" + "sync" "github.com/golang/glog" "k8s.io/api/core/v1" @@ -191,6 +192,8 @@ func (c *realRecyclerClient) Event(eventtype, message string) { c.recorder(eventtype, message) } +// WatchPod watches a pod and events related to it. It sends pod updates and events over the returned channel +// It will continue until stopChannel is closed func (c *realRecyclerClient) WatchPod(name, namespace string, stopChannel chan struct{}) (<-chan watch.Event, error) { podSelector, err := fields.ParseSelector("metadata.name=" + name) if err != nil { @@ -217,13 +220,34 @@ func (c *realRecyclerClient) WatchPod(name, namespace string, stopChannel chan s } eventCh := make(chan watch.Event, 30) + var wg sync.WaitGroup + wg.Add(2) + + go func() { + defer close(eventCh) + wg.Wait() + }() go func() { defer eventWatch.Stop() + defer wg.Done() + for { + select { + case _ = <-stopChannel: + return + case eventEvent, ok := <-eventWatch.ResultChan(): + if !ok { + return + } else { + eventCh <- eventEvent + } + } + } + }() + + go func() { defer podWatch.Stop() - defer close(eventCh) - var podWatchChannelClosed bool - var eventWatchChannelClosed bool + defer wg.Done() for { select { case <-stopChannel: @@ -231,19 +255,10 @@ func (c *realRecyclerClient) WatchPod(name, namespace string, stopChannel chan s case podEvent, ok := <-podWatch.ResultChan(): if !ok { - podWatchChannelClosed = true + return } else { eventCh <- podEvent } - case eventEvent, ok := <-eventWatch.ResultChan(): - if !ok { - eventWatchChannelClosed = true - } else { - eventCh <- eventEvent - } - } - if podWatchChannelClosed && eventWatchChannelClosed { - break } } }()