aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/select.go
AgeCommit message (Collapse)Author
2020-11-25runtime: check channel's elemsize before calling race detectorDaniel S Fava
When c.elemsize==0 we call raceacquire() and racerelease() as opposed to calling racereleaseacquire() The reason for this change is that, when elemsize==0, we don't allocate a full buffer for the channel. Instead of individual buffer entries, the race detector uses the c.buf as the only buffer entry. This simplification prevents us following the memory model's happens-before rules implemented in racereleaseacquire(). So, instead of calling racereleaseacquire(), we accumulate happens-before information in the synchronization object associated with c.buf. The functionality in this change is implemented in a new function called racenotify() Fixes #42598 Change-Id: I75b92708633fdfde658dc52e06264e2171824e51 Reviewed-on: https://go-review.googlesource.com/c/go/+/271987 Reviewed-by: Dmitry Vyukov <dvyukov@google.com> Reviewed-by: Russ Cox <rsc@golang.org> Run-TryBot: Dmitry Vyukov <dvyukov@google.com> TryBot-Result: Go Bot <gobot@golang.org> Trust: Ian Lance Taylor <iant@golang.org>
2020-11-13runtime: swap the order of raceacquire() and racerelease()Daniel S Fava
In chansend() and chanrecv() of chan.go, the order of calls to raceacquire() and racerelease() was swapped, which meant that the code was not following the memory model "by the letter of the law." Similar for bufrecv and bufsend in select.go The memory model says: - A send happens before the corresponding receive completes, and - the kth receive on a channel with capacity C happens before the k+C send on that channel completes. The operative word here is "completes." For example, a sender obtains happens-before information on completion of the send-operation, which means, after the sender has deposited its message onto the channel. Similarly for receives. If the order of raceacquire() and racerelease() is incorrect, the race detector may fail to report some race conditions. The fix is minimal from the point of view of Go. The fix does, however, rely on a new function added to TSan: https://reviews.llvm.org/D76322 This commit only affects execution when race detection is enabled. Added two tests into `runtime/race/output_test.go`: - `chanmm` tests for the issue addressed by this patch - `mutex` is a test for inverted semaphores, which must not be broken by this (or any other) patch Fixes #37355 Change-Id: I5e886879ead2bd456a4b7dd1d17253641b767f63 Reviewed-on: https://go-review.googlesource.com/c/go/+/220419 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Trust: Dmitri Shuralyov <dmitshur@golang.org> Reviewed-by: Dmitry Vyukov <dvyukov@google.com>
2020-09-21runtime: disable stack shrinking in activeStackChans race windowMichael Anthony Knyszek
Currently activeStackChans is set before a goroutine blocks on a channel operation in an unlockf passed to gopark. The trouble is that the unlockf is called *after* the G's status is changed, and the G's status is what is used by a concurrent mark worker (calling suspendG) to determine that a G has successfully been suspended. In this window between the status change and unlockf, the mark worker could try to shrink the G's stack, and in particular observe that activeStackChans is false. This observation will cause the mark worker to *not* synchronize with concurrent channel operations when it should, and so updating pointers in the sudog for the blocked goroutine (which may point to the goroutine's stack) races with channel operations which may also manipulate the pointer (read it, dereference it, update it, etc.). Fix the problem by adding a new atomically-updated flag to the g struct called parkingOnChan, which is non-zero in the race window above. Then, in isShrinkStackSafe, check if parkingOnChan is zero. The race is resolved like so: * Blocking G sets parkingOnChan, then changes status in gopark. * Mark worker successfully suspends blocking G. * If the mark worker observes parkingOnChan is non-zero when checking isShrinkStackSafe, then it's not safe to shrink (we're in the race window). * If the mark worker observes parkingOnChan as zero, then because the mark worker observed the G status change, it can be sure that gopark's unlockf completed, and gp.activeStackChans will be correct. The risk of this change is low, since although it reduces the number of places that stack shrinking is allowed, the window here is incredibly small. Essentially, every place that it might crash now is replaced with no shrink. This change adds a test, but the race window is so small that it's hard to trigger without a well-placed sleep in park_m. Also, this change fixes stackGrowRecursive in proc_test.go to actually allocate a 128-byte stack frame. It turns out the compiler was destructuring the "pad" field and only allocating one uint64 on the stack. Fixes #40641. Change-Id: I7dfbe7d460f6972b8956116b137bc13bc24464e8 Reviewed-on: https://go-review.googlesource.com/c/go/+/247050 Run-TryBot: Michael Knyszek <mknyszek@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Michael Pratt <mpratt@google.com> Trust: Michael Knyszek <mknyszek@google.com>
2020-08-29cmd/compile,runtime: skip zero'ing order array for select statementsCuong Manh Le
The order array was zero initialized by the compiler, but ends up being overwritten by the runtime anyway. So let the runtime takes full responsibility for initializing, save us one instruction per select. Fixes #40399 Change-Id: Iec1eca27ad7180d4fcb3cc9ef97348206b7fe6b8 Reviewed-on: https://go-review.googlesource.com/c/go/+/251517 Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2020-08-18runtime: eliminate scase.kind fieldMatthew Dempsky
Currently, we include a "kind" field on scase to distinguish the three kinds of cases in a select statement: sends, receives, and defaults. This commit removes by kind field by instead arranging for the compiler to always place sends before receives, and to provide their counts separately. It also passes an explicit "block bool" parameter to avoid needing to include a default case in the array. It's safe to shuffle cases like this because the runtime will randomize the order they're polled in anyway. Fixes #40410. Change-Id: Iaeaed4cf7bddd576d78f2c863bd91a03a5c82df2 Reviewed-on: https://go-review.googlesource.com/c/go/+/245125 Reviewed-by: Keith Randall <khr@golang.org>
2020-08-18runtime: split PCs out of scaseMatthew Dempsky
Per-case PCs are only needed for race detector builds, so this allows skipping allocating stack space for them for non-race builds. It's possible to arrange the PCs and order arrays consecutively in memory so that we could just reuse the order0 pointer to identify both. However, there's more risk of that silently going wrong, so this commit passes them as separate arguments for now. We can revisit this in the future. Updates #40410. Change-Id: I8468bc25749e559891cb0cb007d1cc4a40fdd0f8 Reviewed-on: https://go-review.googlesource.com/c/go/+/245124 Reviewed-by: Keith Randall <khr@golang.org>
2020-08-18runtime: omit nil-channel cases from selectgo's ordersMatthew Dempsky
Currently, selectgo does an initial pass over the cases array to look for entries with nil channels, so they can be easily recognized and skipped later on. But this still involves actually visiting the cases. This commit changes selectgo to omit cases with nil channels when constructing pollorder, so that they'll be skipped over entirely later on. It also checks for caseDefault up front, which will facilitate changing it to use a "block bool" parameter instead. Updates #40410. Change-Id: Icaebcb8f08df03cc33b6d8087616fb5585f7fedd Reviewed-on: https://go-review.googlesource.com/c/go/+/245123 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
2020-08-18runtime: remove scase.releasetime fieldMatthew Dempsky
selectgo will report at most one block event, so there's no need to keep a releasetime for every select case. It suffices to simply track the releasetime of the case responsible for the wakeup. Updates #40410. Change-Id: I72679cd43dde80d7e6dbab21a78952a4372d1e79 Reviewed-on: https://go-review.googlesource.com/c/go/+/245122 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
2020-08-18runtime: add "success" field to sudogMatthew Dempsky
The current wakeup protocol for channel communications is that the second goroutine sets gp.param to the sudog when a value is successfully communicated over the channel, and to nil when the wakeup is due to closing the channel. Setting nil to indicate channel closure works okay for chansend and chanrecv, because they're only communicating with one channel, so they know it must be the channel that was closed. However, it means selectgo has to re-poll all of the channels to figure out which one was closed. This commit adds a "success" field to sudog, and changes the wakeup protocol to always set gp.param to sg, and to use sg.success to indicate successful communication vs channel closure. While here, this also reorganizes the chansend code slightly so that the sudog is still released to the pool if the send blocks and then is awoken because the channel closed. Updates #40410. Change-Id: I6cd9a20ebf9febe370a15af1b8afe24c5539efc6 Reviewed-on: https://go-review.googlesource.com/c/go/+/245019 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com> Reviewed-by: Keith Randall <khr@golang.org>
2020-02-24reflect: update Select to panic early on excessive input casesMilan Patel
The runtime implementation of select has an upper limit on the number of select cases that are supported in order to maintain low stack memory usage. Rather than support an arbitrary number of select cases, we've opted to panic early with a useful message pointing the user directly at the problem. Fixes #37350 Change-Id: Id129ba281ae120387e681ef96be8adcf89725840 Reviewed-on: https://go-review.googlesource.com/c/go/+/220583 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
2019-10-25runtime: make copystack/sudog synchronization more explicitAustin Clements
When we copy a stack of a goroutine blocked in a channel operation, we have to be very careful because other goroutines may be writing to that goroutine's stack. To handle this, stack copying acquires the locks for the channels a goroutine is waiting on. One complication is that stack growth may happen while a goroutine holds these locks, in which case stack copying must *not* acquire these locks because that would self-deadlock. Currently, stack growth never acquires these locks because stack growth only happens when a goroutine is running, which means it's either not blocking on a channel or it's holding the channel locks already. Stack shrinking always acquires these locks because shrinking happens asynchronously, so the goroutine is never running, so there are either no locks or they've been released by the goroutine. However, we're about to change when stack shrinking can happen, which is going to break the current rules. Rather than find a new way to derive whether to acquire these locks or not, this CL simply adds a flag to the g struct that indicates that stack copying should acquire channel locks. This flag is set while the goroutine is blocked on a channel op. For #10958, #24543. Change-Id: Ia2ac8831b1bfda98d39bb30285e144c4f7eaf9ab Reviewed-on: https://go-review.googlesource.com/c/go/+/172982 Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Michael Knyszek <mknyszek@google.com>
2019-09-01runtime: remove outdated comment in select sortkeyOu Changkun
This CL removes an outdated comment regarding converting a pointer to `uintptr`. The comment was introduced in Go 1.4 and runtime GC was under the consideration of major revisions. According to the current situation, Go runtime memory allocator has no fragmentation issue. Therefore compact GC won't be implemented in the near future. Change-Id: I5c336d81d810cf57b76797f05428421bb39a5b9f GitHub-Last-Rev: 2ab4be3885d3f48abbcb59af3f74bc95501ff23f GitHub-Pull-Request: golang/go#33685 Reviewed-on: https://go-review.googlesource.com/c/go/+/190520 Reviewed-by: Keith Randall <khr@golang.org> Run-TryBot: Keith Randall <khr@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
2019-08-28cmd/compile: fix wrong field type in scasetypeLE Manh Cuong
The only place set releasetime to negative is in runtime.selectgo (when blockprofilerate greater than zero), so we are safe in compiler code. But scasetype must keep in sync with runtime/select.go scase struct, so releasetime must be int64. Change-Id: I39ea944f5f2872452d3ffd57f7604d51e0d2590a Reviewed-on: https://go-review.googlesource.com/c/go/+/179799 Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2018-12-02all: use "reports whether" consistently instead of "returns whether"Tobias Klauser
Follow-up for CL 147037 and after Brad noticed the "returns whether" pattern during the review of CL 150621. Go documentation style for boolean funcs is to say: // Foo reports whether ... func Foo() bool (rather than "returns whether") Created with: $ perl -i -npe 's/returns whether/reports whether/' $(git grep -l "returns whether" | grep -v vendor) Change-Id: I15fe9ff99180ad97750cd05a10eceafdb12dc0b4 Reviewed-on: https://go-review.googlesource.com/c/150918 Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-09-18runtime: ignore races between close and len/capKeith Randall
They aren't really races, or at least they don't have any observable effect. The spec is silent on whether these are actually races or not. Fix this problem by not using the address of len (or of cap) as the location where channel operations are recorded to occur. Use a random other field of hchan for that. I'm not 100% sure we should in fact fix this. Opinions welcome. Fixes #27070 Change-Id: Ib4efd4b62e0d1ef32fa51e373035ef207a655084 Reviewed-on: https://go-review.googlesource.com/135698 Reviewed-by: Dmitry Vyukov <dvyukov@google.com>
2018-05-16runtime: use debugSelect flag to toggle debug codeZhou Peng
This block of code once was commented by the original author, but commenting code looks a little annoying. However, the debugSelect flag is just for the situation that debug code will be compiled when debuging, when release this code will be eliminated by the compiler. Change-Id: I7b94297e368b515116ef44a36058214ddddf9adb Reviewed-on: https://go-review.googlesource.com/113395 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
2018-05-03runtime: convert g.waitreason from string to uint8Josh Bleecher Snyder
Every time I poke at #14921, the g.waitreason string pointer writes show up. They're not particularly important performance-wise, but it'd be nice to clear the noise away. And it does open up a few extra bytes in the g struct for some future use. This is a re-roll of CL 99078, which was rolled back because of failures on s390x. Those failures were apparently due to an old version of gdb. Change-Id: Icc2c12f449b2934063fd61e272e06237625ed589 Reviewed-on: https://go-review.googlesource.com/111256 Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Michael Munday <mike.munday@ibm.com>
2018-05-01runtime: eliminate scase.receivedpMatthew Dempsky
Make selectgo return recvOK as a result parameter instead. Change-Id: Iffd436371d360bf666b76d4d7503e7c3037a9f1d Reviewed-on: https://go-review.googlesource.com/37935 Reviewed-by: Austin Clements <austin@google.com>
2018-05-01cmd/compile: open code select{send,recv,default}Matthew Dempsky
Registration now looks like: var cases [4]runtime.scases var order [8]uint16 cases[0].kind = caseSend cases[0].c = c1 cases[0].elem = &v1 if raceenabled || msanenabled { selectsetpc(&cases[0]) } cases[1].kind = caseRecv cases[1].c = c2 cases[1].elem = &v2 if raceenabled || msanenabled { selectsetpc(&cases[1]) } ... Change-Id: Ib9bcf426a4797fe4bfd8152ca9e6e08e39a70b48 Reviewed-on: https://go-review.googlesource.com/37934 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Austin Clements <austin@google.com>
2018-05-01runtime: eliminate runtime.hselectMatthew Dempsky
Now the registration phase looks like: var cases [4]runtime.scases var order [8]uint16 selectsend(&cases[0], c1, &v1) selectrecv(&cases[1], c2, &v2, nil) selectrecv(&cases[2], c3, &v3, &ok) selectdefault(&cases[3]) chosen := selectgo(&cases[0], &order[0], 4) Primarily, this is just preparation for having the compiler open-code selectsend, selectrecv, and selectdefault. As a minor benefit, order can now be layed out separately on the stack in the pointer-free segment, so it won't take up space in the function's stack pointer maps. Change-Id: I5552ba594201efd31fcb40084da20b42ea569a45 Reviewed-on: https://go-review.googlesource.com/37933 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Austin Clements <austin@google.com>
2018-03-13Revert "runtime: convert g.waitreason from string to uint8"Josh Bleecher Snyder
This reverts commit 4eea887fd477368653f6fcf8ad766030167936e5. Reason for revert: broke s390x build Change-Id: Id6c2b6a7319273c4d21f613d4cdd38b00d49f847 Reviewed-on: https://go-review.googlesource.com/100375 Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2018-03-12runtime: convert g.waitreason from string to uint8Josh Bleecher Snyder
Every time I poke at #14921, the g.waitreason string pointer writes show up. They're not particularly important performance-wise, but it'd be nice to clear the noise away. And it does open up a few extra bytes in the g struct for some future use. Change-Id: I7ffbd52fbc2a286931a2218038fda52ed6473cc9 Reviewed-on: https://go-review.googlesource.com/99078 Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Austin Clements <austin@google.com>
2017-09-22runtime: remove getcallerpc argumentAustin Clements
Now that getcallerpc is a compiler intrinsic on x86 and non-x86 platforms don't need the argument, we can drop it. Sadly, this doesn't let us remove any dummy arguments since all of those cases also use getcallersp, which still takes the argument pointer, but this is at least an improvement. Change-Id: I9c34a41cf2c18cba57f59938390bf9491efb22d2 Reviewed-on: https://go-review.googlesource.com/65474 Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: David Chase <drchase@google.com>
2017-08-29all: join some chained ifs to unindent codeDaniel Martí
Found with mvdan.cc/unindent. It skipped the cases where parentheses would need to be added, where comments would have to be moved elsewhere, or where actions and simple logic would mix. One of them was of the form "err != nil && err == io.EOF", so the first part was removed. Change-Id: Ie504c2b03a2c87d10ecbca1b9270069be1171b91 Reviewed-on: https://go-review.googlesource.com/57690 Run-TryBot: Daniel Martí <mvdan@mvdan.cc> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-08-15runtime: move selectdone into gDaniel Morsing
Writing to selectdone on the stack of another goroutine meant a pretty subtle dance between the select code and the stack copying code. Instead move the selectdone variable into the g struct. Change-Id: Id246aaf18077c625adef7ca2d62794afef1bdd1b Reviewed-on: https://go-review.googlesource.com/53390 Reviewed-by: Austin Clements <austin@google.com> Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
2017-03-07runtime: join selectgo and selectgoImplAustin Clements
Currently selectgo is just a wrapper around selectgoImpl. This keeps the hard-coded frame skip counts for tracing the same between the channel implementation and the select implementation. However, this is fragile and confusing, so pass a skip parameter to send and recv, join selectgo and selectgoImpl into one function, and use decrease all of the skips in selectgo by one. Change-Id: I11b8cbb7d805b55f5dc6ab4875ac7dde79412ff2 Reviewed-on: https://go-review.googlesource.com/37860 Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2017-03-07cmd/compile, runtime: simplify multiway select implementationMatthew Dempsky
This commit reworks multiway select statements to use normal control flow primitives instead of the previous setjmp/longjmp-like behavior. This simplifies liveness analysis and should prevent issues around "returns twice" function calls within SSA passes. test/live.go is updated because liveness analysis's CFG is more representative of actual control flow. The case bodies are the only real successors of the selectgo call, but previously the selectsend, selectrecv, etc. calls were included in the successors list too. Updates #19331. Change-Id: I7f879b103a4b85e62fc36a270d812f54c0aa3e83 Reviewed-on: https://go-review.googlesource.com/37661 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
2017-02-14runtime: speed up fastrand() % nJosh Bleecher Snyder
This occurs a fair amount in the runtime for non-power-of-two n. Use an alternative, faster formulation. name old time/op new time/op delta Fastrandn/2-8 4.45ns ± 2% 2.09ns ± 3% -53.12% (p=0.000 n=14+14) Fastrandn/3-8 4.78ns ±11% 2.06ns ± 2% -56.94% (p=0.000 n=15+15) Fastrandn/4-8 4.76ns ± 9% 1.99ns ± 3% -58.28% (p=0.000 n=15+13) Fastrandn/5-8 4.96ns ±13% 2.03ns ± 6% -59.14% (p=0.000 n=15+15) name old time/op new time/op delta SelectUncontended-8 33.7ns ± 2% 33.9ns ± 2% +0.70% (p=0.000 n=49+50) SelectSyncContended-8 1.68µs ± 4% 1.65µs ± 4% -1.54% (p=0.000 n=50+45) SelectAsyncContended-8 282ns ± 1% 277ns ± 1% -1.50% (p=0.000 n=48+43) SelectNonblock-8 5.31ns ± 1% 5.32ns ± 1% ~ (p=0.275 n=45+44) SelectProdCons-8 585ns ± 3% 577ns ± 2% -1.35% (p=0.000 n=50+50) GoroutineSelect-8 1.59ms ± 2% 1.59ms ± 1% ~ (p=0.084 n=49+48) Updates #16213 Change-Id: Ib555a4d7da2042a25c3976f76a436b536487d5b7 Reviewed-on: https://go-review.googlesource.com/36932 Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Reviewed-by: Keith Randall <khr@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
2017-02-13runtime: make fastrand to generate 32bit valuesSokolov Yura
Extend period of fastrand from (1<<31)-1 to (1<<32)-1 by choosing other polynom and reacting on high bit before shift. Polynomial is taken at https://users.ece.cmu.edu/~koopman/lfsr/index.html from 32.dat.gz . It is referred as F7711115 cause this list of polynomials is for LFSR with shift to right (and fastrand uses shift to left). (old polynomial is referred in 31.dat.gz as 7BB88888). There were couple of places with conversation of fastrand to int, which leads to negative values on 32bit platforms. They are fixed. Change-Id: Ibee518a3f9103e0aea220ada494b3aec77babb72 Reviewed-on: https://go-review.googlesource.com/36875 Run-TryBot: Minux Ma <minux@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Minux Ma <minux@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
2017-01-06runtime: fix corruption crash/race between select and stack growthRuss Cox
To implement the blocking of a select, a goroutine builds a list of offers to communicate (pseudo-g's, aka sudog), one for each case, queues them on the corresponding channels, and waits for another goroutine to complete one of those cases and wake it up. Obviously it is not OK for two other goroutines to complete multiple cases and both wake the goroutine blocked in select. To make sure that only one branch of the select is chosen, all the sudogs contain a pointer to a shared (single) 'done uint32', which is atomically cas'ed by any interested goroutines. The goroutine that wins the cas race gets to wake up the select. A complication is that 'done uint32' is stored on the stack of the goroutine running the select, and that stack can move during the select due to stack growth or stack shrinking. The relevant ordering to block and unblock in select is: 1. Lock all channels. 2. Create list of sudogs and queue sudogs on all channels. 3. Switch to system stack, mark goroutine as asleep, unlock all channels. 4. Sleep until woken. 5. Wake up on goroutine stack. 6. Lock all channels. 7. Dequeue sudogs from all channels. 8. Free list of sudogs. 9. Unlock all channels. There are two kinds of stack moves: stack growth and stack shrinking. Stack growth happens while the original goroutine is running. Stack shrinking happens asynchronously, during garbage collection. While a channel listing a sudog is locked by select in this process, no other goroutine can attempt to complete communication on that channel, because that other goroutine doesn't hold the lock and can't find the sudog. If the stack moves while all the channel locks are held or when the sudogs are not yet or no longer queued in the channels, no problem, because no goroutine can get to the sudogs and therefore to selectdone. We only need to worry about the stack (and 'done uint32') moving with the sudogs queued in unlocked channels. Stack shrinking can happen any time the goroutine is stopped. That code already acquires all the channel locks before doing the stack move, so it avoids this problem. Stack growth can happen essentially any time the original goroutine is running on its own stack (not the system stack). In the first half of the select, all the channels are locked before any sudogs are queued, and the channels are not unlocked until the goroutine has stopped executing on its own stack and is asleep, so that part is OK. In the second half of the select, the goroutine wakes up on its own goroutine stack and immediately locks all channels. But the actual call to lock might grow the stack, before acquiring any locks. In that case, the stack is moving with the sudogs queued in unlocked channels. Not good. One goroutine has already won a cas on the old stack (that goroutine woke up the selecting goroutine, moving it out of step 4), and the fact that done = 1 now should prevent any other goroutines from completing any other select cases. During the stack move, however, sudog.selectdone is moved from pointing to the old done variable on the old stack to a new memory location on the new stack. Another goroutine might observe the moved pointer before the new memory location has been initialized. If the new memory word happens to be zero, that goroutine might win a cas on the new location, thinking it can now complete the select (again). It will then complete a second communication (reading from or writing to the goroutine stack incorrectly) and then attempt to wake up the selecting goroutine, which is already awake. The scribbling over the goroutine stack unexpectedly is already bad, but likely to go unnoticed, at least immediately. As for the second wakeup, there are a variety of ways it might play out. * The goroutine might not be asleep. That will produce a runtime crash (throw) like in #17007: runtime: gp: gp=0xc0422dcb60, goid=2299, gp->atomicstatus=8 runtime: g: g=0xa5cfe0, goid=0, g->atomicstatus=0 fatal error: bad g->status in ready Here, atomicstatus=8 is copystack; the second, incorrect wakeup is observing that the selecting goroutine is in state "Gcopystack" instead of "Gwaiting". * The goroutine might be sleeping in a send on a nil chan. If it wakes up, it will crash with 'fatal error: unreachable'. * The goroutine might be sleeping in a send on a non-nil chan. If it wakes up, it will crash with 'fatal error: chansend: spurious wakeup'. * The goroutine might be sleeping in a receive on a nil chan. If it wakes up, it will crash with 'fatal error: unreachable'. * The goroutine might be sleeping in a receive on a non-nil chan. If it wakes up, it will silently (incorrectly!) continue as if it received a zero value from a closed channel, leaving a sudog queued on the channel pointing at that zero vaue on the goroutine's stack; that space will be reused as the goroutine executes, and when some other goroutine finally completes the receive, it will do a stray write into the goroutine's stack memory, which may cause problems. Then it will attempt the real wakeup of the goroutine, leading recursively to any of the cases in this list. * The goroutine might have been running a select in a finalizer (I hope not!) and might now be sleeping waiting for more things to finalize. If it wakes up, as long as it goes back to sleep quickly (before the real GC code tries to wake it), the spurious wakeup does no harm (but the stack was still scribbled on). * The goroutine might be sleeping in gcParkAssist. If it wakes up, that will let the goroutine continue executing a bit earlier than we would have liked. Eventually the GC will attempt the real wakeup of the goroutine, leading recursively to any of the cases in this list. * The goroutine cannot be sleeping in bgsweep, because the background sweepers never use select. * The goroutine might be sleeping in netpollblock. If it wakes up, it will crash with 'fatal error: netpollblock: corrupted state'. * The goroutine might be sleeping in main as another thread crashes. If it wakes up, it will exit(0) instead of letting the other thread crash with a non-zero exit status. * The goroutine cannot be sleeping in forcegchelper, because forcegchelper never uses select. * The goroutine might be sleeping in an empty select - select {}. If it wakes up, it will return to the next line in the program! * The goroutine might be sleeping in a non-empty select (again). In this case, it will wake up spuriously, with gp.param == nil (no reason for wakeup), but that was fortuitously overloaded for handling wakeup due to a closing channel and the way it is handled is to rerun the select, which (accidentally) handles the spurious wakeup correctly: if cas == nil { // This can happen if we were woken up by a close(). // TODO: figure that out explicitly so we don't need this loop. goto loop } Before looping, it will dequeue all the sudogs on all the channels involved, so that no other goroutine will attempt to wake it. Since the goroutine was blocked in select before, being blocked in select again when the spurious wakeup arrives may be quite likely. In this case, the spurious wakeup does no harm (but the stack was still scribbled on). * The goroutine might be sleeping in semacquire (mutex slow path). If it wakes up, that is taken as a signal to try for the semaphore again, not a signal that the semaphore is now held, but the next iteration around the loop will queue the sudog a second time, causing a cycle in the wakeup list for the given address. If that sudog is the only one in the list, when it is eventually dequeued, it will (due to the precise way the code is written) leave the sudog on the queue inactive with the sudog broken. But the sudog will also be in the free list, and that will eventually cause confusion. * The goroutine might be sleeping in notifyListWait, for sync.Cond. If it wakes up, (*Cond).Wait returns. The docs say "Unlike in other systems, Wait cannot return unless awoken by Broadcast or Signal," so the spurious wakeup is incorrect behavior, but most callers do not depend on that fact. Eventually the condition will happen, attempting the real wakeup of the goroutine and leading recursively to any of the cases in this list. * The goroutine might be sleeping in timeSleep aka time.Sleep. If it wakes up, it will continue running, leaving a timer ticking. When that time bomb goes off, it will try to ready the goroutine again, leading to any one of the cases in this list. * The goroutine cannot be sleeping in timerproc, because timerproc never uses select. * The goroutine might be sleeping in ReadTrace. If it wakes up, it will print 'runtime: spurious wakeup of trace reader' and return nil. All future calls to ReadTrace will print 'runtime: ReadTrace called from multiple goroutines simultaneously'. Eventually, when trace data is available, a true wakeup will be attempted, leading to any one of the cases in this list. None of these fatal errors appear in any of the trybot or dashboard logs. The 'bad g->status in ready' that happens if the goroutine is running (the most likely scenario anyway) has happened once on the dashboard and eight times in trybot logs. Of the eight, five were atomicstatus=8 during net/http tests, so almost certainly this bug. The other three were atomicstatus=2, all near code in select, but in a draft CL by Dmitry that was rewriting select and may or may not have had its own bugs. This bug has existed since Go 1.4. Until then the select code was implemented in C, 'done uint32' was a C stack variable 'uint32 done', and C stacks never moved. I believe it has become more common recently because of Brad's work to run more and more tests in net/http in parallel, which lengthens race windows. The fix is to run step 6 on the system stack, avoiding possibility of stack growth. Fixes #17007 and possibly other mysterious failures. Change-Id: I9d6575a51ac96ae9d67ec24da670426a4a45a317 Reviewed-on: https://go-review.googlesource.com/34835 Run-TryBot: Russ Cox <rsc@golang.org> Reviewed-by: Austin Clements <austin@google.com>
2016-10-28runtime: use typedmemclr for typed memoryAustin Clements
The hybrid barrier requires distinguishing typed and untyped memory even when zeroing because the *current* contents of the memory matters even when overwriting. This commit introduces runtime.typedmemclr and runtime.memclrHasPointers as a typed memory clearing functions parallel to runtime.typedmemmove. Currently these simply call memclr, but with the hybrid barrier we'll need to shade any pointers we're overwriting. These will provide us with the necessary hooks to do so. Updates #17503. Change-Id: I74478619f8907825898092aaa204d6e4690f27e6 Reviewed-on: https://go-review.googlesource.com/31366 Reviewed-by: Keith Randall <khr@golang.org> Reviewed-by: Rick Hudson <rlh@golang.org>
2016-08-30runtime: rename fastrand1 to fastrandJosh Bleecher Snyder
Change-Id: I37706ff0a3486827c5b072c95ad890ea87ede847 Reviewed-on: https://go-review.googlesource.com/28210 Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2016-04-20runtime: simplify mallocgc flag argumentKeith Randall
mallocgc can calculate noscan itself. The only remaining flag argument is needzero, so we just make that a boolean arg. Fixes #15379 Change-Id: I839a70790b2a0c9dbcee2600052bfbd6c8148e20 Reviewed-on: https://go-review.googlesource.com/22290 Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com> Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-04-10runtime: make execution error panic values implement the Error interfaceEmmanuel Odeke
Make execution panics implement Error as mandated by https://golang.org/ref/spec#Run_time_panics, instead of panics with strings. Fixes #14965 Change-Id: I7827f898b9b9c08af541db922cc24fa0800ff18a Reviewed-on: https://go-review.googlesource.com/21214 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-03-16runtime: never pass stack pointers to goparkAustin Clements
gopark calls the unlock function after setting the G to _Gwaiting. This means it's generally unsafe to access the G's stack from the unlock function because the G may start running on another P. Once we start shrinking stacks concurrently, a stack shrink could also move the stack the moment after it enters _Gwaiting and before the unlock function is called. Document this restriction and fix the two places where we currently violate it. This is unlikely to be a problem in practice for these two places right now, but they're already skating on thin ice. For example, the following sequence could in principle cause corruption, deadlock, or a panic in the select code: On M1/P1: 1. G1 selects on channels A and B. 2. selectgoImpl calls gopark. 3. gopark puts G1 in _Gwaiting. 4. gopark calls selparkcommit. 5. selparkcommit releases the lock on channel A. On M2/P2: 6. G2 sends to channel A. 7. The send puts G1 in _Grunnable and puts it on P2's run queue. 8. The scheduler runs, selects G1, puts it in _Grunning, and resumes G1. 9. On G1, the sellock immediately following the gopark gets called. 10. sellock grows and moves the stack. On M1/P1: 11. selparkcommit continues to scan the lock order for the next channel to unlock, but it's now reading from a freed (and possibly reused) stack. This shouldn't happen in practice because step 10 isn't the first call to sellock, so the stack should already be big enough. However, once we start shrinking stacks concurrently, this reasoning won't work any more. For #12967. Change-Id: I3660c5be37e5be9f87433cb8141bdfdf37fadc4c Reviewed-on: https://go-review.googlesource.com/20038 Reviewed-by: Rick Hudson <rlh@golang.org> Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-03-16runtime: put g.waiting list in lock orderAustin Clements
Currently the g.waiting list created by a select is in poll order. However, nothing depends on this, and we're going to need access to the channel lock order in other places shortly, so modify select to put the waiting list in channel lock order. For #12967. Change-Id: If0d38816216ecbb37a36624d9b25dd96e0a775ec Reviewed-on: https://go-review.googlesource.com/20037 Reviewed-by: Rick Hudson <rlh@golang.org> Reviewed-by: Keith Randall <khr@golang.org> Run-TryBot: Austin Clements <austin@google.com>
2016-03-16runtime: use indexes for select lock orderAustin Clements
Currently the select lock order is a []*hchan. We're going to need to refer to things other than the channel itself in lock order shortly, so switch this to a []uint16 of indexes into the select cases. This parallels the existing representation for the poll order. Change-Id: I89262223fe20b4ddf5321592655ba9eac489cda1 Reviewed-on: https://go-review.googlesource.com/20036 Reviewed-by: Rick Hudson <rlh@golang.org> Reviewed-by: Keith Randall <khr@golang.org> Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-03-16runtime: record channel in sudogAustin Clements
Given a G, there's currently no way to find the channel it's blocking on. We'll need this information to fix a (probably theoretical) bug in select and to implement concurrent stack shrinking, so record the channel in the sudog. For #12967. Change-Id: If8fb63a140f1d07175818824d08c0ebeec2bdf66 Reviewed-on: https://go-review.googlesource.com/20035 Reviewed-by: Rick Hudson <rlh@golang.org> Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-03-14runtime: improve comment on selectgoAustin Clements
In particular, document that *sel is on the stack no matter what. Change-Id: I1c264215e026c27721b13eedae73ec845066cdec Reviewed-on: https://go-review.googlesource.com/20032 Reviewed-by: Rick Hudson <rlh@golang.org>
2016-03-02all: single space after period.Brad Fitzpatrick
The tree's pretty inconsistent about single space vs double space after a period in documentation. Make it consistently a single space, per earlier decisions. This means contributors won't be confused by misleading precedence. This CL doesn't use go/doc to parse. It only addresses // comments. It was generated with: $ perl -i -npe 's,^(\s*// .+[a-z]\.) +([A-Z]),$1 $2,' $(git grep -l -E '^\s*//(.+\.) +([A-Z])') $ go test go/doc -update Change-Id: Iccdb99c37c797ef1f804a94b22ba5ee4b500c4f7 Reviewed-on: https://go-review.googlesource.com/20022 Reviewed-by: Rob Pike <r@golang.org> Reviewed-by: Dave Day <djd@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-02-25runtime: document non-obvious requirement on sudog.elemAustin Clements
The channel code must not allow stack splits between when it assigns a potential stack pointer to sudog.elem (or sudog.selectdone) and when it makes the sudog visible to copystack by putting it on the g.waiting list. We do get this right everywhere, but add a comment about this subtlety for future eyes. Change-Id: I941da150437167acff37b0e56983c793f40fcf79 Reviewed-on: https://go-review.googlesource.com/19632 Reviewed-by: Rick Hudson <rlh@golang.org> Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-02-23Revert "cmd/compile: move hiter, hmap, and scase definitions into builtin.go"Matthew Dempsky
This reverts commit f28bbb776a050cc3edca2bbe1241d81217a7a251. Change-Id: I82fb81dcff3ddcaefef72949f1ef3a41bcd22301 Reviewed-on: https://go-review.googlesource.com/19849 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
2016-02-22cmd/compile: move hiter, hmap, and scase definitions into builtin.goMatthew Dempsky
Also eliminates per-maptype hiter and hmap types, since they're not really needed anyway. Update packages reflect and runtime accordingly. Reduces golang.org/x/tools/cmd/godoc's text segment by ~170kB: text data bss dec hex filename 13085702 140640 151520 13377862 cc2146 godoc.before 12915382 140640 151520 13207542 c987f6 godoc.after Updates #6853. Change-Id: I948b2bc1f22d477c1756204996b4e3e1fb568d81 Reviewed-on: https://go-review.googlesource.com/16610 Reviewed-by: Keith Randall <khr@golang.org>
2015-11-12runtime: break out system-specific constants into package sysMichael Matloob
runtime/internal/sys will hold system-, architecture- and config- specific constants. Updates #11647 Change-Id: I6db29c312556087a42e8d2bdd9af40d157c56b54 Reviewed-on: https://go-review.googlesource.com/16817 Reviewed-by: Russ Cox <rsc@golang.org>
2015-11-08runtime: simplify chan ops, take 2Keith Randall
This change is the same as CL #9345 which was reverted, except for a small bug fix. The only change is to the body of sendDirect and its callsite. Also added a test. The problem was during a channel send operation. The target of the send was a sleeping goroutine waiting to receive. We basically do: 1) Read the destination pointer out of the sudog structure 2) Copy the value we're sending to that destination pointer Unfortunately, the previous change had a goroutine suspend point between 1 & 2 (the call to sendDirect). At that point the destination goroutine's stack could be copied (shrunk). The pointer we read in step 1 is no longer valid for step 2. Fixed by not allowing any suspension points between 1 & 2. I suspect the old code worked correctly basically by accident. Fixes #13169 The original 9345: This change removes the retry mechanism we use for buffered channels. Instead, any sender waking up a receiver or vice versa completes the full protocol with its counterpart. This means the counterpart does not need to relock the channel when it wakes up. (Currently buffered channels need to relock on wakeup.) For sends on a channel with waiting receivers, this change replaces two copies (sender->queue, queue->receiver) with one (sender->receiver). For receives on channels with a waiting sender, two copies are still required. This change unifies to a large degree the algorithm for buffered and unbuffered channels, simplifying the overall implementation. Fixes #11506 Change-Id: I57dfa3fc219cffa4d48301ee15fe5479299efa09 Reviewed-on: https://go-review.googlesource.com/16740 Reviewed-by: Ian Lance Taylor <iant@golang.org>
2015-11-06Revert "runtime: simplify buffered channels."Keith Randall
Revert for now until #13169 is understood. This reverts commit 8e496f1d6923172291658f0a785bdb47cc152325. Change-Id: Ib3eb2588824ef47a2b6eb9e377a24e5c817fcc81 Reviewed-on: https://go-review.googlesource.com/16716 Reviewed-by: Keith Randall <khr@golang.org>
2015-11-05runtime: simplify buffered channels.Keith Randall
This change removes the retry mechanism we use for buffered channels. Instead, any sender waking up a receiver or vice versa completes the full protocol with its counterpart. This means the counterpart does not need to relock the channel when it wakes up. (Currently buffered channels need to relock on wakeup.) For sends on a channel with waiting receivers, this change replaces two copies (sender->queue, queue->receiver) with one (sender->receiver). For receives on channels with a waiting sender, two copies are still required. This change unifies to a large degree the algorithm for buffered and unbuffered channels, simplifying the overall implementation. Fixes #11506 benchmark old ns/op new ns/op delta BenchmarkChanProdCons10 125 110 -12.00% BenchmarkChanProdCons0 303 284 -6.27% BenchmarkChanProdCons100 75.5 71.3 -5.56% BenchmarkChanContended 6452 6125 -5.07% BenchmarkChanNonblocking 11.5 11.0 -4.35% BenchmarkChanCreation 149 143 -4.03% BenchmarkChanSem 63.6 61.6 -3.14% BenchmarkChanUncontended 6390 6212 -2.79% BenchmarkChanSync 282 276 -2.13% BenchmarkChanProdConsWork10 516 506 -1.94% BenchmarkChanProdConsWork0 696 685 -1.58% BenchmarkChanProdConsWork100 470 469 -0.21% BenchmarkChanPopular 660427 660012 -0.06% Change-Id: I164113a56432fbc7cace0786e49c5a6e6a708ea4 Reviewed-on: https://go-review.googlesource.com/9345 Run-TryBot: Keith Randall <khr@golang.org> Reviewed-by: Austin Clements <austin@google.com> Reviewed-by: Dmitry Vyukov <dvyukov@google.com>
2015-10-21runtime, syscall: add calls to msan functionsIan Lance Taylor
Add explicit memory sanitizer instrumentation to the runtime and syscall packages. The compiler does not instrument the runtime package. It does instrument the syscall package, but we need to add a couple of cases that it can't see. Change-Id: I2d66073f713fe67e33a6720460d2bb8f72f31394 Reviewed-on: https://go-review.googlesource.com/16164 Reviewed-by: David Crawshaw <crawshaw@golang.org>
2015-07-13runtime: add memory barrier for sync send in selectRuss Cox
Missed select case when adding the barrier last time. All the more reason to refactor this code in Go 1.6. Fixes #11643. Change-Id: Ib0d19d6e0939296c0a3e06dda5e9b76f813bbc7e Reviewed-on: https://go-review.googlesource.com/12086 Reviewed-by: Austin Clements <austin@google.com>
2015-04-27runtime: remove a modulus calculation from pollorderJosh Bleecher Snyder
This is a follow-up to CL 9269, as suggested by dvyukov. There is probably even more that can be done to speed up this shuffle. It will matter more once CL 7570 (fine-grained locking in select) is in and can be revisited then, with benchmarks. Change-Id: Ic13a27d11cedd1e1f007951214b3bb56b1644f02 Reviewed-on: https://go-review.googlesource.com/9393 Reviewed-by: Dmitry Vyukov <dvyukov@google.com>