| // Copyright 2017 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package runtime |
| |
| import "unsafe" |
| |
| var labelSync uintptr |
| |
| //go:linkname runtime_setProfLabel runtime/pprof.runtime_setProfLabel |
| func runtime_setProfLabel(labels unsafe.Pointer) { |
| // Introduce race edge for read-back via profile. |
| // This would more properly use &getg().labels as the sync address, |
| // but we do the read in a signal handler and can't call the race runtime then. |
| // |
| // This uses racereleasemerge rather than just racerelease so |
| // the acquire in profBuf.read synchronizes with *all* prior |
| // setProfLabel operations, not just the most recent one. This |
| // is important because profBuf.read will observe different |
| // labels set by different setProfLabel operations on |
| // different goroutines, so it needs to synchronize with all |
| // of them (this wouldn't be an issue if we could synchronize |
| // on &getg().labels since we would synchronize with each |
| // most-recent labels write separately.) |
| // |
| // racereleasemerge is like a full read-modify-write on |
| // labelSync, rather than just a store-release, so it carries |
| // a dependency on the previous racereleasemerge, which |
| // ultimately carries forward to the acquire in profBuf.read. |
| if raceenabled { |
| racereleasemerge(unsafe.Pointer(&labelSync)) |
| } |
| getg().labels = labels |
| } |
| |
| //go:linkname runtime_getProfLabel runtime/pprof.runtime_getProfLabel |
| func runtime_getProfLabel() unsafe.Pointer { |
| return getg().labels |
| } |