{"action":"created","issue":{"url":"https://api.github.com/repos/golang/go/issues/13546","labels_url":"https://api.github.com/repos/golang/go/issues/13546/labels{/name}","comments_url":"https://api.github.com/repos/golang/go/issues/13546/comments","events_url":"https://api.github.com/repos/golang/go/issues/13546/events","html_url":"https://github.com/golang/go/issues/13546","id":121229258,"number":13546,"title":"runtime: goroutine starvation due to Gosched","user":{"login":"dvyukov","id":1095328,"avatar_url":"https://avatars.githubusercontent.com/u/1095328?v=3","gravatar_id":"","url":"https://api.github.com/users/dvyukov","html_url":"https://github.com/dvyukov","followers_url":"https://api.github.com/users/dvyukov/followers","following_url":"https://api.github.com/users/dvyukov/following{/other_user}","gists_url":"https://api.github.com/users/dvyukov/gists{/gist_id}","starred_url":"https://api.github.com/users/dvyukov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dvyukov/subscriptions","organizations_url":"https://api.github.com/users/dvyukov/orgs","repos_url":"https://api.github.com/users/dvyukov/repos","events_url":"https://api.github.com/users/dvyukov/events{/privacy}","received_events_url":"https://api.github.com/users/dvyukov/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":4,"created_at":"2015-12-09T12:45:32Z","updated_at":"2015-12-10T21:26:10Z","closed_at":"2015-12-10T21:26:10Z","body":"The following program hangs:\r\n\r\n```go\r\npackage main\r\n\r\nimport (\r\n\t\"runtime\"\r\n\t\"sync/atomic\"\r\n)\r\n\r\nfunc main() {\r\n\tconst P = 4\r\n\truntime.GOMAXPROCS(P)\r\n\tx := uint32(0)\r\n\tfor p := 0; p < P; p++ {\r\n\t\tgo func() {\r\n\t\t\tatomic.AddUint32(&x, 1)\r\n\t\t\tfor atomic.LoadUint32(&x) != P {\r\n\t\t\t}\r\n\t\t}()\r\n\t}\r\n\tfor atomic.LoadUint32(&x) != P {\r\n\t\truntime.Gosched()\r\n\t}\r\n}\r\n```\r\n\r\n```\r\nSIGABRT: abort\r\nPC=0x44dae0 m=0\r\n\r\ngoroutine 21 [running]:\r\nsync/atomic.LoadUint32(0xc8200b6000)\r\n\tsrc/sync/atomic/asm_amd64.s:92 fp=0xc820060798 sp=0xc820060790\r\nmain.main.func1(0xc8200b6000)\r\n\t/tmp/gosched.go:15 +0x37 fp=0xc8200607b8 sp=0xc820060798\r\nruntime.goexit()\r\n\tsrc/runtime/asm_amd64.s:1998 +0x1 fp=0xc8200607c0 sp=0xc8200607b8\r\ncreated by main.main\r\n\t/tmp/gosched.go:17 +0x78\r\n\r\ngoroutine 1 [runnable]:\r\nruntime.Gosched()\r\n\tsrc/runtime/proc.go:235 +0x14\r\nmain.main()\r\n\t/tmp/gosched.go:20 +0xa7\r\n\r\ngoroutine 18 [runnable]:\r\nmain.main.func1(0xc8200b6000)\r\n\t/tmp/gosched.go:13\r\ncreated by main.main\r\n\t/tmp/gosched.go:17 +0x78\r\n\r\ngoroutine 19 [running]:\r\n\tgoroutine running on other thread; stack unavailable\r\ncreated by main.main\r\n\t/tmp/gosched.go:17 +0x78\r\n\r\ngoroutine 20 [running]:\r\n\tgoroutine running on other thread; stack unavailable\r\ncreated by main.main\r\n\t/tmp/gosched.go:17 +0x78\r\n```\r\n\r\nOne goroutine constantly calls ```runtime.Gosched``` but another runnable goroutine is starved.\r\nThe root cause is: Gosched puts the current goroutine onto global run queue, then the thread check local run queue (empty), then it checks global run queue and picks up the old goroutine again. But at the same time there is another runnable goroutine in remote per-P queue.\r\n\r\nThis is probably not super critical, as it can happen only if there are goroutines in tight non-preemptable loops. But still we could check local queues ahead of global queue once in a while in findrunnable. We do the opposite hack in schedule -- check global queue ahead of local queue once in a while. On the other hand this will destroy locality, which is bad for performance...\r\n"},"comment":{"url":"https://api.github.com/repos/golang/go/issues/comments/163754125","html_url":"https://github.com/golang/go/issues/13546#issuecomment-163754125","issue_url":"https://api.github.com/repos/golang/go/issues/13546","id":163754125,"user":{"login":"aclements","id":2688315,"avatar_url":"https://avatars.githubusercontent.com/u/2688315?v=3","gravatar_id":"","url":"https://api.github.com/users/aclements","html_url":"https://github.com/aclements","followers_url":"https://api.github.com/users/aclements/followers","following_url":"https://api.github.com/users/aclements/following{/other_user}","gists_url":"https://api.github.com/users/aclements/gists{/gist_id}","starred_url":"https://api.github.com/users/aclements/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aclements/subscriptions","organizations_url":"https://api.github.com/users/aclements/orgs","repos_url":"https://api.github.com/users/aclements/repos","events_url":"https://api.github.com/users/aclements/events{/privacy}","received_events_url":"https://api.github.com/users/aclements/received_events","type":"User","site_admin":false},"created_at":"2015-12-10T21:26:10Z","updated_at":"2015-12-10T21:26:10Z","body":"Closing as a dup of #10958, though we can of course reopen if we want to take a more specific approach to this problem."}}