diff options
author | Michael Stapelberg <stapelberg@debian.org> | 2013-05-14 18:39:35 +0200 |
---|---|---|
committer | Michael Stapelberg <michael@stapelberg.de> | 2013-05-14 18:39:35 +0200 |
commit | efcc50dfdc94c82ee0292bf71992ecb7c0123061 (patch) | |
tree | 17dca99d1dc7fc4e9fe49c2cf6a99d337d4c039f /src/pkg/runtime/chan.c | |
parent | 04b08da9af0c450d645ab7389d1467308cfc2db8 (diff) | |
download | golang-efcc50dfdc94c82ee0292bf71992ecb7c0123061.tar.gz |
Imported Upstream version 1.1upstream/1.1
Diffstat (limited to 'src/pkg/runtime/chan.c')
-rw-r--r-- | src/pkg/runtime/chan.c | 31 |
1 files changed, 21 insertions, 10 deletions
diff --git a/src/pkg/runtime/chan.c b/src/pkg/runtime/chan.c index 32995c6dd..fba36a4c3 100644 --- a/src/pkg/runtime/chan.c +++ b/src/pkg/runtime/chan.c @@ -809,16 +809,27 @@ sellock(Select *sel) static void selunlock(Select *sel) { - uint32 i; - Hchan *c, *c0; + int32 i, n, r; + Hchan *c; - c = nil; - for(i=sel->ncase; i-->0;) { - c0 = sel->lockorder[i]; - if(c0 && c0 != c) { - c = c0; - runtime·unlock(c); - } + // We must be very careful here to not touch sel after we have unlocked + // the last lock, because sel can be freed right after the last unlock. + // Consider the following situation. + // First M calls runtime·park() in runtime·selectgo() passing the sel. + // Once runtime·park() has unlocked the last lock, another M makes + // the G that calls select runnable again and schedules it for execution. + // When the G runs on another M, it locks all the locks and frees sel. + // Now if the first M touches sel, it will access freed memory. + n = (int32)sel->ncase; + r = 0; + // skip the default case + if(n>0 && sel->lockorder[0] == nil) + r = 1; + for(i = n-1; i >= r; i--) { + c = sel->lockorder[i]; + if(i>0 && sel->lockorder[i-1] == c) + continue; // will unlock it on the next iteration + runtime·unlock(c); } } @@ -1011,7 +1022,7 @@ loop: c = cas->chan; if(c->dataqsiz > 0) - runtime·throw("selectgo: shouldnt happen"); + runtime·throw("selectgo: shouldn't happen"); if(debug) runtime·printf("wait-return: sel=%p c=%p cas=%p kind=%d\n", |