{"action":"created","issue":{"url":"https://api.github.com/repos/fluffle/goirc/issues/58","labels_url":"https://api.github.com/repos/fluffle/goirc/issues/58/labels{/name}","comments_url":"https://api.github.com/repos/fluffle/goirc/issues/58/comments","events_url":"https://api.github.com/repos/fluffle/goirc/issues/58/events","html_url":"https://github.com/fluffle/goirc/pull/58","id":65562610,"number":58,"title":"client/connection: fix deadlock with double shutdown","user":{"login":"StalkR","id":1389952,"avatar_url":"https://avatars.githubusercontent.com/u/1389952?v=3","gravatar_id":"","url":"https://api.github.com/users/StalkR","html_url":"https://github.com/StalkR","followers_url":"https://api.github.com/users/StalkR/followers","following_url":"https://api.github.com/users/StalkR/following{/other_user}","gists_url":"https://api.github.com/users/StalkR/gists{/gist_id}","starred_url":"https://api.github.com/users/StalkR/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/StalkR/subscriptions","organizations_url":"https://api.github.com/users/StalkR/orgs","repos_url":"https://api.github.com/users/StalkR/repos","events_url":"https://api.github.com/users/StalkR/events{/privacy}","received_events_url":"https://api.github.com/users/StalkR/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":2,"created_at":"2015-03-31T22:41:14Z","updated_at":"2015-04-01T17:13:18Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/fluffle/goirc/pulls/58","html_url":"https://github.com/fluffle/goirc/pull/58","diff_url":"https://github.com/fluffle/goirc/pull/58.diff","patch_url":"https://github.com/fluffle/goirc/pull/58.patch"},"body":"second attempt :) I had forgotten the unlock in the return case."},"comment":{"url":"https://api.github.com/repos/fluffle/goirc/issues/comments/88560234","html_url":"https://github.com/fluffle/goirc/pull/58#issuecomment-88560234","issue_url":"https://api.github.com/repos/fluffle/goirc/issues/58","id":88560234,"user":{"login":"StalkR","id":1389952,"avatar_url":"https://avatars.githubusercontent.com/u/1389952?v=3","gravatar_id":"","url":"https://api.github.com/users/StalkR","html_url":"https://github.com/StalkR","followers_url":"https://api.github.com/users/StalkR/followers","following_url":"https://api.github.com/users/StalkR/following{/other_user}","gists_url":"https://api.github.com/users/StalkR/gists{/gist_id}","starred_url":"https://api.github.com/users/StalkR/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/StalkR/subscriptions","organizations_url":"https://api.github.com/users/StalkR/orgs","repos_url":"https://api.github.com/users/StalkR/repos","events_url":"https://api.github.com/users/StalkR/events{/privacy}","received_events_url":"https://api.github.com/users/StalkR/received_events","type":"User","site_admin":false},"created_at":"2015-04-01T17:13:17Z","updated_at":"2015-04-01T17:13:17Z","body":"My understanding is:\r\n- consider we are in a flood condition (easier to trigger), our first goroutine is on `conn.write()`, blocked on `time.After` because of flood: https://github.com/fluffle/goirc/blob/master/client/connection.go#L367\r\n- in a second goroutine a disconnect happens, caught by `conn.recv` which calls `conn.shutdown()` (https://github.com/fluffle/goirc/blob/master/client/connection.go#L314) we get the `conn.mu` lock, then wait on `conn.wg.Wait()` for the others to finish\r\n- `conn.write` gets out of its `time.After`, tries `conn.io.WriteString` which fails, then tries to call `irc.shutdown()` (https://github.com/fluffle/goirc/blob/master/client/connection.go#L371) which is blocked on its mutex (https://github.com/fluffle/goirc/blob/master/client/connection.go#L406) - therefore cannot return\r\n- that `conn.write` was called by `conn.send` (https://github.com/fluffle/goirc/blob/master/client/connection.go#L292) so it's still blocked on that, and cannot execute its `defer conn.wg.Done()` - where we are stuck"}}