Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix race in idle expiration #47

Merged
merged 1 commit into from
Mar 2, 2015
Merged

Conversation

dmcgowan
Copy link
Member

On expiration reset is called, causing a race between resetting objects and accessing the streams. Additionally a deadlock occurs writing frames which can be avoided by running the actual sending of the resets in a goroutine.

for _, stream := range streams {
stream.resetStream()
}
}()
i.conn.Close()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it safer to have this inside the goroutine too? It sends a goaway frame, which means it's sending to resetChan

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you happen to set resetChan's capacity to 0, this hangs unless you move i.conn.Close() inside the goroutine - it's probably safest that way.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggesting i.conn.Close is inside the goroutine before the resets? I don't like that hanging is a possibility on Close but I see it is only because the resetChan cannot be read from while this call is done. I will make that update, my main concern was i.conn.streams was updated before Close.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inside the goroutine after the resets, if that works for you?
On Fri, Feb 27, 2015 at 7:12 PM Derek McGowan notifications@github.com
wrote:

In connection.go
#47 (comment):

@@ -72,11 +72,17 @@ Loop:
timer.Reset(i.timeout)
}
case <-expired:

  •       for _, stream := range i.conn.streams {
    
  •           stream.Reset()
    
  •       }
    
  •       i.conn.streamCond.L.Lock()
    
  •       streams := i.conn.streams
    
  •       i.conn.streams = make(map[spdy.StreamId]*Stream)
    
  •       i.conn.streamCond.Broadcast()
    
  •       i.conn.streamCond.L.Unlock()
    
  •       go func() {
    
  •           for _, stream := range streams {
    
  •               stream.resetStream()
    
  •           }
    
  •       }()
        i.conn.Close()
    

Suggesting i.conn.Close is inside the goroutine before the resets? I don't
like that hanging is a possibility on Close but I see it is only because
the resetChan cannot be read from while this call is done. I will make that
update, my main concern was i.conn.streams was updated before Close.


Reply to this email directly or view it on GitHub
https://github.com/docker/spdystream/pull/47/files#r25549366.

On expiration reset is called, causing a race between resetting objects and accessing the streams. Additionally a deadlock occurs writing frames which can be avoided by running the actual sending of the resets in a goroutine.

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
@dmcgowan dmcgowan force-pushed the fix-expiration-race branch from 65fc6cb to 1fdaf41 Compare February 28, 2015 00:54
@ncdc
Copy link
Contributor

ncdc commented Mar 2, 2015

LGTM

Also looks like we still need #46 for OS X. This one unfortunately doesn't fix that issue.

dmcgowan added a commit that referenced this pull request Mar 2, 2015
@dmcgowan dmcgowan merged commit e9bf991 into moby:master Mar 2, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants